diff --git a/inbm/Changelog.md b/inbm/Changelog.md index 31387c2a4..a60a48a36 100644 --- a/inbm/Changelog.md +++ b/inbm/Changelog.md @@ -5,6 +5,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/). ## NEXT - ?.?.? - ? +###Changed + - RTC 536910 - [source] Remove ubuntuAptSource configuration tag and underlying code ## NEXT - 4.2.0 - 2024-01-23 diff --git a/inbm/configuration-agent/fpm-template/etc/intel_manageability.conf b/inbm/configuration-agent/fpm-template/etc/intel_manageability.conf index bf121ec3d..a91502a43 100644 --- a/inbm/configuration-agent/fpm-template/etc/intel_manageability.conf +++ b/inbm/configuration-agent/fpm-template/etc/intel_manageability.conf @@ -35,9 +35,6 @@ /etc/ssl/certs/csl-ca-cert.pem - - http://archive.ubuntu.com/ubuntu/ - true diff --git a/inbm/dispatcher-agent/dispatcher/dispatcher_class.py b/inbm/dispatcher-agent/dispatcher/dispatcher_class.py index d5ca167c5..da70d5ec3 100644 --- a/inbm/dispatcher-agent/dispatcher/dispatcher_class.py +++ b/inbm/dispatcher-agent/dispatcher/dispatcher_class.py @@ -569,12 +569,6 @@ def config_sanitize(the_payload: Any) -> Any: else: self.proceed_without_rollback = cleaned_payload - if config_name == "ubuntuAptSource": - if cleaned_payload is None: - logger.error("No ubuntuAptSource selected!") - else: - self._sota_repos = cleaned_payload - try: logger.debug('Subscribing to: %s', STATE_CHANNEL) self._dispatcher_broker.mqtt_subscribe(STATE_CHANNEL, self._on_message) diff --git a/inbm/dispatcher-agent/dispatcher/sota/constants.py b/inbm/dispatcher-agent/dispatcher/sota/constants.py index 0d8a60362..c25a8522a 100644 --- a/inbm/dispatcher-agent/dispatcher/sota/constants.py +++ b/inbm/dispatcher-agent/dispatcher/sota/constants.py @@ -14,8 +14,6 @@ # Mender artifact path MENDER_ARTIFACT_PATH = get_canonical_representation_of_path("/etc/mender/artifact_info") -GET_UBUNTU_PKG_REPO = "dispatcher/sota/ubuntuAptSource" - SOTA_STATE = 'normal' LOGPATH = '/var/lib/dispatcher/upload' diff --git a/inbm/dispatcher-agent/dispatcher/sota/setup_helper.py b/inbm/dispatcher-agent/dispatcher/sota/setup_helper.py index f2a9cf555..e3517da5c 100644 --- a/inbm/dispatcher-agent/dispatcher/sota/setup_helper.py +++ b/inbm/dispatcher-agent/dispatcher/sota/setup_helper.py @@ -15,7 +15,7 @@ from typing import Any, Optional from ..dispatcher_broker import DispatcherBroker -from .constants import GET_UBUNTU_PKG_REPO, APT_SOURCES_LIST_PATH, MENDER_FILE_PATH +from .constants import APT_SOURCES_LIST_PATH, MENDER_FILE_PATH from ..common import dispatcher_state logger = logging.getLogger(__name__) @@ -55,7 +55,6 @@ def __init__(self, sota_repos: Optional[str]) -> None: @param sota_repos: new Ubuntu/Debian mirror (or None) """ - self._list_path = GET_UBUNTU_PKG_REPO self._sota_repos = sota_repos super().__init__() diff --git a/inbm/integration-reloaded/scripts/iotg_inb_bmp.conf b/inbm/integration-reloaded/scripts/iotg_inb_bmp.conf index 4a7dd1c95..0597557a0 100644 --- a/inbm/integration-reloaded/scripts/iotg_inb_bmp.conf +++ b/inbm/integration-reloaded/scripts/iotg_inb_bmp.conf @@ -37,9 +37,6 @@ /etc/ssl/certs/csl-ca-cert.pem - - http://archive.ubuntu.com/ubuntu/ - true diff --git a/inbm/integration-reloaded/scripts/iotg_inb_developer_no_nw_check.conf b/inbm/integration-reloaded/scripts/iotg_inb_developer_no_nw_check.conf index 9b9570d83..a3b8ff5ac 100644 --- a/inbm/integration-reloaded/scripts/iotg_inb_developer_no_nw_check.conf +++ b/inbm/integration-reloaded/scripts/iotg_inb_developer_no_nw_check.conf @@ -39,9 +39,6 @@ /etc/ssl/certs/csl-ca-cert.pem - - http://archive.ubuntu.com/ubuntu/ - true diff --git a/inbm/packaging/windows-override/inbm/etc/intel_manageability.conf b/inbm/packaging/windows-override/inbm/etc/intel_manageability.conf index 0fe8e8248..983ba8ff2 100644 --- a/inbm/packaging/windows-override/inbm/etc/intel_manageability.conf +++ b/inbm/packaging/windows-override/inbm/etc/intel_manageability.conf @@ -26,9 +26,6 @@ - - http://archive.ubuntu.com/ubuntu/ - true diff --git a/inbm/venv-3.11/bin/Activate.ps1 b/inbm/venv-3.11/bin/Activate.ps1 new file mode 100644 index 000000000..b49d77ba4 --- /dev/null +++ b/inbm/venv-3.11/bin/Activate.ps1 @@ -0,0 +1,247 @@ +<# +.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/inbm/venv-3.11/bin/activate b/inbm/venv-3.11/bin/activate new file mode 100644 index 000000000..73a75a6e6 --- /dev/null +++ b/inbm/venv-3.11/bin/activate @@ -0,0 +1,63 @@ +# 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 + + # Call hash to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + hash -r 2> /dev/null + + if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then + PS1="${_OLD_VIRTUAL_PS1:-}" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + unset VIRTUAL_ENV_PROMPT + if [ ! "${1:-}" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +VIRTUAL_ENV="/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11" +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-3.11) ${PS1:-}" + export PS1 + VIRTUAL_ENV_PROMPT="(venv-3.11) " + export VIRTUAL_ENV_PROMPT +fi + +# Call hash to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +hash -r 2> /dev/null diff --git a/inbm/venv-3.11/bin/activate.csh b/inbm/venv-3.11/bin/activate.csh new file mode 100644 index 000000000..ddabfb3f4 --- /dev/null +++ b/inbm/venv-3.11/bin/activate.csh @@ -0,0 +1,26 @@ +# 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 "/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11" + +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-3.11) $prompt" + setenv VIRTUAL_ENV_PROMPT "(venv-3.11) " +endif + +alias pydoc python -m pydoc + +rehash diff --git a/inbm/venv-3.11/bin/activate.fish b/inbm/venv-3.11/bin/activate.fish new file mode 100644 index 000000000..e3affed57 --- /dev/null +++ b/inbm/venv-3.11/bin/activate.fish @@ -0,0 +1,69 @@ +# 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 "/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11" + +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-3.11) " (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-3.11) " +end diff --git a/inbm/venv-3.11/bin/coverage b/inbm/venv-3.11/bin/coverage new file mode 100755 index 000000000..5054e0d2b --- /dev/null +++ b/inbm/venv-3.11/bin/coverage @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- coding: utf-8 -*- +import re +import sys +from coverage.cmdline import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/inbm/venv-3.11/bin/coverage-3.11 b/inbm/venv-3.11/bin/coverage-3.11 new file mode 100755 index 000000000..5054e0d2b --- /dev/null +++ b/inbm/venv-3.11/bin/coverage-3.11 @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- coding: utf-8 -*- +import re +import sys +from coverage.cmdline import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/inbm/venv-3.11/bin/coverage3 b/inbm/venv-3.11/bin/coverage3 new file mode 100755 index 000000000..5054e0d2b --- /dev/null +++ b/inbm/venv-3.11/bin/coverage3 @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- coding: utf-8 -*- +import re +import sys +from coverage.cmdline import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/inbm/venv-3.11/bin/futurize b/inbm/venv-3.11/bin/futurize new file mode 100755 index 000000000..0dd1f3768 --- /dev/null +++ b/inbm/venv-3.11/bin/futurize @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- coding: utf-8 -*- +import re +import sys +from libfuturize.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/inbm/venv-3.11/bin/jsonschema b/inbm/venv-3.11/bin/jsonschema new file mode 100755 index 000000000..9132f8b37 --- /dev/null +++ b/inbm/venv-3.11/bin/jsonschema @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- coding: utf-8 -*- +import re +import sys +from jsonschema.cli import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/inbm/venv-3.11/bin/normalizer b/inbm/venv-3.11/bin/normalizer new file mode 100755 index 000000000..695676b61 --- /dev/null +++ b/inbm/venv-3.11/bin/normalizer @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- coding: utf-8 -*- +import re +import sys +from charset_normalizer.cli import cli_detect +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(cli_detect()) diff --git a/inbm/venv-3.11/bin/pasteurize b/inbm/venv-3.11/bin/pasteurize new file mode 100755 index 000000000..049212fc0 --- /dev/null +++ b/inbm/venv-3.11/bin/pasteurize @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- coding: utf-8 -*- +import re +import sys +from libpasteurize.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/inbm/venv-3.11/bin/pbr b/inbm/venv-3.11/bin/pbr new file mode 100755 index 000000000..23cf51957 --- /dev/null +++ b/inbm/venv-3.11/bin/pbr @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- coding: utf-8 -*- +import re +import sys +from pbr.cmd.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/inbm/venv-3.11/bin/pip b/inbm/venv-3.11/bin/pip new file mode 100755 index 000000000..f0d18cb8f --- /dev/null +++ b/inbm/venv-3.11/bin/pip @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- 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/inbm/venv-3.11/bin/pip3 b/inbm/venv-3.11/bin/pip3 new file mode 100755 index 000000000..f0d18cb8f --- /dev/null +++ b/inbm/venv-3.11/bin/pip3 @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- 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/inbm/venv-3.11/bin/pip3.11 b/inbm/venv-3.11/bin/pip3.11 new file mode 100755 index 000000000..f0d18cb8f --- /dev/null +++ b/inbm/venv-3.11/bin/pip3.11 @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- 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/inbm/venv-3.11/bin/py.test b/inbm/venv-3.11/bin/py.test new file mode 100755 index 000000000..21b7cf0a6 --- /dev/null +++ b/inbm/venv-3.11/bin/py.test @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- coding: utf-8 -*- +import re +import sys +from pytest import console_main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(console_main()) diff --git a/inbm/venv-3.11/bin/pygmentize b/inbm/venv-3.11/bin/pygmentize new file mode 100755 index 000000000..5dc5d76b8 --- /dev/null +++ b/inbm/venv-3.11/bin/pygmentize @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- 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/inbm/venv-3.11/bin/pyi-archive_viewer b/inbm/venv-3.11/bin/pyi-archive_viewer new file mode 100755 index 000000000..1ab6c9a22 --- /dev/null +++ b/inbm/venv-3.11/bin/pyi-archive_viewer @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- coding: utf-8 -*- +import re +import sys +from PyInstaller.utils.cliutils.archive_viewer import run +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(run()) diff --git a/inbm/venv-3.11/bin/pyi-bindepend b/inbm/venv-3.11/bin/pyi-bindepend new file mode 100755 index 000000000..101fbf41a --- /dev/null +++ b/inbm/venv-3.11/bin/pyi-bindepend @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- coding: utf-8 -*- +import re +import sys +from PyInstaller.utils.cliutils.bindepend import run +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(run()) diff --git a/inbm/venv-3.11/bin/pyi-grab_version b/inbm/venv-3.11/bin/pyi-grab_version new file mode 100755 index 000000000..d98c4aa84 --- /dev/null +++ b/inbm/venv-3.11/bin/pyi-grab_version @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- coding: utf-8 -*- +import re +import sys +from PyInstaller.utils.cliutils.grab_version import run +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(run()) diff --git a/inbm/venv-3.11/bin/pyi-makespec b/inbm/venv-3.11/bin/pyi-makespec new file mode 100755 index 000000000..afb042f65 --- /dev/null +++ b/inbm/venv-3.11/bin/pyi-makespec @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- coding: utf-8 -*- +import re +import sys +from PyInstaller.utils.cliutils.makespec import run +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(run()) diff --git a/inbm/venv-3.11/bin/pyi-set_version b/inbm/venv-3.11/bin/pyi-set_version new file mode 100755 index 000000000..ee0d5e71b --- /dev/null +++ b/inbm/venv-3.11/bin/pyi-set_version @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- coding: utf-8 -*- +import re +import sys +from PyInstaller.utils.cliutils.set_version import run +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(run()) diff --git a/inbm/venv-3.11/bin/pyinstaller b/inbm/venv-3.11/bin/pyinstaller new file mode 100755 index 000000000..d58762233 --- /dev/null +++ b/inbm/venv-3.11/bin/pyinstaller @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- coding: utf-8 -*- +import re +import sys +from PyInstaller.__main__ import _console_script_run +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(_console_script_run()) diff --git a/inbm/venv-3.11/bin/pytest b/inbm/venv-3.11/bin/pytest new file mode 100755 index 000000000..21b7cf0a6 --- /dev/null +++ b/inbm/venv-3.11/bin/pytest @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- coding: utf-8 -*- +import re +import sys +from pytest import console_main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(console_main()) diff --git a/inbm/venv-3.11/bin/python b/inbm/venv-3.11/bin/python new file mode 120000 index 000000000..6e7f3c7dd --- /dev/null +++ b/inbm/venv-3.11/bin/python @@ -0,0 +1 @@ +python3.11 \ No newline at end of file diff --git a/inbm/venv-3.11/bin/python3 b/inbm/venv-3.11/bin/python3 new file mode 120000 index 000000000..6e7f3c7dd --- /dev/null +++ b/inbm/venv-3.11/bin/python3 @@ -0,0 +1 @@ +python3.11 \ No newline at end of file diff --git a/inbm/venv-3.11/bin/python3.11 b/inbm/venv-3.11/bin/python3.11 new file mode 120000 index 000000000..bdc5cab32 --- /dev/null +++ b/inbm/venv-3.11/bin/python3.11 @@ -0,0 +1 @@ +/usr/bin/python3.11 \ No newline at end of file diff --git a/inbm/venv-3.11/bin/xmlschema-json2xml b/inbm/venv-3.11/bin/xmlschema-json2xml new file mode 100755 index 000000000..40b90ba4f --- /dev/null +++ b/inbm/venv-3.11/bin/xmlschema-json2xml @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- coding: utf-8 -*- +import re +import sys +from xmlschema.cli import json2xml +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(json2xml()) diff --git a/inbm/venv-3.11/bin/xmlschema-validate b/inbm/venv-3.11/bin/xmlschema-validate new file mode 100755 index 000000000..44c332cf4 --- /dev/null +++ b/inbm/venv-3.11/bin/xmlschema-validate @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- coding: utf-8 -*- +import re +import sys +from xmlschema.cli import validate +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(validate()) diff --git a/inbm/venv-3.11/bin/xmlschema-xml2json b/inbm/venv-3.11/bin/xmlschema-xml2json new file mode 100755 index 000000000..5d5c3cccb --- /dev/null +++ b/inbm/venv-3.11/bin/xmlschema-xml2json @@ -0,0 +1,8 @@ +#!/home/labadmin/inbm/intel-inb-manageability/inbm/venv-3.11/bin/python3.11 +# -*- coding: utf-8 -*- +import re +import sys +from xmlschema.cli import xml2json +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(xml2json()) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/__init__.py new file mode 100755 index 000000000..a742ff94b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/__init__.py @@ -0,0 +1,67 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +__all__ = ('HOMEPATH', 'PLATFORM', '__version__', 'DEFAULT_DISTPATH', 'DEFAULT_SPECPATH', 'DEFAULT_WORKPATH') + +import os +import sys + +from PyInstaller import compat +from PyInstaller.utils.git import get_repo_revision + +# Note: Keep this variable as plain string so it could be updated automatically when doing a release. +__version__ = '5.13.1' + +# Absolute path of this package's directory. Save this early so all submodules can use the absolute path. This is +# required for example if the current directory changes prior to loading the hooks. +PACKAGEPATH = os.path.abspath(os.path.dirname(__file__)) + +HOMEPATH = os.path.dirname(PACKAGEPATH) + +# Update __version__ as necessary. +if os.path.exists(os.path.join(HOMEPATH, 'setup.py')): + # PyInstaller is run directly from source without installation, or __version__ is called from 'setup.py'... + if compat.getenv('PYINSTALLER_DO_RELEASE') == '1': + # Suppress the git revision when doing a release. + pass + elif 'sdist' not in sys.argv: + # and 'setup.py' was not called with 'sdist' argument. For creating source tarball we do not want git revision + # in the filename. + try: + __version__ += get_repo_revision() + except Exception: + # Write to stderr because stdout is used for eval() statement in some subprocesses. + sys.stderr.write('WARN: failed to parse git revision') +else: + # PyInstaller was installed by `python setup.py install'. + if compat.is_py38: + from importlib.metadata import version + else: + from importlib_metadata import version + __version__ = version('PyInstaller') +# Default values of paths where to put files created by PyInstaller. If changing these, do not forget to update the +# help text for corresponding command-line options, defined in build_main. + +# Where to put created .spec file. +DEFAULT_SPECPATH = os.getcwd() +# Where to put the final frozen application. +DEFAULT_DISTPATH = os.path.join(os.getcwd(), 'dist') +# Where to put all the temporary files; .log, .pyz, etc. +DEFAULT_WORKPATH = os.path.join(os.getcwd(), 'build') + +PLATFORM = compat.system + '-' + compat.architecture +# Include machine name in path to bootloader for some machines (e.g., 'arm'). Explicitly avoid doing this on macOS, +# where we keep universal2 bootloaders in Darwin-64bit folder regardless of whether we are on x86_64 or arm64. +if compat.machine and not compat.is_darwin: + PLATFORM += '-' + compat.machine +# Similarly, disambiguate musl Linux from glibc Linux. +if compat.is_musl: + PLATFORM += '-musl' diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/__main__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/__main__.py new file mode 100755 index 000000000..c21b85f23 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/__main__.py @@ -0,0 +1,198 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Main command-line interface to PyInstaller. +""" +from __future__ import annotations + +import argparse +import os +import platform +import sys +from collections import defaultdict + +from PyInstaller import __version__ +from PyInstaller import log as logging +# Note: do not import anything else until compat.check_requirements function is run! +from PyInstaller import compat + +logger = logging.getLogger(__name__) + +# Taken from https://stackoverflow.com/a/22157136 to format args more flexibly: any help text which beings with ``R|`` +# will have all newlines preserved; the help text will be line wrapped. See +# https://docs.python.org/3/library/argparse.html#formatter-class. + + +# This is used by the ``--debug`` option. +class _SmartFormatter(argparse.HelpFormatter): + def _split_lines(self, text, width): + if text.startswith('R|'): + # The underlying implementation of ``RawTextHelpFormatter._split_lines`` invokes this; mimic it. + return text[2:].splitlines() + else: + # Invoke the usual formatter. + return super()._split_lines(text, width) + + +def run_makespec(filenames, **opts): + # Split pathex by using the path separator + temppaths = opts['pathex'][:] + pathex = opts['pathex'] = [] + for p in temppaths: + pathex.extend(p.split(os.pathsep)) + + import PyInstaller.building.makespec + + spec_file = PyInstaller.building.makespec.main(filenames, **opts) + logger.info('wrote %s' % spec_file) + return spec_file + + +def run_build(pyi_config, spec_file, **kwargs): + import PyInstaller.building.build_main + PyInstaller.building.build_main.main(pyi_config, spec_file, **kwargs) + + +def __add_options(parser): + parser.add_argument( + '-v', + '--version', + action='version', + version=__version__, + help='Show program version info and exit.', + ) + + +class _PyiArgumentParser(argparse.ArgumentParser): + def __init__(self, *args, **kwargs): + self._pyi_action_groups = defaultdict(list) + super().__init__(*args, **kwargs) + + def _add_options(self, __add_options: callable, name: str = ""): + """ + Mutate self with the given callable, storing any new actions added in a named group + """ + n_actions_before = len(getattr(self, "_actions", [])) + __add_options(self) # preserves old behavior + new_actions = getattr(self, "_actions", [])[n_actions_before:] + self._pyi_action_groups[name].extend(new_actions) + + def _option_name(self, action): + """ + Get the option name(s) associated with an action + + For options that define both short and long names, this function will + return the long names joined by "/" + """ + longnames = [name for name in action.option_strings if name.startswith("--")] + if longnames: + name = "/".join(longnames) + else: + name = action.option_strings[0] + return name + + def _forbid_options(self, args: argparse.Namespace, group: str, errmsg: str = ""): + """Forbid options from a named action group""" + options = defaultdict(str) + for action in self._pyi_action_groups[group]: + dest = action.dest + name = self._option_name(action) + if getattr(args, dest) is not self.get_default(dest): + if dest in options: + options[dest] += "/" + options[dest] += name + + # if any options from the forbidden group are not the default values, + # the user must have passed them in, so issue an error report + if options: + sep = "\n " + bad = sep.join(options.values()) + if errmsg: + errmsg = "\n" + errmsg + raise SystemExit(f"option(s) not allowed:{sep}{bad}{errmsg}") + + +def generate_parser() -> _PyiArgumentParser: + """ + Build an argparse parser for PyInstaller's main CLI. + """ + + import PyInstaller.building.build_main + import PyInstaller.building.makespec + import PyInstaller.log + + parser = _PyiArgumentParser(formatter_class=_SmartFormatter) + parser.prog = "pyinstaller" + + parser._add_options(__add_options) + parser._add_options(PyInstaller.building.makespec.__add_options, name="makespec") + parser._add_options(PyInstaller.building.build_main.__add_options, name="build_main") + parser._add_options(PyInstaller.log.__add_options, name="log") + + parser.add_argument( + 'filenames', + metavar='scriptname', + nargs='+', + help="Name of scriptfiles to be processed or exactly one .spec file. If a .spec file is specified, most " + "options are unnecessary and are ignored.", + ) + + return parser + + +def run(pyi_args: list | None = None, pyi_config: dict | None = None): + """ + pyi_args allows running PyInstaller programmatically without a subprocess + pyi_config allows checking configuration once when running multiple tests + """ + compat.check_requirements() + + import PyInstaller.log + + try: + parser = generate_parser() + args = parser.parse_args(pyi_args) + PyInstaller.log.__process_options(parser, args) + + # Print PyInstaller version, Python version, and platform as the first line to stdout. This helps us identify + # PyInstaller, Python, and platform version when users report issues. + logger.info('PyInstaller: %s' % __version__) + logger.info('Python: %s%s', platform.python_version(), " (conda)" if compat.is_conda else "") + logger.info('Platform: %s' % platform.platform()) + + # Skip creating .spec when .spec file is supplied. + if args.filenames[0].endswith('.spec'): + parser._forbid_options( + args, group="makespec", errmsg="makespec options not valid when a .spec file is given" + ) + spec_file = args.filenames[0] + else: + spec_file = run_makespec(**vars(args)) + + run_build(pyi_config, spec_file, **vars(args)) + + except KeyboardInterrupt: + raise SystemExit("Aborted by user request.") + except RecursionError: + from PyInstaller import _recursion_too_deep_message + _recursion_too_deep_message.raise_with_msg() + + +def _console_script_run(): + # Python prepends the main script's parent directory to sys.path. When PyInstaller is ran via the usual + # `pyinstaller` CLI entry point, this directory is $pythonprefix/bin which should not be in sys.path. + if os.path.basename(sys.path[0]) in ("bin", "Scripts"): + sys.path.pop(0) + run() + + +if __name__ == '__main__': + run() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/_recursion_too_deep_message.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/_recursion_too_deep_message.py new file mode 100755 index 000000000..b3cb1b33c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/_recursion_too_deep_message.py @@ -0,0 +1,45 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +msg = """ +============================================================= +A RecursionError (maximum recursion depth exceeded) occurred. +For working around please follow these instructions +============================================================= + +1. In your program's .spec file add this line near the top:: + + import sys ; sys.setrecursionlimit(sys.getrecursionlimit() * 5) + +2. Build your program by running PyInstaller with the .spec file as + argument:: + + pyinstaller myprog.spec + +3. If this fails, you most probably hit an endless recursion in + PyInstaller. Please try to track this down has far as possible, + create a minimal example so we can reproduce and open an issue at + https://github.com/pyinstaller/pyinstaller/issues following the + instructions in the issue template. Many thanks. + +Explanation: Python's stack-limit is a safety-belt against endless recursion, +eating up memory. PyInstaller imports modules recursively. If the structure +how modules are imported within your program is awkward, this leads to the +nesting being too deep and hitting Python's stack-limit. + +With the default recursion limit (1000), the recursion error occurs at about +115 nested imported, with limit 2000 at about 240, with limit 5000 at about +660. +""" + + +def raise_with_msg(): + raise SystemExit(msg) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/_shared_with_waf.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/_shared_with_waf.py new file mode 100755 index 000000000..c3d52adf6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/_shared_with_waf.py @@ -0,0 +1,86 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Code to be shared by PyInstaller and the bootloader/wscript file. + +This code must not assume that either PyInstaller or any of its dependencies installed. I.e., the only imports allowed +in here are standard library ones. Within reason, it is preferable that this file should still run under Python 2.7 as +many compiler docker images still have only Python 2 installed. +""" + +import platform +import re + + +def _pyi_machine(machine, system): + # type: (str, str) -> str + """ + Choose an intentionally simplified architecture identifier to be used in the bootloader's directory name. + + Args: + machine: + The output of ``platform.machine()`` or any known architecture alias or shorthand that may be used by a + C compiler. + system: + The output of ``platform.system()`` on the target machine. + Returns: + Either a string tag or, on platforms that don't need an architecture tag, ``None``. + + Ideally, we would just use ``platform.machine()`` directly, but that makes cross-compiling the bootloader almost + impossible, because you need to know at compile time exactly what ``platform.machine()`` will be at run time, based + only on the machine name alias or shorthand reported by the C compiler at the build time. Rather, use a loose + differentiation, and trust that anyone mixing armv6l with armv6h knows what they are doing. + """ + # See the corresponding tests in tests/unit/test_compat.py for examples. + + if platform.machine() == "sw_64" or platform.machine() == "loongarch64": + # This explicitly inhibits cross compiling the bootloader for or on SunWay and LoongArch machine. + return platform.machine() + + if system == "Windows": + if machine.lower().startswith("arm"): + return "arm" + else: + return "intel" + + if system != "Linux": + # No architecture specifier for anything par Linux. + # - macOS is on two 64 bit architectures, but they are merged into one "universal2" bootloader. + # - BSD supports a wide range of architectures, but according to PyPI's download statistics, every one of our + # BSD users are on x86_64. This may change in the distant future. + return + + if machine.startswith(("arm", "aarch")): + # ARM has a huge number of similar and aliased sub-versions, such as armv5, armv6l armv8h, aarch64. + return "arm" + if machine in ("thumb"): + # Reported by waf/gcc when Thumb instruction set is enabled on 32-bit ARM. The platform.machine() returns "arm" + # regardless of the instruction set. + return "arm" + if machine in ("x86_64", "x64", "x86"): + return "intel" + if re.fullmatch("i[1-6]86", machine): + return "intel" + if machine.startswith(("ppc", "powerpc")): + # PowerPC comes in 64 vs 32 bit and little vs big endian variants. + return "ppc" + if machine in ("mips64", "mips"): + return "mips" + if machine.startswith("riscv"): + return "riscv" + # Machines with no known aliases :) + if machine in ("s390x",): + return machine + + # Unknown architectures are allowed by default, but will all be placed under one directory. In theory, trying to + # have multiple unknown architectures in one copy of PyInstaller will not work, but that should be sufficiently + # unlikely to ever happen. + return "unknown" diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/archive/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/archive/__init__.py new file mode 100755 index 000000000..a7501ae07 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/archive/__init__.py @@ -0,0 +1 @@ +__author__ = 'martin' diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/archive/pyz_crypto.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/archive/pyz_crypto.py new file mode 100755 index 000000000..530469aca --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/archive/pyz_crypto.py @@ -0,0 +1,48 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +import os + +from PyInstaller import log as logging + +BLOCK_SIZE = 16 +logger = logging.getLogger(__name__) + + +class PyiBlockCipher: + """ + This class is used only to encrypt Python modules. + """ + def __init__(self, key=None): + logger.log( + logging.DEPRECATION, + "Bytecode encryption will be removed in PyInstaller v6. Please remove cipher and block_cipher parameters " + "from your spec file to avoid breakages on upgrade. For the rationale/alternatives see " + "https://github.com/pyinstaller/pyinstaller/pull/6999" + ) + assert type(key) is str + if len(key) > BLOCK_SIZE: + self.key = key[0:BLOCK_SIZE] + else: + self.key = key.zfill(BLOCK_SIZE) + assert len(self.key) == BLOCK_SIZE + + import tinyaes + self._aesmod = tinyaes + + def encrypt(self, data): + iv = os.urandom(BLOCK_SIZE) + return iv + self.__create_cipher(iv).CTR_xcrypt_buffer(data) + + def __create_cipher(self, iv): + # The 'AES' class is stateful, and this factory method is used to re-initialize the block cipher class with + # each call to xcrypt(). + return self._aesmod.AES(self.key.encode(), iv) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/archive/readers.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/archive/readers.py new file mode 100755 index 000000000..51d959f2e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/archive/readers.py @@ -0,0 +1,221 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Python-based CArchive (PKG) reader implementation. Used only in the archive_viewer utility. +""" + +import os +import struct + +from PyInstaller.loader.pyimod01_archive import ZlibArchiveReader, ArchiveReadError + + +class NotAnArchiveError(TypeError): + pass + + +# Type codes for CArchive TOC entries +PKG_ITEM_BINARY = 'b' # binary +PKG_ITEM_DEPENDENCY = 'd' # runtime option +PKG_ITEM_PYZ = 'z' # zlib (pyz) - frozen Python code +PKG_ITEM_ZIPFILE = 'Z' # zlib (pyz) - frozen Python code +PKG_ITEM_PYPACKAGE = 'M' # Python package (__init__.py) +PKG_ITEM_PYMODULE = 'm' # Python module +PKG_ITEM_PYSOURCE = 's' # Python script (v3) +PKG_ITEM_DATA = 'x' # data +PKG_ITEM_RUNTIME_OPTION = 'o' # runtime option +PKG_ITEM_SPLASH = 'l' # splash resources + + +class CArchiveReader: + """ + Reader for PyInstaller's CArchive (PKG) archive. + """ + + # Cookie - holds some information for the bootloader. C struct format definition. '!' at the beginning means network + # byte order. C struct looks like: + # + # typedef struct _cookie { + # char magic[8]; /* 'MEI\014\013\012\013\016' */ + # uint32_t len; /* len of entire package */ + # uint32_t TOC; /* pos (rel to start) of TableOfContents */ + # int TOClen; /* length of TableOfContents */ + # int pyvers; /* new in v4 */ + # char pylibname[64]; /* Filename of Python dynamic library. */ + # } COOKIE; + # + _COOKIE_MAGIC_PATTERN = b'MEI\014\013\012\013\016' + + _COOKIE_FORMAT = '!8sIIii64s' + _COOKIE_LENGTH = struct.calcsize(_COOKIE_FORMAT) + + # TOC entry: + # + # typedef struct _toc { + # int structlen; /* len of this one - including full len of name */ + # uint32_t pos; /* pos rel to start of concatenation */ + # uint32_t len; /* len of the data (compressed) */ + # uint32_t ulen; /* len of data (uncompressed) */ + # char cflag; /* is it compressed (really a byte) */ + # char typcd; /* type code -'b' binary, 'z' zlib, 'm' module, + # * 's' script (v3),'x' data, 'o' runtime option */ + # char name[1]; /* the name to save it as */ + # /* starting in v5, we stretch this out to a mult of 16 */ + # } TOC; + # + _TOC_ENTRY_FORMAT = '!iIIIBB' + _TOC_ENTRY_LENGTH = struct.calcsize(_TOC_ENTRY_FORMAT) + + def __init__(self, filename): + self._filename = filename + self._start_offset = 0 + self._toc_offset = 0 + self._toc_length = 0 + + self.toc = {} + + # Load TOC + with open(self._filename, "rb") as fp: + # Find cookie MAGIC pattern + cookie_start_offset = self._find_magic_pattern(fp, self._COOKIE_MAGIC_PATTERN) + if cookie_start_offset == -1: + raise ArchiveReadError("Could not find COOKIE magic pattern!") + + # Read the whole cookie + fp.seek(cookie_start_offset, os.SEEK_SET) + cookie_data = fp.read(self._COOKIE_LENGTH) + + magic, archive_length, toc_offset, toc_length, pyvers, pylib_name = \ + struct.unpack(self._COOKIE_FORMAT, cookie_data) + + # Compute start of the the archive + self._start_offset = (cookie_start_offset + self._COOKIE_LENGTH) - archive_length + + # Verify that Python shared library name is set + if not pylib_name: + raise ArchiveReadError("Python shared library name not set in the archive!") + + # Read whole toc + fp.seek(self._start_offset + toc_offset) + toc_data = fp.read(toc_length) + + self.toc = self._parse_toc(toc_data) + + @staticmethod + def _find_magic_pattern(fp, magic_pattern): + # Start at the end of file, and scan back-to-start + fp.seek(0, os.SEEK_END) + end_pos = fp.tell() + + # Scan from back + SEARCH_CHUNK_SIZE = 8192 + magic_offset = -1 + while end_pos >= len(magic_pattern): + start_pos = max(end_pos - SEARCH_CHUNK_SIZE, 0) + chunk_size = end_pos - start_pos + # Is the remaining chunk large enough to hold the pattern? + if chunk_size < len(magic_pattern): + break + # Read and scan the chunk + fp.seek(start_pos, os.SEEK_SET) + buf = fp.read(chunk_size) + pos = buf.rfind(magic_pattern) + if pos != -1: + magic_offset = start_pos + pos + break + # Adjust search location for next chunk; ensure proper overlap + end_pos = start_pos + len(magic_pattern) - 1 + + return magic_offset + + @classmethod + def _parse_toc(cls, data): + toc = {} + cur_pos = 0 + while cur_pos < len(data): + # Read and parse the fixed-size TOC entry header + entry_length, entry_offset, data_length, uncompressed_length, compression_flag, typecode = \ + struct.unpack(cls._TOC_ENTRY_FORMAT, data[cur_pos:(cur_pos + cls._TOC_ENTRY_LENGTH)]) + cur_pos += cls._TOC_ENTRY_LENGTH + # Read variable-length name + name_length = entry_length - cls._TOC_ENTRY_LENGTH + name, *_ = struct.unpack(f'{name_length}s', data[cur_pos:(cur_pos + name_length)]) + cur_pos += name_length + # Name string may contain up to 15 bytes of padding + name = name.rstrip(b'\0').decode('utf-8') + + typecode = chr(typecode) + + # TODO: handle duplicates + toc[name] = (entry_offset, data_length, uncompressed_length, compression_flag, typecode) + + return toc + + def extract(self, name): + """ + Extract data for the given entry name. + """ + + entry = self.toc.get(name) + if entry is None: + raise KeyError(f"No entry named {name} found in the archive!") + + entry_offset, data_length, uncompressed_length, compression_flag, typecode = entry + with open(self._filename, "rb") as fp: + fp.seek(self._start_offset + entry_offset, os.SEEK_SET) + data = fp.read(data_length) + + if compression_flag: + import zlib + data = zlib.decompress(data) + + return data + + def open_embedded_archive(self, name): + """ + Open new archive reader for the embedded archive. + """ + + entry = self.toc.get(name) + if entry is None: + raise KeyError(f"No entry named {name} found in the archive!") + + entry_offset, data_length, uncompressed_length, compression_flag, typecode = entry + + if typecode == PKG_ITEM_PYZ: + # Open as embedded archive, without extraction. + return ZlibArchiveReader(self._filename, self._start_offset + entry_offset) + elif typecode == PKG_ITEM_ZIPFILE: + raise NotAnArchiveError("Zipfile archives not supported yet!") + else: + raise NotAnArchiveError(f"Entry {name} is not a supported embedded archive!") + + +def pkg_archive_contents(filename, recursive=True): + """ + List the contents of the PKG / CArchive. If `recursive` flag is set (the default), the contents of the embedded PYZ + archive is included as well. + + Used by the tests. + """ + + contents = [] + + pkg_archive = CArchiveReader(filename) + for name, toc_entry in pkg_archive.toc.items(): + *_, typecode = toc_entry + contents.append(name) + if typecode == PKG_ITEM_PYZ and recursive: + pyz_archive = pkg_archive.open_embedded_archive(name) + for name in pyz_archive.toc.keys(): + contents.append(name) + + return contents diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/archive/writers.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/archive/writers.py new file mode 100755 index 000000000..9bd19b072 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/archive/writers.py @@ -0,0 +1,414 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Utilities to create data structures for embedding Python modules and additional files into the executable. +""" + +import marshal +import os +import shutil +import struct +import sys +import zlib + +from PyInstaller.building.utils import get_code_object, strip_paths_in_code +from PyInstaller.compat import BYTECODE_MAGIC, is_win, strict_collect_mode +from PyInstaller.loader.pyimod01_archive import PYZ_ITEM_DATA, PYZ_ITEM_MODULE, PYZ_ITEM_NSPKG, PYZ_ITEM_PKG + + +class ZlibArchiveWriter: + """ + Writer for PyInstaller's PYZ (ZlibArchive) archive. The archive is used to store collected byte-compiled Python + modules, as individually-compressed entries. + """ + _PYZ_MAGIC_PATTERN = b'PYZ\0' + _HEADER_LENGTH = 12 + 5 + _COMPRESSION_LEVEL = 6 # zlib compression level + + def __init__(self, filename, entries, code_dict=None, cipher=None): + """ + filename + Target filename of the archive. + entries + An iterable containing entries in the form of tuples: (name, src_path, typecode), where `name` is the name + under which the resource is stored (e.g., python module name, without suffix), `src_path` is name of the + file from which the resource is read, and `typecode` is the Analysis-level TOC typecode (`PYMODULE` or + `DATA`). + code_dict + Optional code dictionary containing code objects for analyzed/collected python modules. + cipher + Optional `Cipher` object for bytecode encryption. + """ + code_dict = code_dict or {} + + with open(filename, "wb") as fp: + # Reserve space for the header. + fp.write(b'\0' * self._HEADER_LENGTH) + + # Write entries' data and collect TOC entries + toc = [] + for entry in entries: + toc_entry = self._write_entry(fp, entry, code_dict, cipher) + toc.append(toc_entry) + + # Write TOC + toc_offset = fp.tell() + toc_data = marshal.dumps(toc) + fp.write(toc_data) + + # Write header: + # - PYZ magic pattern (4 bytes) + # - python bytecode magic pattern (4 bytes) + # - TOC offset (32-bit int, 4 bytes) + # - encryption flag (1 byte) + # - 4 unused bytes + fp.seek(0, os.SEEK_SET) + + fp.write(self._PYZ_MAGIC_PATTERN) + fp.write(BYTECODE_MAGIC) + fp.write(struct.pack('!i', toc_offset)) + fp.write(struct.pack('!B', cipher is not None)) + + @classmethod + def _write_entry(cls, fp, entry, code_dict, cipher): + name, src_path, typecode = entry + + if typecode == 'PYMODULE': + typecode = PYZ_ITEM_MODULE + if src_path in ('-', None): + # This is a NamespacePackage, modulegraph marks them by using the filename '-'. (But wants to use None, + # so check for None, too, to be forward-compatible.) + typecode = PYZ_ITEM_NSPKG + else: + src_basename, _ = os.path.splitext(os.path.basename(src_path)) + if src_basename == '__init__': + typecode = PYZ_ITEM_PKG + data = marshal.dumps(code_dict[name]) + else: + # Any data files, that might be required by pkg_resources. + typecode = PYZ_ITEM_DATA + with open(src_path, 'rb') as fh: + data = fh.read() + # No need to use forward slash as path-separator here since pkg_resources on Windows uses back slash as + # path-separator. + + # First compress, then encrypt. + obj = zlib.compress(data, cls._COMPRESSION_LEVEL) + if cipher: + obj = cipher.encrypt(obj) + + # Create TOC entry + toc_entry = (name, (typecode, fp.tell(), len(obj))) + + # Write data blob + fp.write(obj) + + return toc_entry + + +class CArchiveWriter: + """ + Writer for PyInstaller's CArchive (PKG) archive. + + This archive contains all files that are bundled within an executable; a PYZ (ZlibArchive), DLLs, Python C + extensions, and other data files that are bundled in onefile mode. + + The archive can be read from either C (bootloader code at application's run-time) or Python (for debug purposes). + """ + _COOKIE_MAGIC_PATTERN = b'MEI\014\013\012\013\016' + + # For cookie and TOC entry structure, see `PyInstaller.archive.readers.CArchiveReader`. + _COOKIE_FORMAT = '!8sIIii64s' + _COOKIE_LENGTH = struct.calcsize(_COOKIE_FORMAT) + + _TOC_ENTRY_FORMAT = '!iIIIBB' + _TOC_ENTRY_LENGTH = struct.calcsize(_TOC_ENTRY_FORMAT) + + _COMPRESSION_LEVEL = 9 # zlib compression level + + def __init__(self, filename, entries, pylib_name): + """ + filename + Target filename of the archive. + entries + An iterable containing entries in the form of tuples: (dest_name, src_name, compress, typecode), where + `dest_name` is the name under which the resource is stored in the archive (and name under which it is + extracted at runtime), `src_name` is name of the file from which the resouce is read, `compress` is a + boolean compression flag, and `typecode` is the Analysis-level TOC typecode. + pylib_name + Name of the python shared library. + """ + self._collected_names = set() # Track collected names for strict package mode. + + with open(filename, "wb") as fp: + # Write entries' data and collect TOC entries + toc = [] + for entry in entries: + toc_entry = self._write_entry(fp, entry) + toc.append(toc_entry) + + # Write TOC + toc_offset = fp.tell() + toc_data = self._serialize_toc(toc) + toc_length = len(toc_data) + + fp.write(toc_data) + + # Write cookie + archive_length = toc_offset + toc_length + self._COOKIE_LENGTH + pyvers = sys.version_info[0] * 100 + sys.version_info[1] + cookie_data = struct.pack( + self._COOKIE_FORMAT, + self._COOKIE_MAGIC_PATTERN, + archive_length, + toc_offset, + toc_length, + pyvers, + pylib_name.encode('ascii'), + ) + + fp.write(cookie_data) + + def _write_entry(self, fp, entry): + dest_name, src_name, compress, typecode = entry + + # Ensure forward slashes in paths are on Windows converted to back slashes '\\', as on Windows the bootloader + # works only with back slashes. + dest_name = os.path.normpath(dest_name) + if is_win and os.path.sep == '/': + # When building under MSYS, the above path normalization uses Unix-style separators, so replace them + # manually. + dest_name = dest_name.replace(os.path.sep, '\\') + + # Strict pack/collect mode: keep track of the destination names, and raise an error if we try to add a duplicate + # (a file with same destination name, subject to OS case normalization rules). + if strict_collect_mode: + normalized_dest = None + if type in ('o', 's', 'm', 'M'): + # Exempt options, python source script, and modules from the check + pass + else: + # Everything else; normalize the case + normalized_dest = os.path.normcase(dest_name) + # Check for existing entry, if applicable + if normalized_dest: + if normalized_dest in self._collected_names: + raise ValueError( + f"Attempting to collect a duplicated file into CArchive: {normalized_dest} (type: {typecode})" + ) + self._collected_names.add(normalized_dest) + + if typecode == 'o': + return self._write_blob(fp, b"", dest_name, typecode) + elif typecode == 'd': + # Dependency; merge src_name (= reference path prefix) and dest_name (= name) into single-string format that + # is parsed by bootloader. + return self._write_blob(fp, b"", f"{src_name}:{dest_name}", typecode) + elif typecode == 's': + # If it is a source code file, compile it to a code object and marshal the object, so it can be unmarshalled + # by the bootloader. + code = get_code_object(dest_name, src_name) + code = strip_paths_in_code(code) + return self._write_blob(fp, marshal.dumps(code), dest_name, typecode, compress=compress) + elif typecode in ('m', 'M'): + # Read the PYC file + with open(src_name, "rb") as in_fp: + data = in_fp.read() + assert data[:4] == BYTECODE_MAGIC + # Skip the PYC header, load the code object. + code = marshal.loads(data[16:]) + code = strip_paths_in_code(code) + # These module entries are loaded and executed within the bootloader, which requires only the code + # object, without the PYC header. + return self._write_blob(fp, marshal.dumps(code), dest_name, typecode, compress=compress) + else: + return self._write_file(fp, src_name, dest_name, typecode, compress=compress) + + def _write_blob(self, out_fp, blob: bytes, dest_name, typecode, compress=False): + """ + Write the binary contents (**blob**) of a small file to the archive and return the corresponding CArchive TOC + entry. + """ + data_offset = out_fp.tell() + data_length = len(blob) + if compress: + blob = zlib.compress(blob, level=self._COMPRESSION_LEVEL) + out_fp.write(blob) + + return (data_offset, len(blob), data_length, int(compress), typecode, dest_name) + + def _write_file(self, out_fp, src_name, dest_name, typecode, compress=False): + """ + Stream copy a large file into the archive and return the corresponding CArchive TOC entry. + """ + data_offset = out_fp.tell() + data_length = os.stat(src_name).st_size + with open(src_name, 'rb') as in_fp: + if compress: + tmp_buffer = bytearray(16 * 1024) + compressor = zlib.compressobj(self._COMPRESSION_LEVEL) + while True: + num_read = in_fp.readinto(tmp_buffer) + if not num_read: + break + out_fp.write(compressor.compress(tmp_buffer[:num_read])) + out_fp.write(compressor.flush()) + else: + shutil.copyfileobj(in_fp, out_fp) + + return (data_offset, out_fp.tell() - data_offset, data_length, int(compress), typecode, dest_name) + + @classmethod + def _serialize_toc(cls, toc): + serialized_toc = [] + for toc_entry in toc: + data_offset, compressed_length, data_length, compress, typecode, name = toc_entry + + # Encode names as UTF-8. This should be safe as standard python modules only contain ASCII-characters (and + # standard shared libraries should have the same), and thus the C-code still can handle this correctly. + name = name.encode('utf-8') + name_length = len(name) + 1 # Add 1 for string-terminating zero byte. + + # Ensure TOC entries are aligned on 16-byte boundary, so they can be read by bootloader (C code) on + # platforms with strict data alignment requirements (for example linux on `armhf`/`armv7`, such as 32-bit + # Debian Buster on Raspberry Pi). + entry_length = cls._TOC_ENTRY_LENGTH + name_length + if entry_length % 16 != 0: + padding_length = 16 - (entry_length % 16) + name_length += padding_length + + # Serialize + serialized_entry = struct.pack( + cls._TOC_ENTRY_FORMAT + f"{name_length}s", # "Ns" format automatically pads the string with zero bytes. + cls._TOC_ENTRY_LENGTH + name_length, + data_offset, + compressed_length, + data_length, + compress, + ord(typecode), + name, + ) + serialized_toc.append(serialized_entry) + + return b''.join(serialized_toc) + + +class SplashWriter: + """ + Writer for the splash screen resources archive. + + The resulting archive is added as an entry into the CArchive with the typecode PKG_ITEM_SPLASH. + """ + # This struct describes the splash resources as it will be in an buffer inside the bootloader. All necessary parts + # are bundled, the *_len and *_offset fields describe the data beyond this header definition. + # Whereas script and image fields are binary data, the requirements fields describe an array of strings. Each string + # is null-terminated in order to easily iterate over this list from within C. + # + # typedef struct _splash_data_header { + # char tcl_libname[16]; /* Name of tcl library, e.g. tcl86t.dll */ + # char tk_libname[16]; /* Name of tk library, e.g. tk86t.dll */ + # char tk_lib[16]; /* Tk Library generic, e.g. "tk/" */ + # char rundir[16]; /* temp folder inside extraction path in + # * which the dependencies are extracted */ + # + # int script_len; /* Length of the script */ + # int script_offset; /* Offset (rel to start) of the script */ + # + # int image_len; /* Length of the image data */ + # int image_offset; /* Offset (rel to start) of the image */ + # + # int requirements_len; + # int requirements_offset; + # + # } SPLASH_DATA_HEADER; + # + _HEADER_FORMAT = '!16s 16s 16s 16s ii ii ii' + _HEADER_LENGTH = struct.calcsize(_HEADER_FORMAT) + + # The created archive is compressed by the CArchive, so no need to compress the data here. + + def __init__(self, filename, name_list, tcl_libname, tk_libname, tklib, rundir, image, script): + """ + Writer for splash screen resources that are bundled into the CArchive as a single archive/entry. + + :param filename: The filename of the archive to create + :param name_list: List of filenames for the requirements array + :param str tcl_libname: Name of the tcl shared library file + :param str tk_libname: Name of the tk shared library file + :param str tklib: Root of tk library (e.g. tk/) + :param str rundir: Unique path to extract requirements to + :param Union[str, bytes] image: Image like object + :param str script: The tcl/tk script to execute to create the screen. + """ + + # Ensure forward slashes in dependency names are on Windows converted to back slashes '\\', as on Windows the + # bootloader works only with back slashes. + def _normalize_filename(filename): + filename = os.path.normpath(filename) + if is_win and os.path.sep == '/': + # When building under MSYS, the above path normalization uses Unix-style separators, so replace them + # manually. + filename = filename.replace(os.path.sep, '\\') + return filename + + name_list = [_normalize_filename(name) for name in name_list] + + with open(filename, "wb") as fp: + # Reserve space for the header. + fp.write(b'\0' * self._HEADER_LENGTH) + + # Serialize the requirements list. This list (more an array) contains the names of all files the bootloader + # needs to extract before the splash screen can be started. The implementation terminates every name with a + # null-byte, that keeps the list short memory wise and makes it iterable from C. + requirements_len = 0 + requirements_offset = fp.tell() + for name in name_list: + name = name.encode('utf-8') + b'\0' + fp.write(name) + requirements_len += len(name) + + # Write splash script + script_offset = fp.tell() + script_len = len(script) + fp.write(script.encode("utf-8")) + + # Write splash image. If image is a bytes buffer, it is written directly into the archive. Otherwise, it + # is assumed to be a path and the file is copied into the archive. + image_offset = fp.tell() + if isinstance(image, bytes): + # Image was converted by PIL/Pillow and is already in buffer + image_len = len(image) + fp.write(image) + else: + # Read image into buffer + with open(image, 'rb') as image_fp: + image_data = image_fp.read() + image_len = len(image_data) + fp.write(image_data) + del image_data + + # Write header + header_data = struct.pack( + self._HEADER_FORMAT, + tcl_libname.encode("utf-8"), + tk_libname.encode("utf-8"), + tklib.encode("utf-8"), + rundir.encode("utf-8"), + script_len, + script_offset, + image_len, + image_offset, + requirements_len, + requirements_offset, + ) + + fp.seek(0, os.SEEK_SET) + fp.write(header_data) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/bootloader/Linux-64bit-intel/run b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/bootloader/Linux-64bit-intel/run new file mode 100755 index 000000000..1e4b7f1df Binary files /dev/null and b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/bootloader/Linux-64bit-intel/run differ diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/bootloader/Linux-64bit-intel/run_d b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/bootloader/Linux-64bit-intel/run_d new file mode 100755 index 000000000..66eabf484 Binary files /dev/null and b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/bootloader/Linux-64bit-intel/run_d differ diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/__init__.py new file mode 100755 index 000000000..792d60054 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/__init__.py @@ -0,0 +1 @@ +# diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/api.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/api.py new file mode 100755 index 000000000..1e1995b0d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/api.py @@ -0,0 +1,1077 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +This module contains classes that are available for the .spec files. + +Spec file is generated by PyInstaller. The generated code from .spec file +is a way how PyInstaller does the dependency analysis and creates executable. +""" + +import os +import subprocess +import time +import shutil +from operator import itemgetter + +from PyInstaller import HOMEPATH, PLATFORM +from PyInstaller import log as logging +from PyInstaller.archive.writers import CArchiveWriter, ZlibArchiveWriter +from PyInstaller.building.datastruct import Target, _check_guts_eq, normalize_pyz_toc, normalize_toc +from PyInstaller.building.utils import ( + _check_guts_toc, _make_clean_directory, _rmtree, checkCache, get_code_object, strip_paths_in_code, compile_pymodule +) +from PyInstaller.building.splash import Splash # argument type validation in EXE +from PyInstaller.compat import is_cygwin, is_darwin, is_linux, is_win, strict_collect_mode +from PyInstaller.depend import bindepend +from PyInstaller.depend.analysis import get_bootstrap_modules +from PyInstaller.depend.utils import is_path_to_egg +import PyInstaller.utils.misc as miscutils + +logger = logging.getLogger(__name__) + +if is_win: + from PyInstaller.utils.win32 import (icon, versioninfo, winmanifest, winresource, winutils) + +if is_darwin: + import PyInstaller.utils.osx as osxutils + + +class PYZ(Target): + """ + Creates a ZlibArchive that contains all pure Python modules. + """ + def __init__(self, *tocs, **kwargs): + """ + tocs + One or more TOC (Table of Contents) lists, usually an `Analysis.pure` and an `Analysis.zipped_data`. + + If the passed TOC has an attribute `_code_cache`, it is expected to be a dictionary of module code objects + from ModuleGraph. + + kwargs + Possible keyword arguments: + + name + A filename for the .pyz. Normally not needed, as the generated name will do fine. + cipher + The block cipher that will be used to encrypt Python bytecode. + """ + + from PyInstaller.config import CONF + + super().__init__() + + name = kwargs.get('name', None) + cipher = kwargs.get('cipher', None) + + self.name = name + if name is None: + self.name = os.path.splitext(self.tocfilename)[0] + '.pyz' + + # PyInstaller bootstrapping modules. + bootstrap_dependencies = get_bootstrap_modules() + + # Bundle the crypto key. + self.cipher = cipher + if cipher: + key_file = ('pyimod00_crypto_key', os.path.join(CONF['workpath'], 'pyimod00_crypto_key.py'), 'PYMODULE') + # Insert the key as the first module in the list. The key module contains just variables and does not depend + # on other modules. + bootstrap_dependencies.insert(0, key_file) + + # Compile the python modules that are part of bootstrap dependencies, so that they can be collected into the + # CArchive and imported by the bootstrap script. + self.dependencies = [] + workpath = os.path.join(CONF['workpath'], 'localpycs') + for name, src_path, typecode in bootstrap_dependencies: + if typecode == 'PYMODULE': + # Compile pymodule and include the compiled .pyc file. + pyc_path = compile_pymodule(name, src_path, workpath, code_cache=None) + self.dependencies.append((name, pyc_path, typecode)) + else: + # Include as is (extensions). + self.dependencies.append((name, src_path, typecode)) + + # Merge input TOC(s) and their code object dictionaries (if available). Skip the bootstrap modules, which will + # be passed on to CArchive. + bootstrap_module_names = set(name for name, _, typecode in self.dependencies if typecode == 'PYMODULE') + self.toc = [] + self.code_dict = {} + for toc in tocs: + # Check if code cache association exists for the given TOC list + code_cache = CONF['code_cache'].get(id(toc)) + if code_cache is not None: + self.code_dict.update(code_cache) + + for entry in toc: + name, _, typecode = entry + # PYZ expects PYMODULE entries (python code objects) and DATA entries (data collected from zipped eggs). + assert typecode in ('PYMODULE', 'DATA'), f"Invalid entry passed to PYZ: {entry}!" + # Module required during bootstrap; skip to avoid collecting a duplicate. + if typecode == 'PYMODULE' and name in bootstrap_module_names: + continue + self.toc.append(entry) + + # Normalize TOC + self.toc = normalize_pyz_toc(self.toc) + + # Alphabetically sort the TOC to enable reproducible builds. + self.toc.sort() + + self.__postinit__() + + _GUTS = ( + # input parameters + ('name', _check_guts_eq), + ('toc', _check_guts_toc), + # no calculated/analysed values + ) + + def assemble(self): + logger.info("Building PYZ (ZlibArchive) %s", self.name) + + # Ensure code objects are available for all modules we are about to collect. + # NOTE: `self.toc` is already sorted by names. + archive_toc = [] + for entry in self.toc: + name, src_path, typecode = entry + if typecode == 'PYMODULE' and name not in self.code_dict: + # The code object is not available from the ModuleGraph's cache; re-create it. + try: + self.code_dict[name] = get_code_object(name, src_path) + except SyntaxError: + # The module was likely written for different Python version; exclude it + continue + archive_toc.append(entry) + + # Remove leading parts of paths in code objects. + self.code_dict = {name: strip_paths_in_code(code) for name, code in self.code_dict.items()} + + # Create the archive + ZlibArchiveWriter(self.name, archive_toc, code_dict=self.code_dict, cipher=self.cipher) + logger.info("Building PYZ (ZlibArchive) %s completed successfully.", self.name) + + +class PKG(Target): + """ + Creates a CArchive. CArchive is the data structure that is embedded into the executable. This data structure allows + to include various read-only data in a single-file deployment. + """ + xformdict = { + 'PYMODULE': 'm', + 'PYSOURCE': 's', + 'EXTENSION': 'b', + 'PYZ': 'z', + 'PKG': 'a', + 'DATA': 'x', + 'BINARY': 'b', + 'ZIPFILE': 'Z', + 'EXECUTABLE': 'b', + 'DEPENDENCY': 'd', + 'SPLASH': 'l' + } + + def __init__( + self, + toc, + name=None, + cdict=None, + exclude_binaries=False, + strip_binaries=False, + upx_binaries=False, + upx_exclude=None, + target_arch=None, + codesign_identity=None, + entitlements_file=None + ): + """ + toc + A TOC (Table of Contents) list. + name + An optional filename for the PKG. + cdict + Dictionary that specifies compression by typecode. For Example, PYZ is left uncompressed so that it + can be accessed inside the PKG. The default uses sensible values. If zlib is not available, no + compression is used. + exclude_binaries + If True, EXTENSIONs and BINARYs will be left out of the PKG, and forwarded to its container (usually + a COLLECT). + strip_binaries + If True, use 'strip' command to reduce the size of binary files. + upx_binaries + """ + super().__init__() + + self.toc = normalize_toc(toc) # Ensure guts contain normalized TOC + self.cdict = cdict + self.name = name + if name is None: + self.name = os.path.splitext(self.tocfilename)[0] + '.pkg' + self.exclude_binaries = exclude_binaries + self.strip_binaries = strip_binaries + self.upx_binaries = upx_binaries + self.upx_exclude = upx_exclude or [] + self.target_arch = target_arch + self.codesign_identity = codesign_identity + self.entitlements_file = entitlements_file + + # This dict tells PyInstaller what items embedded in the executable should be compressed. + if self.cdict is None: + self.cdict = { + 'EXTENSION': COMPRESSED, + 'DATA': COMPRESSED, + 'BINARY': COMPRESSED, + 'EXECUTABLE': COMPRESSED, + 'PYSOURCE': COMPRESSED, + 'PYMODULE': COMPRESSED, + 'SPLASH': COMPRESSED, + # Do not compress PYZ as a whole, as it contains individually-compressed modules. + 'PYZ': UNCOMPRESSED + } + + self.__postinit__() + + _GUTS = ( # input parameters + ('name', _check_guts_eq), + ('cdict', _check_guts_eq), + ('toc', _check_guts_toc), # list unchanged and no newer files + ('exclude_binaries', _check_guts_eq), + ('strip_binaries', _check_guts_eq), + ('upx_binaries', _check_guts_eq), + ('upx_exclude', _check_guts_eq), + ('target_arch', _check_guts_eq), + ('codesign_identity', _check_guts_eq), + ('entitlements_file', _check_guts_eq), + # no calculated/analysed values + ) + + def assemble(self): + logger.info("Building PKG (CArchive) %s", os.path.basename(self.name)) + + bootstrap_toc = [] # TOC containing bootstrap scripts and modules, which must not be sorted. + archive_toc = [] # TOC containing all other elements. Sorted to enable reproducible builds. + + for dest_name, src_name, typecode in self.toc: + # Ensure that the source file exists, if necessary. Skip the check for OPTION entries, where 'src_name' is + # None. Also skip DEPENDENCY entries due to special contents of 'dest_name' and/or 'src_name'. + if typecode not in ('OPTION', 'DEPENDENCY') and not os.path.exists(src_name): + # If file is contained within python egg, it will be added with the egg. + if not is_path_to_egg(src_name): + if strict_collect_mode: + raise ValueError(f"Non-existent resource {src_name}, meant to be collected as {dest_name}!") + else: + logger.warning( + "Ignoring non-existent resource %s, meant to be collected as %s", src_name, dest_name + ) + continue + if typecode in ('BINARY', 'EXTENSION'): + if self.exclude_binaries: + # This is onedir-specific codepath - the EXE and consequently PKG should not be passed the Analysis' + # `datas` and `binaries` TOCs (unless the user messes up the .spec file). However, EXTENSION entries + # might still slip in via `PYZ.dependencies`, which are merged by EXE into its TOC and passed on to + # PKG here. Such entries need to be passed to the parent container (the COLLECT) via + # `PKG.dependencies`. + # + # This codepath formerly performed such pass-through only for EXTENSION entries, but in order to + # keep code simple, we now also do it for BINARY entries. In a sane world, we do not expect to + # encounter them here; but if they do happen to pass through here and we pass them on, the + # container's TOC de-duplication should take care of them (same as with EXTENSION ones, really). + self.dependencies.append((dest_name, src_name, typecode)) + else: + # This is onefile-specific codepath. The binaries (both EXTENSION and BINARY entries) need to be + # processed using `checkCache` helper. + src_name = checkCache( + src_name, + strip=self.strip_binaries, + upx=self.upx_binaries, + upx_exclude=self.upx_exclude, + dist_nm=dest_name, + target_arch=self.target_arch, + codesign_identity=self.codesign_identity, + entitlements_file=self.entitlements_file, + strict_arch_validation=(typecode == 'EXTENSION'), + ) + archive_toc.append((dest_name, src_name, self.cdict.get(typecode, False), self.xformdict[typecode])) + elif typecode in ('DATA', 'ZIPFILE'): + # Same logic as above for BINARY and EXTENSION; if `exclude_binaries` is set, we are in onedir mode; + # we should exclude DATA (and ZIPFILE) entries and instead pass them on via PKG's `dependencies`. This + # prevents a onedir application from becoming a broken onefile one if user accidentally passes datas + # and binaries TOCs to EXE instead of COLLECT. + if self.exclude_binaries: + self.dependencies.append((dest_name, src_name, typecode)) + else: + archive_toc.append((dest_name, src_name, self.cdict.get(typecode, False), self.xformdict[typecode])) + elif typecode == 'OPTION': + archive_toc.append((dest_name, '', False, 'o')) + elif typecode in ('PYSOURCE', 'PYMODULE'): + # Collect python script and modules in a TOC that will not be sorted. + bootstrap_toc.append((dest_name, src_name, self.cdict.get(typecode, False), self.xformdict[typecode])) + else: + # PYZ, PKG, DEPENDENCY, SPLASH + archive_toc.append((dest_name, src_name, self.cdict.get(typecode, False), self.xformdict[typecode])) + + # Bootloader has to know the name of Python library. Pass python libname to CArchive. + pylib_name = os.path.basename(bindepend.get_python_library_path()) + + # Sort content alphabetically by type and name to enable reproducible builds. + archive_toc.sort(key=itemgetter(3, 0)) + # Do *not* sort modules and scripts, as their order is important. + # TODO: Think about having all modules first and then all scripts. + CArchiveWriter(self.name, bootstrap_toc + archive_toc, pylib_name=pylib_name) + + logger.info("Building PKG (CArchive) %s completed successfully.", os.path.basename(self.name)) + + +class EXE(Target): + """ + Creates the final executable of the frozen app. This bundles all necessary files together. + """ + def __init__(self, *args, **kwargs): + """ + args + One or more arguments that are either an instance of `Target` or an iterable representing TOC list. + kwargs + Possible keyword arguments: + + bootloader_ignore_signals + Non-Windows only. If True, the bootloader process will ignore all ignorable signals. If False (default), + it will forward all signals to the child process. Useful in situations where for example a supervisor + process signals both the bootloader and the child (e.g., via a process group) to avoid signalling the + child twice. + console + On Windows or Mac OS governs whether to use the console executable or the windowed executable. Always + True on Linux/Unix (always console executable - it does not matter there). + disable_windowed_traceback + Disable traceback dump of unhandled exception in windowed (noconsole) mode (Windows and macOS only), + and instead display a message that this feature is disabled. + debug + Setting to True gives you progress messages from the executable (for console=False there will be + annoying MessageBoxes on Windows). + name + The filename for the executable. On Windows suffix '.exe' is appended. + exclude_binaries + Forwarded to the PKG the EXE builds. + icon + Windows and Mac OS only. icon='myicon.ico' to use an icon file or icon='notepad.exe,0' to grab an icon + resource. Defaults to use PyInstaller's console or windowed icon. Use icon=`NONE` to not add any icon. + version + Windows only. version='myversion.txt'. Use grab_version.py to get a version resource from an executable + and then edit the output to create your own. (The syntax of version resources is so arcane that I would + not attempt to write one from scratch). + uac_admin + Windows only. Setting to True creates a Manifest with will request elevation upon application start. + uac_uiaccess + Windows only. Setting to True allows an elevated application to work with Remote Desktop. + embed_manifest + Windows only. Setting to True (the default) embeds the manifest into the executable. Setting to False + generates an external .exe.manifest file. Applicable only in onedir mode (exclude_binaries=True); in + onefile mode (exclude_binaries=False), the manifest is always embedded in the executable, regardless + of this option. + argv_emulation + macOS only. Enables argv emulation in macOS .app bundles (i.e., windowed bootloader). If enabled, the + initial open document/URL Apple Events are intercepted by bootloader and converted into sys.argv. + target_arch + macOS only. Used to explicitly specify the target architecture; either single-arch ('x86_64' or 'arm64') + or 'universal2'. Used in checks that the collected binaries contain the requires arch slice(s) and/or + to convert fat binaries into thin ones as necessary. If not specified (default), a single-arch build + corresponding to running architecture is assumed. + codesign_identity + macOS only. Use the provided identity to sign collected binaries and the generated executable. If + signing identity is not provided, ad-hoc signing is performed. + entitlements_file + macOS only. Optional path to entitlements file to use with code signing of collected binaries + (--entitlements option to codesign utility). + """ + from PyInstaller.config import CONF + + super().__init__() + + # Available options for EXE in .spec files. + self.exclude_binaries = kwargs.get('exclude_binaries', False) + self.bootloader_ignore_signals = kwargs.get('bootloader_ignore_signals', False) + self.console = kwargs.get('console', True) + self.disable_windowed_traceback = kwargs.get('disable_windowed_traceback', False) + self.debug = kwargs.get('debug', False) + self.name = kwargs.get('name', None) + self.icon = kwargs.get('icon', None) + self.versrsrc = kwargs.get('version', None) + self.manifest = kwargs.get('manifest', None) + self.embed_manifest = kwargs.get('embed_manifest', True) + self.resources = kwargs.get('resources', []) + self.strip = kwargs.get('strip', False) + self.upx_exclude = kwargs.get("upx_exclude", []) + self.runtime_tmpdir = kwargs.get('runtime_tmpdir', None) + # If ``append_pkg`` is false, the archive will not be appended to the exe, but copied beside it. + self.append_pkg = kwargs.get('append_pkg', True) + + # On Windows allows the exe to request admin privileges. + self.uac_admin = kwargs.get('uac_admin', False) + self.uac_uiaccess = kwargs.get('uac_uiaccess', False) + + # macOS argv emulation + self.argv_emulation = kwargs.get('argv_emulation', False) + + # Target architecture (macOS only) + self.target_arch = kwargs.get('target_arch', None) + if is_darwin: + if self.target_arch is None: + import platform + self.target_arch = platform.machine() + else: + assert self.target_arch in {'x86_64', 'arm64', 'universal2'}, \ + f"Unsupported target arch: {self.target_arch}" + logger.info("EXE target arch: %s", self.target_arch) + else: + self.target_arch = None # explicitly disable + + # Code signing identity (macOS only) + self.codesign_identity = kwargs.get('codesign_identity', None) + if is_darwin: + logger.info("Code signing identity: %s", self.codesign_identity) + else: + self.codesign_identity = None # explicitly disable + # Code signing entitlements + self.entitlements_file = kwargs.get('entitlements_file', None) + + # UPX needs to be both available and enabled for the target. + self.upx = CONF['upx_available'] and kwargs.get('upx', False) + + # Catch and clear options that are unsupported on specific platforms. + if self.versrsrc and not is_win: + logger.warning('Ignoring version information; supported only on Windows!') + self.versrsrc = None + if self.manifest and not is_win: + logger.warning('Ignoring manifest; supported only on Windows!') + self.manifest = None + if self.resources and not is_win: + logger.warning('Ignoring resources; supported only on Windows!') + self.resources = [] + if self.icon and not (is_win or is_darwin): + logger.warning('Ignoring icon; supported only on Windows and macOS!') + self.icon = None + + # Old .spec format included in 'name' the path where to put created app. New format includes only exename. + # + # Ignore fullpath in the 'name' and prepend DISTPATH or WORKPATH. + # DISTPATH - onefile + # WORKPATH - onedir + if self.exclude_binaries: + # onedir mode - create executable in WORKPATH. + self.name = os.path.join(CONF['workpath'], os.path.basename(self.name)) + else: + # onefile mode - create executable in DISTPATH. + self.name = os.path.join(CONF['distpath'], os.path.basename(self.name)) + + # Old .spec format included on Windows in 'name' .exe suffix. + if is_win or is_cygwin: + # Append .exe suffix if it is not already there. + if not self.name.endswith('.exe'): + self.name += '.exe' + base_name = os.path.splitext(os.path.basename(self.name))[0] + else: + base_name = os.path.basename(self.name) + # Create the CArchive PKG in WORKPATH. When instancing PKG(), set name so that guts check can test whether the + # file already exists. + self.pkgname = os.path.join(CONF['workpath'], base_name + '.pkg') + + self.toc = [] + + for arg in args: + # Valid arguments: PYZ object, Splash object, and TOC-list iterables + if isinstance(arg, (PYZ, Splash)): + # Add object as an entry to the TOC, and merge its dependencies TOC + if isinstance(arg, PYZ): + self.toc.append((os.path.basename(arg.name), arg.name, "PYZ")) + else: + self.toc.append((os.path.basename(arg.name), arg.name, "SPLASH")) + self.toc.extend(arg.dependencies) + elif miscutils.is_iterable(arg): + # TOC-like iterable + self.toc.extend(arg) + else: + raise TypeError(f"Invalid argument type for EXE: {type(arg)!r}") + + if self.runtime_tmpdir is not None: + self.toc.append(("pyi-runtime-tmpdir " + self.runtime_tmpdir, "", "OPTION")) + + if self.bootloader_ignore_signals: + # no value; presence means "true" + self.toc.append(("pyi-bootloader-ignore-signals", "", "OPTION")) + + if self.disable_windowed_traceback: + # no value; presence means "true" + self.toc.append(("pyi-disable-windowed-traceback", "", "OPTION")) + + if self.argv_emulation: + # no value; presence means "true" + self.toc.append(("pyi-macos-argv-emulation", "", "OPTION")) + + # If the icon path is relative, make it relative to the .spec file. + def makeabs(path): + if os.path.isabs(path): + return path + else: + return os.path.join(CONF['specpath'], path) + + if self.icon and self.icon != "NONE": + if isinstance(self.icon, list): + self.icon = [makeabs(ic) for ic in self.icon] + else: + self.icon = [makeabs(self.icon)] + + if is_win: + if not self.exclude_binaries: + # onefile mode forces embed_manifest=True + if not self.embed_manifest: + logger.warning("Ignoring embed_manifest=False setting in onefile mode!") + self.embed_manifest = True + if not self.icon: + # --icon not specified; use default from bootloader folder + if self.console: + ico = 'icon-console.ico' + else: + ico = 'icon-windowed.ico' + self.icon = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'bootloader', 'images', ico) + filename = os.path.join(CONF['workpath'], CONF['specnm'] + ".exe.manifest") + self.manifest = winmanifest.create_manifest( + filename, self.manifest, self.console, self.uac_admin, self.uac_uiaccess + ) + + manifest_filename = os.path.basename(self.name) + ".manifest" + + # If external manifest file is requested (supported only in onedir mode), add the file to the TOC in order + # for it to be collected as an external manifest file. Otherwise, the assembly pipeline will embed the + # manifest into the executable later on. + if not self.embed_manifest: + self.toc.append((manifest_filename, filename, 'BINARY')) + + if self.versrsrc: + if isinstance(self.versrsrc, versioninfo.VSVersionInfo): + # We were passed a valid versioninfo.VSVersionInfo structure + pass + elif isinstance(self.versrsrc, (str, bytes, os.PathLike)): + # File path; either absolute, or relative to the spec file + if not os.path.isabs(self.versrsrc): + self.versrsrc = os.path.join(CONF['specpath'], self.versrsrc) + logger.debug("Loading version info from file: %r", self.versrsrc) + self.versrsrc = versioninfo.load_version_info_from_text_file(self.versrsrc) + else: + raise TypeError(f"Unsupported type for version info argument: {type(self.versrsrc)!r}") + + # Normalize TOC + self.toc = normalize_toc(self.toc) + + self.pkg = PKG( + self.toc, + name=self.pkgname, + cdict=kwargs.get('cdict', None), + exclude_binaries=self.exclude_binaries, + strip_binaries=self.strip, + upx_binaries=self.upx, + upx_exclude=self.upx_exclude, + target_arch=self.target_arch, + codesign_identity=self.codesign_identity, + entitlements_file=self.entitlements_file + ) + self.dependencies = self.pkg.dependencies + + # Get the path of the bootloader and store it in a TOC, so it can be checked for being changed. + exe = self._bootloader_file('run', '.exe' if is_win or is_cygwin else '') + self.exefiles = [(os.path.basename(exe), exe, 'EXECUTABLE')] + + self.__postinit__() + + _GUTS = ( # input parameters + ('name', _check_guts_eq), + ('console', _check_guts_eq), + ('debug', _check_guts_eq), + ('exclude_binaries', _check_guts_eq), + ('icon', _check_guts_eq), + ('versrsrc', _check_guts_eq), + ('uac_admin', _check_guts_eq), + ('uac_uiaccess', _check_guts_eq), + ('manifest', _check_guts_eq), + ('embed_manifest', _check_guts_eq), + ('append_pkg', _check_guts_eq), + ('argv_emulation', _check_guts_eq), + ('target_arch', _check_guts_eq), + ('codesign_identity', _check_guts_eq), + ('entitlements_file', _check_guts_eq), + # for the case the directory ius shared between platforms: + ('pkgname', _check_guts_eq), + ('toc', _check_guts_eq), + ('resources', _check_guts_eq), + ('strip', _check_guts_eq), + ('upx', _check_guts_eq), + ('mtm', None), # checked below + # no calculated/analysed values + ('exefiles', _check_guts_toc), + ) + + def _check_guts(self, data, last_build): + if not os.path.exists(self.name): + logger.info("Rebuilding %s because %s missing", self.tocbasename, os.path.basename(self.name)) + return True + if not self.append_pkg and not os.path.exists(self.pkgname): + logger.info("Rebuilding because %s missing", os.path.basename(self.pkgname)) + return True + + if Target._check_guts(self, data, last_build): + return True + + mtm = data['mtm'] + if mtm != miscutils.mtime(self.name): + logger.info("Rebuilding %s because mtimes don't match", self.tocbasename) + return True + if mtm < miscutils.mtime(self.pkg.tocfilename): + logger.info("Rebuilding %s because pkg is more recent", self.tocbasename) + return True + + return False + + def _bootloader_file(self, exe, extension=None): + """ + Pick up the right bootloader file - debug, console, windowed. + """ + # Having console/windowed bootloader makes sense only on Windows and Mac OS. + if is_win or is_darwin: + if not self.console: + exe = exe + 'w' + # There are two types of bootloaders: + # run - release, no verbose messages in console. + # run_d - contains verbose messages in console. + if self.debug: + exe = exe + '_d' + if extension: + exe = exe + extension + bootloader_file = os.path.join(HOMEPATH, 'PyInstaller', 'bootloader', PLATFORM, exe) + logger.info('Bootloader %s' % bootloader_file) + return bootloader_file + + def assemble(self): + from PyInstaller.config import CONF + + # On Windows, we must never create a file with a .exe suffix that we then have to (re)write to (see #6467). + # Any intermediate/temporary file must have an alternative suffix. + build_name = self.name + '.notanexecutable' if is_win or is_cygwin else self.name + + logger.info("Building EXE from %s", self.tocbasename) + if os.path.exists(self.name): + if os.path.isdir(self.name): + _rmtree(self.name) # will prompt for confirmation if --noconfirm is not given + else: + os.remove(self.name) + if not os.path.exists(os.path.dirname(self.name)): + os.makedirs(os.path.dirname(self.name)) + exe = self.exefiles[0][1] # pathname of bootloader + if not os.path.exists(exe): + raise SystemExit(_MISSING_BOOTLOADER_ERRORMSG) + + # Step 1: copy the bootloader file, and perform any operations that need to be done prior to appending the PKG. + logger.info("Copying bootloader EXE to %s", build_name) + self._copyfile(exe, build_name) + os.chmod(build_name, 0o755) + + if is_win: + # First, remove all resources from the file. This ensures that no manifest is embedded, even if bootloader + # was compiled with a toolchain that forcibly embeds a default manifest (e.g., mingw toolchain from msys2). + winresource.RemoveAllResources(build_name) + # Embed icon. + if self.icon != "NONE": + logger.info("Copying icon to EXE") + icon.CopyIcons(build_name, self.icon) + # Embed version info. + if self.versrsrc: + logger.info("Copying version information to EXE") + versioninfo.write_version_info_to_executable(build_name, self.versrsrc) + # Embed other resources. + logger.info("Copying %d resources to EXE", len(self.resources)) + for res in self.resources: + res = res.split(",") + for i in range(1, len(res)): + try: + res[i] = int(res[i]) + except ValueError: + pass + resfile = res[0] + if not os.path.isabs(resfile): + resfile = os.path.join(CONF['specpath'], resfile) + restype = resname = reslang = None + if len(res) > 1: + restype = res[1] + if len(res) > 2: + resname = res[2] + if len(res) > 3: + reslang = res[3] + try: + winresource.UpdateResourcesFromResFile( + build_name, resfile, [restype or "*"], [resname or "*"], [reslang or "*"] + ) + except winresource.pywintypes.error as exc: + if exc.args[0] != winresource.ERROR_BAD_EXE_FORMAT: + logger.error( + "Error while updating resources in %s from resource file %s!", + build_name, + resfile, + exc_info=1 + ) + continue + + # Handle the case where the file contains no resources, and is intended as a single resource to be + # added to the exe. + if not restype or not resname: + logger.error("Resource type and/or name not specified!") + continue + if "*" in (restype, resname): + logger.error( + "No wildcards allowed for resource type and name when the source file does not contain " + "any resources!" + ) + continue + try: + winresource.UpdateResourcesFromDataFile(build_name, resfile, restype, [resname], [reslang or 0]) + except winresource.pywintypes.error: + logger.error( + "Error while updating resource %s %s in %s from data file %s!", + restype, + resname, + build_name, + resfile, + exc_info=1 + ) + # Embed the manifest into the executable. + if self.embed_manifest: + logger.info("Embedding manifest in EXE") + self.manifest.update_resources(build_name, [1]) + elif is_darwin: + # Convert bootloader to the target arch + logger.info("Converting EXE to target arch (%s)", self.target_arch) + osxutils.binary_to_target_arch(build_name, self.target_arch, display_name='Bootloader EXE') + + # Step 2: append the PKG, if necessary + if self.append_pkg: + append_file = self.pkg.name # Append PKG + append_type = 'PKG archive' # For debug messages + else: + # In onefile mode, copy the stand-alone PKG next to the executable. In onedir, this will be done by the + # COLLECT() target. + if not self.exclude_binaries: + pkg_dst = os.path.join(os.path.dirname(build_name), os.path.basename(self.pkgname)) + logger.info("Copying stand-alone PKG archive from %s to %s", self.pkg.name, pkg_dst) + self._copyfile(self.pkg.name, pkg_dst) + else: + logger.info("Stand-alone PKG archive will be handled by COLLECT") + + # The bootloader requires package side-loading to be explicitly enabled, which is done by embedding custom + # signature to the executable. This extra signature ensures that the sideload-enabled executable is at least + # slightly different from the stock bootloader executables, which should prevent antivirus programs from + # flagging our stock bootloaders due to sideload-enabled applications in the wild. + + # Write to temporary file + pkgsig_file = self.pkg.name + '.sig' + with open(pkgsig_file, "wb") as f: + # 8-byte MAGIC; slightly changed PKG MAGIC pattern + f.write(b'MEI\015\013\012\013\016') + + append_file = pkgsig_file # Append PKG-SIG + append_type = 'PKG sideload signature' # For debug messages + + if is_linux: + # Linux: append data into custom ELF section using objcopy. + logger.info("Appending %s to custom ELF section in EXE", append_type) + cmd = ['objcopy', '--add-section', f'pydata={append_file}', build_name] + p = subprocess.run(cmd, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, universal_newlines=True) + if p.returncode: + raise SystemError(f"objcopy Failure: {p.returncode} {p.stdout}") + + elif is_darwin: + # macOS: remove signature, append data, and fix-up headers so that the appended data appears to be part of + # the executable (which is required by strict validation during code-signing). + + # Strip signatures from all arch slices. Strictly speaking, we need to remove signature (if present) from + # the last slice, because we will be appending data to it. When building universal2 bootloaders natively on + # macOS, only arm64 slices have a (dummy) signature. However, when cross-compiling with osxcross, we seem to + # get dummy signatures on both x86_64 and arm64 slices. While the former should not have any impact, it does + # seem to cause issues with further binary signing using real identity. Therefore, we remove all signatures + # and re-sign the binary using dummy signature once the data is appended. + logger.info("Removing signature(s) from EXE") + osxutils.remove_signature_from_binary(build_name) + + # Append the data + logger.info("Appending %s to EXE", append_type) + with open(build_name, 'ab') as outf: + with open(append_file, 'rb') as inf: + shutil.copyfileobj(inf, outf, length=64 * 1024) + + # Fix Mach-O headers + logger.info("Fixing EXE headers for code signing") + osxutils.fix_exe_for_code_signing(build_name) + else: + # Fall back to just appending data at the end of the file + logger.info("Appending %s to EXE", append_type) + with open(build_name, 'ab') as outf: + with open(append_file, 'rb') as inf: + shutil.copyfileobj(inf, outf, length=64 * 1024) + + # Step 3: post-processing + if is_win: + # Set checksum to appease antiviral software. Also set build timestamp to current time to increase entropy + # (but honor SOURCE_DATE_EPOCH environment variable for reproducible builds). + logger.info("Fixing EXE headers") + build_timestamp = int(os.environ.get('SOURCE_DATE_EPOCH', time.time())) + winutils.set_exe_build_timestamp(build_name, build_timestamp) + winutils.update_exe_pe_checksum(build_name) + elif is_darwin: + # If the version of macOS SDK used to build bootloader exceeds that of macOS SDK used to built Python + # library (and, by extension, bundled Tcl/Tk libraries), force the version declared by the frozen executable + # to match that of the Python library. + # Having macOS attempt to enable new features (based on SDK version) for frozen application has no benefit + # if the Python library does not support them as well. + # On the other hand, there seem to be UI issues in tkinter due to failed or partial enablement of dark mode + # (i.e., the bootloader executable being built against SDK 10.14 or later, which causes macOS to enable dark + # mode, and Tk libraries being built against an earlier SDK version that does not support the dark mode). + # With python.org Intel macOS installers, this manifests as black Tk windows and UI elements (see issue + # #5827), while in Anaconda python, it may result in white text on bright background. + pylib_version = osxutils.get_macos_sdk_version(bindepend.get_python_library_path()) + exe_version = osxutils.get_macos_sdk_version(build_name) + if pylib_version < exe_version: + logger.info( + "Rewriting the executable's macOS SDK version (%d.%d.%d) to match the SDK version of the Python " + "library (%d.%d.%d) in order to avoid inconsistent behavior and potential UI issues in the " + "frozen application.", *exe_version, *pylib_version + ) + osxutils.set_macos_sdk_version(build_name, *pylib_version) + + # Re-sign the binary (either ad-hoc or using real identity, if provided). + logger.info("Re-signing the EXE") + osxutils.sign_binary(build_name, self.codesign_identity, self.entitlements_file) + + # Ensure executable flag is set + os.chmod(build_name, 0o755) + # Get mtime for storing into the guts + self.mtm = miscutils.mtime(build_name) + if build_name != self.name: + os.rename(build_name, self.name) + logger.info("Building EXE from %s completed successfully.", self.tocbasename) + + def _copyfile(self, infile, outfile): + with open(infile, 'rb') as infh: + with open(outfile, 'wb') as outfh: + shutil.copyfileobj(infh, outfh, length=64 * 1024) + + +class COLLECT(Target): + """ + In one-dir mode creates the output folder with all necessary files. + """ + def __init__(self, *args, **kwargs): + """ + args + One or more arguments that are either an instance of `Target` or an iterable representing TOC list. + kwargs + Possible keyword arguments: + + name + The name of the directory to be built. + """ + from PyInstaller.config import CONF + + super().__init__() + + self.strip_binaries = kwargs.get('strip', False) + self.upx_exclude = kwargs.get("upx_exclude", []) + self.console = True + self.target_arch = None + self.codesign_identity = None + self.entitlements_file = None + + # UPX needs to be both available and enabled for the taget. + self.upx_binaries = CONF['upx_available'] and kwargs.get('upx', False) + + # The `name` should be the output directory name, without the parent path (the directory is created in the + # DISTPATH). Old .spec formats included parent path, so strip it away. + self.name = os.path.join(CONF['distpath'], os.path.basename(kwargs.get('name'))) + + self.toc = [] + for arg in args: + # Valid arguments: EXE object and TOC-like iterables + if isinstance(arg, EXE): + # Add EXE as an entry to the TOC, and merge its dependencies TOC + self.toc.append((os.path.basename(arg.name), arg.name, 'EXECUTABLE')) + self.toc.extend(arg.dependencies) + # Inherit settings + self.console = arg.console + self.target_arch = arg.target_arch + self.codesign_identity = arg.codesign_identity + self.entitlements_file = arg.entitlements_file + # Search for the executable's external manifest, and collect it if available + for dest_name, src_name, typecode in arg.toc: + if dest_name == os.path.basename(arg.name) + ".manifest": + self.toc.append((dest_name, src_name, typecode)) + # If PKG is not appended to the executable, we need to collect it. + if not arg.append_pkg: + self.toc.append((os.path.basename(arg.pkgname), arg.pkgname, 'PKG')) + elif miscutils.is_iterable(arg): + # TOC-like iterable + self.toc.extend(arg) + else: + raise TypeError(f"Invalid argument type for COLLECT: {type(arg)!r}") + + # Normalize TOC + self.toc = normalize_toc(self.toc) + + self.__postinit__() + + _GUTS = ( + # COLLECT always builds, we just want the TOC to be written out. + ('toc', None), + ) + + def _check_guts(self, data, last_build): + # COLLECT always needs to be executed, in order to clean the output directory. + return True + + def assemble(self): + _make_clean_directory(self.name) + logger.info("Building COLLECT %s", self.tocbasename) + for dest_name, src_name, typecode in self.toc: + # Ensure that the source file exists, if necessary. Skip the check for DEPENDENCY entries due to special + # contents of 'dest_name' and/or 'src_name'. + if typecode != 'DEPENDENCY' and not os.path.exists(src_name): + # If file is contained within python egg, it will be added with the egg. + if not is_path_to_egg(src_name): + if strict_collect_mode: + raise ValueError(f"Non-existent resource {src_name}, meant to be collected as {dest_name}!") + else: + logger.warning( + "Ignoring non-existent resource %s, meant to be collected as %s", src_name, dest_name + ) + continue + # Disallow collection outside of the dist directory. + if os.pardir in os.path.normpath(dest_name).split(os.sep) or os.path.isabs(dest_name): + raise SystemExit( + 'Security-Alert: attempting to store file outside of the dist directory: %r. Aborting.' % dest_name + ) + # Create parent directory structure, if necessary + dest_path = os.path.join(self.name, dest_name) # Absolute destination path + dest_dir = os.path.dirname(dest_path) + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) + elif not os.path.isdir(dest_dir): + raise SystemExit( + f"Pyinstaller needs to create a directory at {dest_dir!r}, " + "but there already exists a file at that path!" + ) + if typecode in ('EXTENSION', 'BINARY'): + src_name = checkCache( + src_name, + strip=self.strip_binaries, + upx=self.upx_binaries, + upx_exclude=self.upx_exclude, + dist_nm=dest_name, + target_arch=self.target_arch, + codesign_identity=self.codesign_identity, + entitlements_file=self.entitlements_file, + strict_arch_validation=(typecode == 'EXTENSION'), + ) + if typecode != 'DEPENDENCY': + # At this point, `src_name` should be a valid file. + if not os.path.isfile(src_name): + raise ValueError(f"Resource {src_name!r} is not a valid file!") + # If strict collection mode is enabled, the destination should not exist yet. + if strict_collect_mode and os.path.exists(dest_path): + raise ValueError( + f"Attempting to collect a duplicated file into COLLECT: {dest_name} (type: {typecode})" + ) + shutil.copy2(src_name, dest_path) # Use copy2 to (attempt to) preserve metadata + if typecode in ('EXTENSION', 'BINARY'): + os.chmod(dest_path, 0o755) + logger.info("Building COLLECT %s completed successfully.", self.tocbasename) + + +class MERGE: + """ + Given Analysis objects for multiple executables, replace occurrences of data and binary files with references to the + first executable in which they occur. The actual data and binary files are then collected only once, thereby + reducing the disk space used by multiple executables. Every executable (even onedir ones!) obtained from a + MERGE-processed Analysis gains onefile semantics, because it needs to extract its referenced dependencies from other + executables into temporary directory before they can run. + """ + def __init__(self, *args): + """ + args + Dependencies as a list of (analysis, identifier, path_to_exe) tuples. `analysis` is an instance of + `Analysis`, `identifier` is the basename of the entry-point script (without .py suffix), and `path_to_exe` + is path to the corresponding executable, relative to the `dist` directory (without .exe suffix in the + filename component). For onefile executables, `path_to_exe` is usually just executable's base name + (e.g., `myexecutable`). For onedir executables, `path_to_exe` usually comprises both the application's + directory name and executable name (e.g., `myapp/myexecutable`). + """ + self._dependencies = {} + + # Process all given (analysis, identifier, path_to_exe) tuples + for analysis, identifier, path_to_exe in args: + # Process analysis.binaries and analysis.datas TOCs. self._process_toc() call returns two TOCs; the first + # contains entries that remain within this analysis, while the second contains entries that reference + # an entry in another executable. + binaries, binaries_refs = self._process_toc(analysis.binaries, path_to_exe) + datas, datas_refs = self._process_toc(analysis.datas, path_to_exe) + # Update `analysis.binaries`, `analysis.datas`, and `analysis.dependencies`. + # The entries that are found in preceding executable(s) are removed from `binaries` and `datas`, and their + # DEPENDENCY entry counterparts are added to `dependencies`. We cannot simply update the entries in + # `binaries` and `datas`, because at least in theory, we need to support both onefile and onedir mode. And + # while in onefile, `a.datas`, `a.binaries`, and `a.dependencies` are passed to `EXE` (and its `PKG`), with + # onedir, `a.datas` and `a.binaries` need to be passed to `COLLECT` (as they were before the MERGE), while + # `a.dependencies` needs to be passed to `EXE`. This split requires DEPENDENCY entries to be in a separate + # TOC. + analysis.binaries = normalize_toc(binaries) + analysis.datas = normalize_toc(datas) + analysis.dependencies += binaries_refs + datas_refs + + def _process_toc(self, toc, path_to_exe): + # NOTE: unfortunately, these need to keep two separate lists. See the comment in the calling code on why this + # is so. + toc_keep = [] + toc_refs = [] + for entry in toc: + dest_name, src_name, typecode = entry + if src_name not in self._dependencies: + logger.debug("Adding dependency %s located in %s", src_name, path_to_exe) + self._dependencies[src_name] = path_to_exe + # Add entry to list of kept TOC entries + toc_keep.append(entry) + else: + # Construct relative dependency path; i.e., the relative path from this executable (or rather, its + # parent directory) to the executable that contains the dependency. + dep_path = os.path.relpath(self._dependencies[src_name], os.path.dirname(path_to_exe)) + # Ignore references that point to the origin package. This can happen if the same resource is listed + # multiple times in TOCs (e.g., once as binary and once as data). + if dep_path.endswith(path_to_exe): + logger.debug( + "Ignoring self-reference of %s for %s, located in %s - duplicated TOC entry?", src_name, + path_to_exe, dep_path + ) + # The entry is a duplicate, and should be ignored (i.e., do not add it to either of output TOCs). + continue + logger.debug("Referencing %s to be a dependency for %s, located in %s", src_name, path_to_exe, dep_path) + # Create new DEPENDENCY entry; under destination path (first element), we store the original destination + # path, while source path contains the relative reference path. + toc_refs.append((dest_name, dep_path, "DEPENDENCY")) + + return toc_keep, toc_refs + + +UNCOMPRESSED = False +COMPRESSED = True + +_MISSING_BOOTLOADER_ERRORMSG = """Fatal error: PyInstaller does not include a pre-compiled bootloader for your +platform. For more details and instructions how to build the bootloader see +""" diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/build_main.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/build_main.py new file mode 100755 index 000000000..8e4e24768 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/build_main.py @@ -0,0 +1,1019 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Build packages using spec files. + +NOTE: All global variables, classes and imported modules create API for .spec files. +""" + +import glob +import os +import pprint +import shutil +import enum + +import sys + +from PyInstaller import DEFAULT_DISTPATH, DEFAULT_WORKPATH, HOMEPATH, compat +from PyInstaller import log as logging +from PyInstaller.archive import pyz_crypto +from PyInstaller.building.api import COLLECT, EXE, MERGE, PYZ +from PyInstaller.building.datastruct import TOC, Target, Tree, _check_guts_eq, normalize_toc, normalize_pyz_toc +from PyInstaller.building.osx import BUNDLE +from PyInstaller.building.splash import Splash +from PyInstaller.building.toc_conversion import DependencyProcessor +from PyInstaller.building.utils import ( + _check_guts_toc, _check_guts_toc_mtime, _should_include_system_binary, format_binaries_and_datas, compile_pymodule, + add_suffix_to_extension, postprocess_binaries_toc_pywin32, postprocess_binaries_toc_pywin32_anaconda +) +from PyInstaller.compat import PYDYLIB_NAMES, is_win, is_conda +from PyInstaller.depend import bindepend +from PyInstaller.depend.analysis import initialize_modgraph +from PyInstaller.depend.utils import create_py3_base_library, scan_code_for_ctypes +from PyInstaller import isolated +from PyInstaller.utils.misc import absnormpath, get_path_to_toplevel_modules, get_unicode_modules, mtime +from PyInstaller.utils.hooks.gi import compile_glib_schema_files + +if is_win: + from PyInstaller.utils.win32 import winmanifest + +logger = logging.getLogger(__name__) + +STRINGTYPE = type('') +TUPLETYPE = type((None,)) + +rthooks = {} + +# Place where the loader modules and initialization scripts live. +_init_code_path = os.path.join(HOMEPATH, 'PyInstaller', 'loader') + +IMPORT_TYPES = [ + 'top-level', 'conditional', 'delayed', 'delayed, conditional', 'optional', 'conditional, optional', + 'delayed, optional', 'delayed, conditional, optional' +] + +WARNFILE_HEADER = """\ + +This file lists modules PyInstaller was not able to find. This does not +necessarily mean this module is required for running your program. Python and +Python 3rd-party packages include a lot of conditional or optional modules. For +example the module 'ntpath' only exists on Windows, whereas the module +'posixpath' only exists on Posix systems. + +Types if import: +* top-level: imported at the top-level - look at these first +* conditional: imported within an if-statement +* delayed: imported within a function +* optional: imported within a try-except-statement + +IMPORTANT: Do NOT post this list to the issue-tracker. Use it as a basis for + tracking down the missing module yourself. Thanks! + +""" + + +@isolated.decorate +def discover_hook_directories(): + """ + Discover hook directories via pkg_resources and pyinstaller40 entry points. Perform the discovery in a subprocess + to avoid importing the package(s) in the main process. + + :return: list of discovered hook directories. + """ + + import sys # noqa: F401 + from traceback import format_exception_only + import pkg_resources + from PyInstaller.log import logger + + entry_points = pkg_resources.iter_entry_points('pyinstaller40', 'hook-dirs') + # Ensure that pyinstaller_hooks_contrib comes last so that hooks from packages providing their own take priority. + entry_points = sorted(entry_points, key=lambda x: x.module_name == "_pyinstaller_hooks_contrib.hooks") + + hook_directories = [] + for entry_point in entry_points: + try: + hook_directories.extend(entry_point.load()()) + except Exception as e: + msg = "".join(format_exception_only(type(e), e)).strip() + logger.warning("discover_hook_directories: Failed to process hook entry point '%s': %s", entry_point, msg) + + logger.debug("discover_hook_directories: Hook directories: %s", hook_directories) + + return hook_directories + + +# NOTE: this helper is called via isolated.call() in Analysis.assemble(). We cannot use @isolated.decorate here, because +# one of the tests (test_regression::test_issue_5131) needs to be able to monkey-patch it, in order to override the +# bindepend.getImports() in the isolated subprocess (!) with its own implementation... +def find_binary_dependencies(binaries, binding_redirects, import_packages): + """ + Find dynamic dependencies (linked shared libraries) for the provided list of binaries. + + Before scanning the binaries, the function imports the packages from provided list of packages to import, to ensure + that library search paths are properly set up (i.e., if a package sets up search paths when imported). Therefore, + this function *must* always be called in an isolated subprocess to avoid import leaks! + + binaries + List of binaries to scan for dynamic dependencies. + binding_redirects + List of assembly binding redirects. + import_packages + List of packages to import prior to scanning binaries. + + :return: expanded list of binaries and then dependencies. + """ + import os + + from PyInstaller.depend import bindepend + from PyInstaller.building.build_main import logger + from PyInstaller import compat + + # Extra library search paths (used on Windows to resolve DLL paths). + # + # Always search `sys.base_prefix`, and search it first. This ensures that we resolve the correct version of + # `python3X.dll` and `python3.dll` (a PEP-0384 stable ABI stub that forwards symbols to the fully versioned + # `python3X.dll`), regardless of other python installations that might be present in the PATH. + extra_libdirs = [] + if compat.is_win: + extra_libdirs.append(compat.base_prefix) + + # On Windows, packages' initialization code might register additional DLL search paths, either by modifying the + # `PATH` environment variable, or (on pythonn >= 3.8) by calling `os.add_dll_directory`. Therefore, we import + # all collected packages, and track changes made to the environment. + if compat.is_win: + # Track changes made via `os.add_dll_directory`. + if compat.is_py38: + added_dll_directories = [] + _orig_add_dll_directory = os.add_dll_directory + + def _pyi_add_dll_directory(path): + added_dll_directories.append(path) + return _orig_add_dll_directory(path) + + os.add_dll_directory = _pyi_add_dll_directory + + # Import collected packages to set up environment. + for package in import_packages: + try: + __import__(package) + except Exception: + pass + + # Process extra search paths... + # Directories added via os.add_dll_directory() calls. + if compat.is_py38: + logger.info("Extra DLL search directories (AddDllDirectory): %r", added_dll_directories) + extra_libdirs += added_dll_directories + + # Restore original function + os.add_dll_directory = _orig_add_dll_directory + + # Directories set via PATH environment variable. + # NOTE: PATH might contain empty entries that need to be filtered out. + path_directories = [directory for directory in os.environ.get("PATH", '').split(os.pathsep) if directory] + logger.info("Extra DLL search directories (PATH): %r", path_directories) + extra_libdirs += path_directories + + # Search for dependencies of the given binaries + return bindepend.Dependencies(binaries, redirects=binding_redirects, xtrapath=extra_libdirs) + + +class _ModuleCollectionMode(enum.IntFlag): + """ + Module collection mode flags. + """ + PYZ = enum.auto() # Collect byte-compiled .pyc into PYZ archive + PYC = enum.auto() # Collect byte-compiled .pyc as external data file + PY = enum.auto() # Collect source .py file as external data file + + +_MODULE_COLLECTION_MODES = { + "pyz": _ModuleCollectionMode.PYZ, + "pyc": _ModuleCollectionMode.PYC, + "py": _ModuleCollectionMode.PY, + "pyz+py": _ModuleCollectionMode.PYZ | _ModuleCollectionMode.PY, + "py+pyz": _ModuleCollectionMode.PYZ | _ModuleCollectionMode.PY, +} + + +def _get_module_collection_mode(mode_dict, name, noarchive=False): + """ + Determine the module/package collection mode for the given module name, based on the provided collection + mode settings dictionary. + """ + # Default mode: collect into PYZ, unless noarchive is enabled. In that case, collect as pyc. + mode_flags = _ModuleCollectionMode.PYC if noarchive else _ModuleCollectionMode.PYZ + + # If we have no collection mode settings, end here and now. + if not mode_dict: + return mode_flags + + # Search the parent modules/packages in top-down fashion, and take the last given setting. This ensures that + # a setting given for the top-level package is recursively propagated to all its subpackages and submodules, + # but also allows individual sub-modules to override the setting again. + mode = 'pyz' + + name_parts = name.split('.') + for i in range(len(name_parts)): + modlevel = ".".join(name_parts[:i + 1]) + modlevel_mode = mode_dict.get(modlevel, None) + if modlevel_mode is not None: + mode = modlevel_mode + + # Convert mode string to _ModuleCollectionMode flags + try: + mode_flags = _MODULE_COLLECTION_MODES[mode] + except KeyError: + raise ValueError(f"Unknown module collection mode for {name!r}: {mode!r}!") + + # noarchive flag being set means that we need to change _ModuleCollectionMode.PYZ into _ModuleCollectionMode.PYC + if noarchive and _ModuleCollectionMode.PYZ in mode_flags: + mode_flags ^= _ModuleCollectionMode.PYZ + mode_flags |= _ModuleCollectionMode.PYC + + return mode_flags + + +class Analysis(Target): + """ + Class that performs analysis of the user's main Python scripts. + + An Analysis has five outputs, all TOC (Table of lists Contents) accessed as attributes of the analysis. + + scripts + The scripts you gave Analysis as input, with any runtime hook scripts prepended. + pure + The pure Python modules. + binaries + The extensionmodules and their dependencies. The secondary dependencies are filtered. On Windows files from + C:\\Windows are excluded by default. On Linux/Unix only system libraries from /lib or /usr/lib are excluded. + datas + Data-file dependencies. These are data-file that are found to be needed by modules. They can be anything: + plugins, font files, images, translations, etc. + zipfiles + The zipfiles dependencies (usually .egg files). + """ + _old_scripts = { + absnormpath(os.path.join(HOMEPATH, "support", "_mountzlib.py")), + absnormpath(os.path.join(HOMEPATH, "support", "useUnicode.py")), + absnormpath(os.path.join(HOMEPATH, "support", "useTK.py")), + absnormpath(os.path.join(HOMEPATH, "support", "unpackTK.py")), + absnormpath(os.path.join(HOMEPATH, "support", "removeTK.py")) + } + + def __init__( + self, + scripts, + pathex=None, + binaries=None, + datas=None, + hiddenimports=None, + hookspath=None, + hooksconfig=None, + excludes=None, + runtime_hooks=None, + cipher=None, + win_no_prefer_redirects=False, + win_private_assemblies=False, + noarchive=False, + module_collection_mode=None, + ): + """ + scripts + A list of scripts specified as file names. + pathex + An optional list of paths to be searched before sys.path. + binaries + An optional list of additional binaries (dlls, etc.) to include. + datas + An optional list of additional data files to include. + hiddenimport + An optional list of additional (hidden) modules to include. + hookspath + An optional list of additional paths to search for hooks. (hook-modules). + hooksconfig + An optional dict of config settings for hooks. (hook-modules). + excludes + An optional list of module or package names (their Python names, not path names) that will be + ignored (as though they were not found). + runtime_hooks + An optional list of scripts to use as users' runtime hooks. Specified as file names. + cipher + Add optional instance of the pyz_crypto.PyiBlockCipher class (with a provided key). + win_no_prefer_redirects + If True, prefer not to follow version redirects when searching for Windows SxS Assemblies. + win_private_assemblies + If True, change all bundled Windows SxS Assemblies into Private Assemblies to enforce assembly versions. + noarchive + If True, do not place source files in a archive, but keep them as individual files. + module_collection_mode + An optional dict of package/module names and collection mode strings. Valid collection mode strings: + 'pyz' (default), 'pyc', 'py', 'pyz+py' (or 'py+pyz') + """ + super().__init__() + from PyInstaller.config import CONF + + self.inputs = [] + spec_dir = os.path.dirname(CONF['spec']) + for script in scripts: + # If path is relative, it is relative to the location of .spec file. + if not os.path.isabs(script): + script = os.path.join(spec_dir, script) + if absnormpath(script) in self._old_scripts: + logger.warning('Ignoring obsolete auto-added script %s', script) + continue + # Normalize script path. + script = os.path.normpath(script) + if not os.path.exists(script): + raise SystemExit("script '%s' not found" % script) + self.inputs.append(script) + + # Django hook requires this variable to find the script manage.py. + CONF['main_script'] = self.inputs[0] + + self.pathex = self._extend_pathex(pathex, self.inputs) + # Set global config variable 'pathex' to make it available for PyInstaller.utils.hooks and import hooks. Path + # extensions for module search. + CONF['pathex'] = self.pathex + # Extend sys.path so PyInstaller could find all necessary modules. + logger.info('Extending PYTHONPATH with paths\n' + pprint.pformat(self.pathex)) + sys.path.extend(self.pathex) + + # If pkg_resources has already been imported, force update of its working set to account for changes made to + # sys.path. Otherwise, distribution data in the added path(s) may not be discovered. + if 'pkg_resources' in sys.modules: + # See https://github.com/pypa/setuptools/issues/373 + import pkg_resources + if hasattr(pkg_resources, '_initialize_master_working_set'): + pkg_resources._initialize_master_working_set() + + # Set global variable to hold assembly binding redirects + CONF['binding_redirects'] = [] + + self.hiddenimports = hiddenimports or [] + # Include modules detected when parsing options, like 'codecs' and encodings. + self.hiddenimports.extend(CONF['hiddenimports']) + + self.hookspath = [] + # Append directories in `hookspath` (`--additional-hooks-dir`) to take precedence over those from the entry + # points. + if hookspath: + self.hookspath.extend(hookspath) + + # Add hook directories from PyInstaller entry points. + self.hookspath += discover_hook_directories() + + self.hooksconfig = {} + if hooksconfig: + self.hooksconfig.update(hooksconfig) + + # Custom runtime hook files that should be included and started before any existing PyInstaller runtime hooks. + self.custom_runtime_hooks = runtime_hooks or [] + + if cipher: + logger.info('Will encrypt Python bytecode with provided cipher key') + # Create a Python module which contains the decryption key which will be used at runtime by + # pyi_crypto.PyiBlockCipher. + pyi_crypto_key_path = os.path.join(CONF['workpath'], 'pyimod00_crypto_key.py') + with open(pyi_crypto_key_path, 'w', encoding='utf-8') as f: + f.write('# -*- coding: utf-8 -*-\nkey = %r\n' % cipher.key) + self.hiddenimports.append('tinyaes') + + self._input_binaries = [] + self._input_datas = [] + + self.excludes = excludes or [] + self.scripts = [] + self.pure = [] + self.binaries = [] + self.zipfiles = [] + self.zipped_data = [] + self.datas = [] + self.dependencies = [] + self.binding_redirects = CONF['binding_redirects'] = [] + self.win_no_prefer_redirects = win_no_prefer_redirects + self.win_private_assemblies = win_private_assemblies + self._python_version = sys.version + self.noarchive = noarchive + self.module_collection_mode = module_collection_mode or {} + + # Expand the `binaries` and `datas` lists specified in the .spec file, and ensure that the lists are normalized + # and sorted before guts comparison. + # + # While we use these lists to initialize `Analysis.binaries` and `Analysis.datas`, at this point, we need to + # store them in separate variables, which undergo *full* guts comparison (`_check_guts_toc`) as opposed to + # just mtime-based comparison (`_check_guts_toc_mtime`). Changes to these initial list *must* trigger a rebuild + # (and due to the way things work, a re-analysis), otherwise user might end up with a cached build that fails to + # reflect the changes. + if binaries: + logger.info("Appending 'binaries' from .spec") + self._input_binaries = [(dest_name, src_name, 'BINARY') + for dest_name, src_name in format_binaries_and_datas(binaries, workingdir=spec_dir)] + self._input_binaries = sorted(normalize_toc(self._input_binaries)) + + if datas: + logger.info("Appending 'datas' from .spec") + self._input_datas = [(dest_name, src_name, 'DATA') + for dest_name, src_name in format_binaries_and_datas(datas, workingdir=spec_dir)] + self._input_datas = sorted(normalize_toc(self._input_datas)) + + self.__postinit__() + + _GUTS = ( # input parameters + ('inputs', _check_guts_eq), # parameter `scripts` + ('pathex', _check_guts_eq), + ('hiddenimports', _check_guts_eq), + ('hookspath', _check_guts_eq), + ('hooksconfig', _check_guts_eq), + ('excludes', _check_guts_eq), + ('custom_runtime_hooks', _check_guts_eq), + ('win_no_prefer_redirects', _check_guts_eq), + ('win_private_assemblies', _check_guts_eq), + ('noarchive', _check_guts_eq), + ('module_collection_mode', _check_guts_eq), + + ('_input_binaries', _check_guts_toc), + ('_input_datas', _check_guts_toc), + + # 'cipher': no need to check as it is implied by an additional hidden import + + # calculated/analysed values + ('_python_version', _check_guts_eq), + ('scripts', _check_guts_toc_mtime), + ('pure', _check_guts_toc_mtime), + ('binaries', _check_guts_toc_mtime), + ('zipfiles', _check_guts_toc_mtime), + ('zipped_data', None), # TODO check this, too + ('datas', _check_guts_toc_mtime), + # TODO: Need to add "dependencies"? + + # cached binding redirects - loaded into CONF for PYZ/COLLECT to find. + ('binding_redirects', None), + ) + + def _extend_pathex(self, spec_pathex, scripts): + """ + Normalize additional paths where PyInstaller will look for modules and add paths with scripts to the list of + paths. + + :param spec_pathex: Additional paths defined defined in .spec file. + :param scripts: Scripts to create executable from. + :return: list of updated paths + """ + # Based on main supplied script - add top-level modules directory to PYTHONPATH. + # Sometimes the main app script is not top-level module but submodule like 'mymodule.mainscript.py'. + # In that case PyInstaller will not be able find modules in the directory containing 'mymodule'. + # Add this directory to PYTHONPATH so PyInstaller could find it. + pathex = [] + # Add scripts paths first. + for script in scripts: + logger.debug('script: %s' % script) + script_toplevel_dir = get_path_to_toplevel_modules(script) + if script_toplevel_dir: + pathex.append(script_toplevel_dir) + # Append paths from .spec. + if spec_pathex is not None: + pathex.extend(spec_pathex) + # Normalize paths in pathex and make them absolute. + return [absnormpath(p) for p in pathex] + + def _check_guts(self, data, last_build): + if Target._check_guts(self, data, last_build): + return True + for filename in self.inputs: + if mtime(filename) > last_build: + logger.info("Building because %s changed", filename) + return True + # Now we know that none of the input parameters and none of the input files has changed. So take the values + # that were calculated / analyzed in the last run and store them in `self`. These TOC lists should already + # be normalized. + self.scripts = data['scripts'] + self.pure = data['pure'] + self.binaries = data['binaries'] + self.zipfiles = data['zipfiles'] + self.zipped_data = data['zipped_data'] + self.datas = data['datas'] + + # Store previously found binding redirects in CONF for later use by PKG/COLLECT + from PyInstaller.config import CONF + self.binding_redirects = CONF['binding_redirects'] = data['binding_redirects'] + + return False + + def assemble(self): + """ + This method is the MAIN method for finding all necessary files to be bundled. + """ + from PyInstaller.config import CONF + + for m in self.excludes: + logger.debug("Excluding module '%s'" % m) + self.graph = initialize_modgraph(excludes=self.excludes, user_hook_dirs=self.hookspath) + + # Initialize `binaries` and `datas` with `_input_binaries` and `_input_datas`. Make sure to copy the lists + # to prevent modifications of original lists, which we need to store in original form for guts comparison. + self.datas = [entry for entry in self._input_datas] + self.binaries = [entry for entry in self._input_binaries] + + # TODO: find a better place where to put 'base_library.zip' and when to created it. + # For Python 3 it is necessary to create file 'base_library.zip' containing core Python modules. In Python 3 + # some built-in modules are written in pure Python. base_library.zip is a way how to have those modules as + # "built-in". + libzip_filename = os.path.join(CONF['workpath'], 'base_library.zip') + create_py3_base_library(libzip_filename, graph=self.graph) + # Bundle base_library.zip as data file. + # Data format of TOC item: ('relative_path_in_dist_dir', 'absolute_path_on_disk', 'DATA') + self.datas.append((os.path.basename(libzip_filename), libzip_filename, 'DATA')) + + # Expand sys.path of module graph. The attribute is the set of paths to use for imports: sys.path, plus our + # loader, plus other paths from e.g. --path option). + self.graph.path = self.pathex + self.graph.path + self.graph.set_setuptools_nspackages() + + logger.info("running Analysis %s", self.tocbasename) + # Get paths to Python and, in Windows, the manifest. + python = compat.python_executable + if not is_win: + # Linux/MacOS: get a real, non-link path to the running Python executable. + while os.path.islink(python): + python = os.path.join(os.path.dirname(python), os.readlink(python)) + depmanifest = None + else: + # Windows: Create a manifest to embed into built .exe, containing the same dependencies as python.exe. + depmanifest = winmanifest.Manifest( + type_="win32", + name=CONF['specnm'], + processorArchitecture=winmanifest.processor_architecture(), + version=(1, 0, 0, 0) + ) + depmanifest.filename = os.path.join(CONF['workpath'], CONF['specnm'] + ".exe.manifest") + + # We record "binaries" separately from the modulegraph, as there is no way to record those dependencies in the + # graph. These include the python executable and any binaries added by hooks later. "binaries" are not the same + # as "extensions" which are .so or .dylib that are found and recorded as extension nodes in the graph. Reset + # seen variable before running bindepend. We use bindepend only for the python executable. + bindepend.seen.clear() + + # Add binary and assembly dependencies of Python.exe. This also ensures that its assembly dependencies under + # Windows get added to the built .exe's manifest. Python 2.7 extension modules have no assembly dependencies, + # and rely on the app-global dependencies set by the .exe. + self.binaries.extend( + bindepend.Dependencies([('', python, '')], manifest=depmanifest, redirects=self.binding_redirects)[1:] + ) + if is_win: + depmanifest.writeprettyxml() + + # -- Module graph. -- + # + # Construct the module graph of import relationships between modules required by this user's application. For + # each entry point (top-level user-defined Python script), all imports originating from this entry point are + # recursively parsed into a subgraph of the module graph. This subgraph is then connected to this graph's root + # node, ensuring imported module nodes will be reachable from the root node -- which is is (arbitrarily) chosen + # to be the first entry point's node. + + # List to hold graph nodes of scripts and runtime hooks in use order. + priority_scripts = [] + + # Assume that if the script does not exist, Modulegraph will raise error. Save the graph nodes of each in + # sequence. + for script in self.inputs: + logger.info("Analyzing %s", script) + priority_scripts.append(self.graph.add_script(script)) + + # Analyze the script's hidden imports (named on the command line) + self.graph.add_hiddenimports(self.hiddenimports) + + # -- Post-graph hooks. -- + self.graph.process_post_graph_hooks(self) + + # Update 'binaries' TOC and 'datas' TOC. + deps_proc = DependencyProcessor(self.graph, self.graph._additional_files_cache) + + self.binaries.extend(deps_proc.make_binaries_toc()) + self.datas.extend(deps_proc.make_datas_toc()) + + self.zipped_data = deps_proc.make_zipped_data_toc() # Already normalized + # Note: zipped eggs are collected below + + # -- Look for dlls that are imported by Python 'ctypes' module. -- + # First get code objects of all modules that import 'ctypes'. + logger.info('Looking for ctypes DLLs') + # dict like: {'module1': code_obj, 'module2': code_obj} + ctypes_code_objs = self.graph.get_code_using("ctypes") + + for name, co in ctypes_code_objs.items(): + # Get dlls that might be needed by ctypes. + logger.debug('Scanning %s for shared libraries or dlls', name) + try: + ctypes_binaries = scan_code_for_ctypes(co) + self.binaries.extend(set(ctypes_binaries)) + except Exception as ex: + raise RuntimeError(f"Failed to scan the module '{name}'. This is a bug. Please report it.") from ex + + self.datas.extend((dest, source, "DATA") + for (dest, source) in format_binaries_and_datas(self.graph.metadata_required())) + + # Analyze run-time hooks. Run-time hooks has to be executed before user scripts. Add them to the beginning of + # 'priority_scripts'. + priority_scripts = self.graph.analyze_runtime_hooks(self.custom_runtime_hooks) + priority_scripts + + # 'priority_scripts' is now a list of the graph nodes of custom runtime hooks, then regular runtime hooks, then + # the PyI loader scripts. Further on, we will make sure they end up at the front of self.scripts + + # -- Extract the nodes of the graph as TOCs for further processing. -- + + # Initialize the scripts list with priority scripts in the proper order. + self.scripts = self.graph.nodes_to_toc(priority_scripts) + self.scripts = normalize_toc(self.scripts) # Should not really contain duplicates, but just in case... + + # Extend the binaries list with all the Extensions modulegraph has found. + self.binaries += self.graph.make_binaries_toc() + + # Convert extension module names into full filenames, and append suffix. Ensure that extensions that come from + # the lib-dynload are collected into _MEIPASS/lib-dynload instead of directly into _MEIPASS. + for idx, (dest, source, typecode) in enumerate(self.binaries): + if typecode != 'EXTENSION': + continue + + # Convert to full filename and append suffix + dest, source, typecode = add_suffix_to_extension(dest, source, typecode) + + # Divert into lib-dyload, if necessary (i.e., if file comes from lib-dynload directory) and its destination + # path does not already have a directory prefix. + src_parent = os.path.basename(os.path.dirname(source)) + if src_parent == 'lib-dynload' and not os.path.dirname(os.path.normpath(dest)): + dest = os.path.join('lib-dynload', dest) + + # Update + self.binaries[idx] = (dest, source, typecode) + + # Perform initial normalization of `datas` and `binaries` + self.datas = normalize_toc(self.datas) + self.binaries = normalize_toc(self.binaries) + + # Post-process GLib schemas + self.datas = compile_glib_schema_files(self.datas, os.path.join(CONF['workpath'], "_pyi_gschema_compilation")) + self.datas = normalize_toc(self.datas) + + # Process the pure-python modules list. Depending on the collection mode, these entries end up either in "pure" + # list for collection into the PYZ archive, or in the "datas" list for collection as external data files. + assert len(self.pure) == 0 + pure_pymodules_toc = self.graph.make_pure_toc() + + # Merge package collection mode settings from .spec file. These are applied last, so they override the + # settings previously applied by hooks. + self.graph._module_collection_mode.update(self.module_collection_mode) + logger.debug("Module collection settings: %r", self.graph._module_collection_mode) + + pycs_dir = os.path.join(CONF['workpath'], 'localpycs') + code_cache = self.graph.get_code_objects() + + for name, src_path, typecode in pure_pymodules_toc: + assert typecode == 'PYMODULE' + collect_mode = _get_module_collection_mode(self.graph._module_collection_mode, name, self.noarchive) + + # Collect byte-compiled .pyc into PYZ archive + if _ModuleCollectionMode.PYZ in collect_mode: + self.pure.append((name, src_path, typecode)) + + # Pure namespace packages have no source path, and cannot be collected as external data file. + if src_path in (None, '-'): + continue + + # Collect source .py file as external data file + if _ModuleCollectionMode.PY in collect_mode: + dest_path = name.replace('.', os.sep) + # Special case: modules have an implied filename to add. + basename, ext = os.path.splitext(os.path.basename(src_path)) + if basename == '__init__': + dest_path += os.sep + '__init__' + ext + else: + dest_path += ext + self.datas.append((dest_path, src_path, "DATA")) + + # Collect byte-compiled .pyc file as external data file + if _ModuleCollectionMode.PYC in collect_mode: + dest_path = name.replace('.', os.sep) + # Special case: modules have an implied filename to add. + basename, ext = os.path.splitext(os.path.basename(src_path)) + if basename == '__init__': + dest_path += os.sep + '__init__' + # Append the extension for the compiled result. In python 3.5 (PEP-488) .pyo files were replaced by + # .opt-1.pyc and .opt-2.pyc. However, it seems that for bytecode-only module distribution, we always + # need to use the .pyc extension. + dest_path += '.pyc' + + # Compile + obj_path = compile_pymodule(name, src_path, workpath=pycs_dir, code_cache=code_cache) + + self.datas.append((dest_path, obj_path, "DATA")) + + # Normalize list of pure-python modules (these will end up in PYZ archive, so use specific normalization). + self.pure = normalize_pyz_toc(self.pure) + + # Associate the `pure` TOC list instance with code cache in the global `CONF`; this is used by `PYZ` writer + # to obtain modules' code from cache instead + # + # (NOTE: back when `pure` was an instance of `TOC` class, the code object was passed by adding an attribute + # to the `pure` itself; now that `pure` is plain `list`, we cannot do that anymore. But the association via + # object ID should have the same semantics as the added attribute). + from PyInstaller.config import CONF + global_code_cache_map = CONF['code_cache'] + global_code_cache_map[id(self.pure)] = code_cache + + # Add remaining binary dependencies - analyze Python C-extensions and what DLLs they depend on. + # + # Up until this point, we did very best not to import the packages into the main process. However, a package + # may set up additional library search paths during its import (e.g., by modifying PATH or calling the + # add_dll_directory() function on Windows, or modifying LD_LIBRARY_PATH on Linux). In order to reliably + # discover dynamic libraries, we therefore require an environment with all packages imported. We achieve that + # by gathering list of all collected packages, and spawn an isolated process, in which we first import all + # the packages from the list, and then perform search for dynamic libraries. + logger.info('Looking for dynamic libraries') + + collected_packages = self.graph.get_collected_packages() + self.binaries.extend( + isolated.call(find_binary_dependencies, self.binaries, self.binding_redirects, collected_packages) + ) + + # Apply work-around for (potential) binaries collected from `pywin32` package... + if is_win: + self.binaries = postprocess_binaries_toc_pywin32(self.binaries) + # With anaconda, we need additional work-around... + if is_conda: + self.binaries = postprocess_binaries_toc_pywin32_anaconda(self.binaries) + + # Include zipped Python eggs. + logger.info('Looking for eggs') + self.zipfiles = deps_proc.make_zipfiles_toc() # Already normalized + + # Final normalization of datas and binaries + self.datas = normalize_toc(self.datas) + self.binaries = normalize_toc(self.binaries) + + # Verify that Python dynamic library can be found. Without dynamic Python library PyInstaller cannot continue. + self._check_python_library(self.binaries) + + if is_win: + # Remove duplicate redirects + self.binding_redirects = list(set(self.binding_redirects)) + logger.info("Found binding redirects: \n%s", self.binding_redirects) + + # Write warnings about missing modules. + self._write_warnings() + # Write debug information about the graph + self._write_graph_debug() + + def _write_warnings(self): + """ + Write warnings about missing modules. Get them from the graph and use the graph to figure out who tried to + import them. + """ + def dependency_description(name, dep_info): + if not dep_info or dep_info == 'direct': + imptype = 0 + else: + imptype = (dep_info.conditional + 2 * dep_info.function + 4 * dep_info.tryexcept) + return '%s (%s)' % (name, IMPORT_TYPES[imptype]) + + from PyInstaller.config import CONF + miss_toc = self.graph.make_missing_toc() + with open(CONF['warnfile'], 'w', encoding='utf-8') as wf: + wf.write(WARNFILE_HEADER) + for (n, p, status) in miss_toc: + importers = self.graph.get_importers(n) + print( + status, + 'module named', + n, + '- imported by', + ', '.join(dependency_description(name, data) for name, data in importers), + file=wf + ) + logger.info("Warnings written to %s", CONF['warnfile']) + + def _write_graph_debug(self): + """ + Write a xref (in html) and with `--log-level DEBUG` a dot-drawing of the graph. + """ + from PyInstaller.config import CONF + with open(CONF['xref-file'], 'w', encoding='utf-8') as fh: + self.graph.create_xref(fh) + logger.info("Graph cross-reference written to %s", CONF['xref-file']) + if logger.getEffectiveLevel() > logging.DEBUG: + return + # The `DOT language's `_ default character encoding (see the end + # of the linked page) is UTF-8. + with open(CONF['dot-file'], 'w', encoding='utf-8') as fh: + self.graph.graphreport(fh) + logger.info("Graph drawing written to %s", CONF['dot-file']) + + def _check_python_library(self, binaries): + """ + Verify presence of the Python dynamic library in the binary dependencies. Python library is an essential + piece that has to be always included. + """ + # First check if libpython is already among the resolved binary dependencies. + for dest_name, src_name, typecode in binaries: + if typecode == 'BINARY' and dest_name in PYDYLIB_NAMES: + # Just print its filename and return. + logger.info('Using Python library %s', src_name) + return + + # Python lib not in dependencies - try to find it. + logger.info('Python library not among binary dependencies. Performing additional search...') + python_lib = bindepend.get_python_library_path() + logger.debug('Adding Python library to binary dependencies') + binaries.append((os.path.basename(python_lib), python_lib, 'BINARY')) + logger.info('Using Python library %s', python_lib) + + def exclude_system_libraries(self, list_of_exceptions=None): + """ + This method may be optionally called from the spec file to exclude any system libraries from the list of + binaries other than those containing the shell-style wildcards in list_of_exceptions. Those that match + '*python*' or are stored under 'lib-dynload' are always treated as exceptions and not excluded. + """ + + self.binaries = [ + entry for entry in self.binaries if _should_include_system_binary(entry, list_of_exceptions or []) + ] + + +class ExecutableBuilder: + """ + Class that constructs the executable. + """ + # TODO wrap the 'main' and 'build' function into this class. + + +def build(spec, distpath, workpath, clean_build): + """ + Build the executable according to the created SPEC file. + """ + from PyInstaller.config import CONF + + # Ensure starting tilde and environment variables get expanded in distpath / workpath. + # '~/path/abc', '${env_var_name}/path/abc/def' + distpath = os.path.abspath(compat.expand_path(distpath)) + workpath = os.path.abspath(compat.expand_path(workpath)) + CONF['spec'] = os.path.abspath(compat.expand_path(spec)) + + CONF['specpath'], CONF['specnm'] = os.path.split(CONF['spec']) + CONF['specnm'] = os.path.splitext(CONF['specnm'])[0] + + # Add 'specname' to workpath and distpath if they point to PyInstaller homepath. + if os.path.dirname(distpath) == HOMEPATH: + distpath = os.path.join(HOMEPATH, CONF['specnm'], os.path.basename(distpath)) + CONF['distpath'] = distpath + if os.path.dirname(workpath) == HOMEPATH: + workpath = os.path.join(HOMEPATH, CONF['specnm'], os.path.basename(workpath), CONF['specnm']) + else: + workpath = os.path.join(workpath, CONF['specnm']) + CONF['workpath'] = workpath + + CONF['warnfile'] = os.path.join(workpath, 'warn-%s.txt' % CONF['specnm']) + CONF['dot-file'] = os.path.join(workpath, 'graph-%s.dot' % CONF['specnm']) + CONF['xref-file'] = os.path.join(workpath, 'xref-%s.html' % CONF['specnm']) + + CONF['code_cache'] = dict() + + # Clean PyInstaller cache (CONF['cachedir']) and temporary files (workpath) to be able start a clean build. + if clean_build: + logger.info('Removing temporary files and cleaning cache in %s', CONF['cachedir']) + for pth in (CONF['cachedir'], workpath): + if os.path.exists(pth): + # Remove all files in 'pth'. + for f in glob.glob(pth + '/*'): + # Remove dirs recursively. + if os.path.isdir(f): + shutil.rmtree(f) + else: + os.remove(f) + + # Create DISTPATH and workpath if they does not exist. + for pth in (CONF['distpath'], CONF['workpath']): + os.makedirs(pth, exist_ok=True) + + # Construct NAMESPACE for running the Python code from .SPEC file. + # NOTE: Passing NAMESPACE allows to avoid having global variables in this module and makes isolated environment for + # running tests. + # NOTE: Defining NAMESPACE allows to map any class to a apecific name for .SPEC. + # FIXME: Some symbols might be missing. Add them if there are some failures. + # TODO: What from this .spec API is deprecated and could be removed? + spec_namespace = { + # Set of global variables that can be used while processing .spec file. Some of them act as configuration + # options. + 'DISTPATH': CONF['distpath'], + 'HOMEPATH': HOMEPATH, + 'SPEC': CONF['spec'], + 'specnm': CONF['specnm'], + 'SPECPATH': CONF['specpath'], + 'WARNFILE': CONF['warnfile'], + 'workpath': CONF['workpath'], + # PyInstaller classes for .spec. + 'TOC': TOC, # Kept for backward compatibility even though `TOC` class is deprecated. + 'Analysis': Analysis, + 'BUNDLE': BUNDLE, + 'COLLECT': COLLECT, + 'EXE': EXE, + 'MERGE': MERGE, + 'PYZ': PYZ, + 'Tree': Tree, + 'Splash': Splash, + # Python modules available for .spec. + 'os': os, + 'pyi_crypto': pyz_crypto, + } + + # Execute the specfile. Read it as a binary file... + try: + with open(spec, 'rb') as f: + # ... then let Python determine the encoding, since ``compile`` accepts byte strings. + code = compile(f.read(), spec, 'exec') + except FileNotFoundError: + raise SystemExit(f'Spec file "{spec}" not found!') + exec(code, spec_namespace) + + +def __add_options(parser): + parser.add_argument( + "--distpath", + metavar="DIR", + default=DEFAULT_DISTPATH, + help="Where to put the bundled app (default: ./dist)", + ) + parser.add_argument( + '--workpath', + default=DEFAULT_WORKPATH, + help="Where to put all the temporary work files, .log, .pyz and etc. (default: ./build)", + ) + parser.add_argument( + '-y', + '--noconfirm', + action="store_true", + default=False, + help="Replace output directory (default: %s) without asking for confirmation" % + os.path.join('SPECPATH', 'dist', 'SPECNAME'), + ) + parser.add_argument( + '--upx-dir', + default=None, + help="Path to UPX utility (default: search the execution path)", + ) + parser.add_argument( + "-a", + "--ascii", + action="store_true", + help="Do not include unicode encoding support (default: included if available)", + ) + parser.add_argument( + '--clean', + dest='clean_build', + action='store_true', + default=False, + help="Clean PyInstaller cache and remove temporary files before building.", + ) + + +def main( + pyi_config, + specfile, + noconfirm=False, + ascii=False, + distpath=DEFAULT_DISTPATH, + workpath=DEFAULT_WORKPATH, + upx_dir=None, + clean_build=False, + **kw +): + from PyInstaller.config import CONF + CONF['noconfirm'] = noconfirm + + # Some modules are included if they are detected at build-time or if a command-line argument is specified + # (e.g., --ascii). + if CONF.get('hiddenimports') is None: + CONF['hiddenimports'] = [] + # Test unicode support. + if not ascii: + CONF['hiddenimports'].extend(get_unicode_modules()) + + # If configuration dict is supplied - skip configuration step. + if pyi_config is None: + import PyInstaller.configure as configure + CONF.update(configure.get_config(upx_dir=upx_dir)) + else: + CONF.update(pyi_config) + + CONF['ui_admin'] = kw.get('ui_admin', False) + CONF['ui_access'] = kw.get('ui_uiaccess', False) + + build(specfile, distpath, workpath, clean_build) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/datastruct.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/datastruct.py new file mode 100755 index 000000000..078b59210 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/datastruct.py @@ -0,0 +1,363 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +import os +import pathlib +import warnings + +from PyInstaller import log as logging +from PyInstaller.building.utils import _check_guts_eq +from PyInstaller.utils import misc + +logger = logging.getLogger(__name__) + + +def unique_name(entry): + """ + Return the filename used to enforce uniqueness for the given TOC entry. + + Parameters + ---------- + entry : tuple + + Returns + ------- + unique_name: str + """ + name, path, typecode = entry + if typecode in ('BINARY', 'DATA', 'EXTENSION', 'DEPENDENCY'): + name = os.path.normcase(name) + + return name + + +# This class is deprecated and has been replaced by plain lists with explicit normalization (de-duplication) via +# `normalize_toc` and `normalize_pyz_toc` helper functions. +class TOC(list): + """ + TOC (Table of Contents) class is a list of tuples of the form (name, path, typecode). + + typecode name path description + -------------------------------------------------------------------------------------- + EXTENSION Python internal name. Full path name in build. Extension module. + PYSOURCE Python internal name. Full path name in build. Script. + PYMODULE Python internal name. Full path name in build. Pure Python module (including __init__ modules). + PYZ Runtime name. Full path name in build. A .pyz archive (ZlibArchive data structure). + PKG Runtime name. Full path name in build. A .pkg archive (Carchive data structure). + BINARY Runtime name. Full path name in build. Shared library. + DATA Runtime name. Full path name in build. Arbitrary files. + OPTION The option. Unused. Python runtime option (frozen into executable). + + A TOC contains various types of files. A TOC contains no duplicates and preserves order. + PyInstaller uses TOC data type to collect necessary files bundle them into an executable. + """ + def __init__(self, initlist=None): + super().__init__() + + # Deprecation warning + warnings.warn( + "TOC class is deprecated. Use a plain list of 3-element tuples instead.", + DeprecationWarning, + stacklevel=2, + ) + + self.filenames = set() + if initlist: + for entry in initlist: + self.append(entry) + + def append(self, entry): + if not isinstance(entry, tuple): + logger.info("TOC found a %s, not a tuple", entry) + raise TypeError("Expected tuple, not %s." % type(entry).__name__) + + unique = unique_name(entry) + + if unique not in self.filenames: + self.filenames.add(unique) + super().append(entry) + + def insert(self, pos, entry): + if not isinstance(entry, tuple): + logger.info("TOC found a %s, not a tuple", entry) + raise TypeError("Expected tuple, not %s." % type(entry).__name__) + unique = unique_name(entry) + + if unique not in self.filenames: + self.filenames.add(unique) + super().insert(pos, entry) + + def __add__(self, other): + result = TOC(self) + result.extend(other) + return result + + def __radd__(self, other): + result = TOC(other) + result.extend(self) + return result + + def __iadd__(self, other): + for entry in other: + self.append(entry) + return self + + def extend(self, other): + # TODO: look if this can be done more efficient with out the loop, e.g. by not using a list as base at all. + for entry in other: + self.append(entry) + + def __sub__(self, other): + # Construct new TOC with entries not contained in the other TOC + other = TOC(other) + return TOC([entry for entry in self if unique_name(entry) not in other.filenames]) + + def __rsub__(self, other): + result = TOC(other) + return result.__sub__(self) + + def __setitem__(self, key, value): + if isinstance(key, slice): + if key == slice(None, None, None): + # special case: set the entire list + self.filenames = set() + self.clear() + self.extend(value) + return + else: + raise KeyError("TOC.__setitem__ doesn't handle slices") + + else: + old_value = self[key] + old_name = unique_name(old_value) + self.filenames.remove(old_name) + + new_name = unique_name(value) + if new_name not in self.filenames: + self.filenames.add(new_name) + super(TOC, self).__setitem__(key, value) + + +class Target: + invcnum = 0 + + def __init__(self): + from PyInstaller.config import CONF + + # Get a (per class) unique number to avoid conflicts between toc objects + self.invcnum = self.__class__.invcnum + self.__class__.invcnum += 1 + self.tocfilename = os.path.join(CONF['workpath'], '%s-%02d.toc' % (self.__class__.__name__, self.invcnum)) + self.tocbasename = os.path.basename(self.tocfilename) + self.dependencies = [] + + def __postinit__(self): + """ + Check if the target need to be rebuild and if so, re-assemble. + + `__postinit__` is to be called at the end of `__init__` of every subclass of Target. `__init__` is meant to + setup the parameters and `__postinit__` is checking if rebuild is required and in case calls `assemble()` + """ + logger.info("checking %s", self.__class__.__name__) + data = None + last_build = misc.mtime(self.tocfilename) + if last_build == 0: + logger.info("Building %s because %s is non existent", self.__class__.__name__, self.tocbasename) + else: + try: + data = misc.load_py_data_struct(self.tocfilename) + except Exception: + logger.info("Building because %s is bad", self.tocbasename) + else: + # create a dict for easier access + data = dict(zip((g[0] for g in self._GUTS), data)) + # assemble if previous data was not found or is outdated + if not data or self._check_guts(data, last_build): + self.assemble() + self._save_guts() + + _GUTS = [] + + def _check_guts(self, data, last_build): + """ + Returns True if rebuild/assemble is required. + """ + if len(data) != len(self._GUTS): + logger.info("Building because %s is bad", self.tocbasename) + return True + for attr, func in self._GUTS: + if func is None: + # no check for this value + continue + if func(attr, data[attr], getattr(self, attr), last_build): + return True + return False + + def _save_guts(self): + """ + Save the input parameters and the work-product of this run to maybe avoid regenerating it later. + """ + data = tuple(getattr(self, g[0]) for g in self._GUTS) + misc.save_py_data_struct(self.tocfilename, data) + + +class Tree(Target, list): + """ + This class is a way of creating a TOC (Table of Contents) list that describes some or all of the files within a + directory. + """ + def __init__(self, root=None, prefix=None, excludes=None, typecode='DATA'): + """ + root + The root of the tree (on the build system). + prefix + Optional prefix to the names of the target system. + excludes + A list of names to exclude. Two forms are allowed: + + name + Files with this basename will be excluded (do not include the path). + *.ext + Any file with the given extension will be excluded. + typecode + The typecode to be used for all files found in this tree. See the TOC class for for information about + the typcodes. + """ + Target.__init__(self) + list.__init__(self) + self.root = root + self.prefix = prefix + self.excludes = excludes + self.typecode = typecode + if excludes is None: + self.excludes = [] + self.__postinit__() + + _GUTS = ( # input parameters + ('root', _check_guts_eq), + ('prefix', _check_guts_eq), + ('excludes', _check_guts_eq), + ('typecode', _check_guts_eq), + ('data', None), # tested below + # no calculated/analysed values + ) + + def _check_guts(self, data, last_build): + if Target._check_guts(self, data, last_build): + return True + # Walk the collected directories as check if they have been changed - which means files have been added or + # removed. There is no need to check for the files, since `Tree` is only about the directory contents (which is + # the list of files). + stack = [data['root']] + while stack: + d = stack.pop() + if misc.mtime(d) > last_build: + logger.info("Building %s because directory %s changed", self.tocbasename, d) + return True + for nm in os.listdir(d): + path = os.path.join(d, nm) + if os.path.isdir(path): + stack.append(path) + self[:] = data['data'] # collected files + return False + + def _save_guts(self): + # Use the attribute `data` to save the list + self.data = self + super()._save_guts() + del self.data + + def assemble(self): + logger.info("Building Tree %s", self.tocbasename) + stack = [(self.root, self.prefix)] + excludes = set() + xexcludes = set() + for name in self.excludes: + if name.startswith('*'): + xexcludes.add(name[1:]) + else: + excludes.add(name) + result = [] + while stack: + dir, prefix = stack.pop() + for filename in os.listdir(dir): + if filename in excludes: + continue + ext = os.path.splitext(filename)[1] + if ext in xexcludes: + continue + fullfilename = os.path.join(dir, filename) + if prefix: + resfilename = os.path.join(prefix, filename) + else: + resfilename = filename + if os.path.isdir(fullfilename): + stack.append((fullfilename, resfilename)) + else: + result.append((resfilename, fullfilename, self.typecode)) + self[:] = result + + +def normalize_toc(toc): + # Default priority: 0 + _TOC_TYPE_PRIORITIES = { + # DEPENDENCY entries need to replace original entries, so they need the highest priority. + 'DEPENDENCY': 2, + # BINARY/EXTENSION entries undergo additional processing, so give them precedence over DATA and other entries. + 'BINARY': 1, + 'EXTENSION': 1, + } + + def _type_case_normalization_fcn(typecode): + # Case-normalize all entries except OPTION. + return typecode not in { + "OPTION", + } + + return _normalize_toc(toc, _TOC_TYPE_PRIORITIES, _type_case_normalization_fcn) + + +def normalize_pyz_toc(toc): + # Default priority: 0 + _TOC_TYPE_PRIORITIES = { + # Ensure that modules are never shadowed by PYZ-embedded data files. + 'PYMODULE': 1, + } + + return _normalize_toc(toc, _TOC_TYPE_PRIORITIES) + + +def _normalize_toc(toc, toc_type_priorities, type_case_normalization_fcn=lambda typecode: False): + tmp_toc = dict() + for dest_name, src_name, typecode in toc: + # Always sanitize the dest_name with `os.path.normpath` to remove any local loops with parent directory path + # components. `pathlib` does not seem to offer equivalent functionality. + dest_name = os.path.normpath(dest_name) + + # Normalize the destination name for uniqueness. Use `pathlib.PurePath` to ensure that keys are both + # case-normalized (on OSes where applicable) and directory-separator normalized (just in case). + if type_case_normalization_fcn(typecode): + entry_key = pathlib.PurePath(dest_name) + else: + entry_key = dest_name + + existing_entry = tmp_toc.get(entry_key) + if existing_entry is None: + # Entry does not exist - insert + tmp_toc[entry_key] = (dest_name, src_name, typecode) + else: + # Entry already exists - replace if its typecode has higher priority + _, _, existing_typecode = existing_entry + if toc_type_priorities.get(typecode, 0) > toc_type_priorities.get(existing_typecode, 0): + tmp_toc[entry_key] = (dest_name, src_name, typecode) + + # Return the items as list. The order matches the original order due to python dict maintaining the insertion order. + return list(tmp_toc.values()) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/icon.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/icon.py new file mode 100755 index 000000000..5ba029f37 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/icon.py @@ -0,0 +1,85 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2022-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from typing import Tuple + +import os +import hashlib + + +def normalize_icon_type(icon_path: str, allowed_types: Tuple[str], convert_type: str, workpath: str) -> str: + """ + Returns a valid icon path or raises an Exception on error. + Ensures that the icon exists, and, if necessary, attempts to convert it to correct OS-specific format using Pillow. + + Takes: + icon_path - the icon given by the user + allowed_types - a tuple of icon formats that should be allowed through + EX: ("ico", "exe") + convert_type - the type to attempt conversion too if necessary + EX: "icns" + workpath - the temp directory to save any newly generated image files + """ + + # explicitly error if file not found + if not os.path.exists(icon_path): + raise FileNotFoundError(f"Icon input file {icon_path} not found") + + _, extension = os.path.splitext(icon_path) + extension = extension[1:] # get rid of the "." in ".whatever" + + # if the file is already in the right format, pass it back unchanged + if extension in allowed_types: + # Check both the suffix and the header of the file to guard against the user confusing image types. + signatures = hex_signatures[extension] + with open(icon_path, "rb") as f: + header = f.read(max(len(s) for s in signatures)) + if any(list(header)[:len(s)] == s for s in signatures): + return icon_path + + # The icon type is wrong! Let's try and import PIL + try: + from PIL import Image as PILImage + import PIL + + except ImportError: + raise ValueError( + f"Received icon image '{icon_path}' which exists but is not in the correct format. On this platform, " + f"only {allowed_types} images may be used as icons. If Pillow is installed, automatic conversion will " + f"be attempted. Please install Pillow or convert your '{extension}' file to one of {allowed_types} " + f"and try again." + ) + + # Let's try to use PIL to convert the icon file type + try: + _generated_name = f"generated-{hashlib.sha256(icon_path.encode()).hexdigest()}.{convert_type}" + generated_icon = os.path.join(workpath, _generated_name) + with PILImage.open(icon_path) as im: + im.save(generated_icon) + icon_path = generated_icon + except PIL.UnidentifiedImageError: + raise ValueError( + f"Something went wrong converting icon image '{icon_path}' to '.{convert_type}' with Pillow, " + f"perhaps the image format is unsupported. Try again with a different file or use a file that can " + f"be used without conversion on this platform: {allowed_types}" + ) + + return icon_path + + +# Possible initial bytes of icon types PyInstaller needs to be able to recognise. +# Taken from: https://en.wikipedia.org/wiki/List_of_file_signatures +hex_signatures = { + "png": [[0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]], + "exe": [[0x4D, 0x5A], [0x5A, 0x4D]], + "ico": [[0x00, 0x00, 0x01, 0x00]], + "icns": [[0x69, 0x63, 0x6e, 0x73]], +} diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/makespec.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/makespec.py new file mode 100755 index 000000000..b71f0d3c0 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/makespec.py @@ -0,0 +1,836 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Automatically build spec files containing a description of the project. +""" + +import argparse +import os +import sys + +from PyInstaller import DEFAULT_SPECPATH, HOMEPATH +from PyInstaller import log as logging +from PyInstaller.building.templates import ( + bundleexetmplt, bundletmplt, cipher_absent_template, cipher_init_template, onedirtmplt, onefiletmplt, splashtmpl +) +from PyInstaller.compat import expand_path, is_darwin, is_win + +logger = logging.getLogger(__name__) +add_command_sep = os.pathsep + +# This list gives valid choices for the ``--debug`` command-line option, except for the ``all`` choice. +DEBUG_ARGUMENT_CHOICES = ['imports', 'bootloader', 'noarchive'] +# This is the ``all`` choice. +DEBUG_ALL_CHOICE = ['all'] + + +def escape_win_filepath(path): + # escape all \ with another \ after using normpath to clean up the path + return os.path.normpath(path).replace('\\', '\\\\') + + +def make_path_spec_relative(filename, spec_dir): + """ + Make the filename relative to the directory containing .spec file if filename is relative and not absolute. + Otherwise keep filename untouched. + """ + if os.path.isabs(filename): + return filename + else: + filename = os.path.abspath(filename) + # Make it relative. + filename = os.path.relpath(filename, start=spec_dir) + return filename + + +# Support for trying to avoid hard-coded paths in the .spec files. Eg, all files rooted in the Installer directory tree +# will be written using "HOMEPATH", thus allowing this spec file to be used with any Installer installation. Same thing +# could be done for other paths too. +path_conversions = ((HOMEPATH, "HOMEPATH"),) + + +def add_data_or_binary(string): + try: + src, dest = string.split(add_command_sep) + except ValueError as e: + # Split into SRC and DEST failed, wrong syntax + raise argparse.ArgumentError("Wrong syntax, should be SRC{}DEST".format(add_command_sep)) from e + if not src or not dest: + # Syntax was correct, but one or both of SRC and DEST was not given + raise argparse.ArgumentError("You have to specify both SRC and DEST") + # Return tuple containing SRC and SRC + return src, dest + + +def make_variable_path(filename, conversions=path_conversions): + if not os.path.isabs(filename): + # os.path.commonpath can not compare relative and absolute paths, and if filename is not absolute, none of the + # paths in conversions will match anyway. + return None, filename + for (from_path, to_name) in conversions: + assert os.path.abspath(from_path) == from_path, ("path '%s' should already be absolute" % from_path) + try: + common_path = os.path.commonpath([filename, from_path]) + except ValueError: + # Per https://docs.python.org/3/library/os.path.html#os.path.commonpath, this raises ValueError in several + # cases which prevent computing a common path. + common_path = None + if common_path == from_path: + rest = filename[len(from_path):] + if rest.startswith(('\\', '/')): + rest = rest[1:] + return to_name, rest + return None, filename + + +def deprecated_key_option(x): + logger.log( + logging.DEPRECATION, + "Bytecode encryption will be removed in PyInstaller v6. Please remove your --key=xxx argument to avoid " + "breakages on upgrade. For the rationale/alternatives see https://github.com/pyinstaller/pyinstaller/pull/6999" + ) + return x + + +# An object used in place of a "path string", which knows how to repr() itself using variable names instead of +# hard-coded paths. +class Path: + def __init__(self, *parts): + self.path = os.path.join(*parts) + self.variable_prefix = self.filename_suffix = None + + def __repr__(self): + if self.filename_suffix is None: + self.variable_prefix, self.filename_suffix = make_variable_path(self.path) + if self.variable_prefix is None: + return repr(self.path) + return "os.path.join(" + self.variable_prefix + "," + repr(self.filename_suffix) + ")" + + +# An object used to construct extra preamble for the spec file, in order to accommodate extra collect_*() calls from the +# command-line +class Preamble: + def __init__( + self, datas, binaries, hiddenimports, collect_data, collect_binaries, collect_submodules, collect_all, + copy_metadata, recursive_copy_metadata + ): + # Initialize with literal values - will be switched to preamble variable name later, if necessary + self.binaries = binaries or [] + self.hiddenimports = hiddenimports or [] + self.datas = datas or [] + # Preamble content + self.content = [] + + # Import statements + if collect_data: + self._add_hookutil_import('collect_data_files') + if collect_binaries: + self._add_hookutil_import('collect_dynamic_libs') + if collect_submodules: + self._add_hookutil_import('collect_submodules') + if collect_all: + self._add_hookutil_import('collect_all') + if copy_metadata or recursive_copy_metadata: + self._add_hookutil_import('copy_metadata') + if self.content: + self.content += [''] # empty line to separate the section + # Variables + if collect_data or copy_metadata or collect_all or recursive_copy_metadata: + self._add_var('datas', self.datas) + self.datas = 'datas' # switch to variable + if collect_binaries or collect_all: + self._add_var('binaries', self.binaries) + self.binaries = 'binaries' # switch to variable + if collect_submodules or collect_all: + self._add_var('hiddenimports', self.hiddenimports) + self.hiddenimports = 'hiddenimports' # switch to variable + # Content - collect_data_files + for entry in collect_data: + self._add_collect_data(entry) + # Content - copy_metadata + for entry in copy_metadata: + self._add_copy_metadata(entry) + # Content - copy_metadata(..., recursive=True) + for entry in recursive_copy_metadata: + self._add_recursive_copy_metadata(entry) + # Content - collect_binaries + for entry in collect_binaries: + self._add_collect_binaries(entry) + # Content - collect_submodules + for entry in collect_submodules: + self._add_collect_submodules(entry) + # Content - collect_all + for entry in collect_all: + self._add_collect_all(entry) + # Merge + if self.content and self.content[-1] != '': + self.content += [''] # empty line + self.content = '\n'.join(self.content) + + def _add_hookutil_import(self, name): + self.content += ['from PyInstaller.utils.hooks import {0}'.format(name)] + + def _add_var(self, name, initial_value): + self.content += ['{0} = {1}'.format(name, initial_value)] + + def _add_collect_data(self, name): + self.content += ['datas += collect_data_files(\'{0}\')'.format(name)] + + def _add_copy_metadata(self, name): + self.content += ['datas += copy_metadata(\'{0}\')'.format(name)] + + def _add_recursive_copy_metadata(self, name): + self.content += ['datas += copy_metadata(\'{0}\', recursive=True)'.format(name)] + + def _add_collect_binaries(self, name): + self.content += ['binaries += collect_dynamic_libs(\'{0}\')'.format(name)] + + def _add_collect_submodules(self, name): + self.content += ['hiddenimports += collect_submodules(\'{0}\')'.format(name)] + + def _add_collect_all(self, name): + self.content += [ + 'tmp_ret = collect_all(\'{0}\')'.format(name), + 'datas += tmp_ret[0]; binaries += tmp_ret[1]; hiddenimports += tmp_ret[2]' + ] + + +def __add_options(parser): + """ + Add the `Makespec` options to a option-parser instance or a option group. + """ + g = parser.add_argument_group('What to generate') + g.add_argument( + "-D", + "--onedir", + dest="onefile", + action="store_false", + default=None, + help="Create a one-folder bundle containing an executable (default)", + ) + g.add_argument( + "-F", + "--onefile", + dest="onefile", + action="store_true", + default=None, + help="Create a one-file bundled executable.", + ) + g.add_argument( + "--specpath", + metavar="DIR", + help="Folder to store the generated spec file (default: current directory)", + ) + g.add_argument( + "-n", + "--name", + help="Name to assign to the bundled app and spec file (default: first script's basename)", + ) + + g = parser.add_argument_group('What to bundle, where to search') + g.add_argument( + '--add-data', + action='append', + default=[], + type=add_data_or_binary, + metavar='', + dest='datas', + help='Additional non-binary files or folders to be added to the executable. The path separator is platform ' + 'specific, ``os.pathsep`` (which is ``;`` on Windows and ``:`` on most unix systems) is used. This option ' + 'can be used multiple times.', + ) + g.add_argument( + '--add-binary', + action='append', + default=[], + type=add_data_or_binary, + metavar='', + dest="binaries", + help='Additional binary files to be added to the executable. See the ``--add-data`` option for more details. ' + 'This option can be used multiple times.', + ) + g.add_argument( + "-p", + "--paths", + dest="pathex", + metavar="DIR", + action="append", + default=[], + help="A path to search for imports (like using PYTHONPATH). Multiple paths are allowed, separated by ``%s``, " + "or use this option multiple times. Equivalent to supplying the ``pathex`` argument in the spec file." % + repr(os.pathsep), + ) + g.add_argument( + '--hidden-import', + '--hiddenimport', + action='append', + default=[], + metavar="MODULENAME", + dest='hiddenimports', + help='Name an import not visible in the code of the script(s). This option can be used multiple times.', + ) + g.add_argument( + '--collect-submodules', + action="append", + default=[], + metavar="MODULENAME", + dest='collect_submodules', + help='Collect all submodules from the specified package or module. This option can be used multiple times.', + ) + g.add_argument( + '--collect-data', + '--collect-datas', + action="append", + default=[], + metavar="MODULENAME", + dest='collect_data', + help='Collect all data from the specified package or module. This option can be used multiple times.', + ) + g.add_argument( + '--collect-binaries', + action="append", + default=[], + metavar="MODULENAME", + dest='collect_binaries', + help='Collect all binaries from the specified package or module. This option can be used multiple times.', + ) + g.add_argument( + '--collect-all', + action="append", + default=[], + metavar="MODULENAME", + dest='collect_all', + help='Collect all submodules, data files, and binaries from the specified package or module. This option can ' + 'be used multiple times.', + ) + g.add_argument( + '--copy-metadata', + action="append", + default=[], + metavar="PACKAGENAME", + dest='copy_metadata', + help='Copy metadata for the specified package. This option can be used multiple times.', + ) + g.add_argument( + '--recursive-copy-metadata', + action="append", + default=[], + metavar="PACKAGENAME", + dest='recursive_copy_metadata', + help='Copy metadata for the specified package and all its dependencies. This option can be used multiple ' + 'times.', + ) + g.add_argument( + "--additional-hooks-dir", + action="append", + dest="hookspath", + default=[], + help="An additional path to search for hooks. This option can be used multiple times.", + ) + g.add_argument( + '--runtime-hook', + action='append', + dest='runtime_hooks', + default=[], + help='Path to a custom runtime hook file. A runtime hook is code that is bundled with the executable and is ' + 'executed before any other code or module to set up special features of the runtime environment. This option ' + 'can be used multiple times.', + ) + g.add_argument( + '--exclude-module', + dest='excludes', + action='append', + default=[], + help='Optional module or package (the Python name, not the path name) that will be ignored (as though it was ' + 'not found). This option can be used multiple times.', + ) + g.add_argument( + '--key', + dest='key', + help=argparse.SUPPRESS, + type=deprecated_key_option, + ) + g.add_argument( + '--splash', + dest='splash', + metavar="IMAGE_FILE", + help="(EXPERIMENTAL) Add an splash screen with the image IMAGE_FILE to the application. The splash screen can " + "display progress updates while unpacking.", + ) + + g = parser.add_argument_group('How to generate') + g.add_argument( + "-d", + "--debug", + # If this option is not specified, then its default value is an empty list (no debug options selected). + default=[], + # Note that ``nargs`` is omitted. This produces a single item not stored in a list, as opposed to a list + # containing one item, as per `nargs `_. + nargs=None, + # The options specified must come from this list. + choices=DEBUG_ALL_CHOICE + DEBUG_ARGUMENT_CHOICES, + # Append choice, rather than storing them (which would overwrite any previous selections). + action='append', + # Allow newlines in the help text; see the ``_SmartFormatter`` in ``__main__.py``. + help=( + "R|Provide assistance with debugging a frozen\n" + "application. This argument may be provided multiple\n" + "times to select several of the following options.\n" + "\n" + "- all: All three of the following options.\n" + "\n" + "- imports: specify the -v option to the underlying\n" + " Python interpreter, causing it to print a message\n" + " each time a module is initialized, showing the\n" + " place (filename or built-in module) from which it\n" + " is loaded. See\n" + " https://docs.python.org/3/using/cmdline.html#id4.\n" + "\n" + "- bootloader: tell the bootloader to issue progress\n" + " messages while initializing and starting the\n" + " bundled app. Used to diagnose problems with\n" + " missing imports.\n" + "\n" + "- noarchive: instead of storing all frozen Python\n" + " source files as an archive inside the resulting\n" + " executable, store them as files in the resulting\n" + " output directory.\n" + "\n" + ), + ) + g.add_argument( + '--python-option', + dest='python_options', + metavar='PYTHON_OPTION', + action='append', + default=[], + help='Specify a command-line option to pass to the Python interpreter at runtime. Currently supports ' + '"v" (equivalent to "--debug imports"), "u", and "W ".', + ) + g.add_argument( + "-s", + "--strip", + action="store_true", + help="Apply a symbol-table strip to the executable and shared libs (not recommended for Windows)", + ) + g.add_argument( + "--noupx", + action="store_true", + default=False, + help="Do not use UPX even if it is available (works differently between Windows and *nix)", + ) + g.add_argument( + "--upx-exclude", + dest="upx_exclude", + metavar="FILE", + action="append", + help="Prevent a binary from being compressed when using upx. This is typically used if upx corrupts certain " + "binaries during compression. FILE is the filename of the binary without path. This option can be used " + "multiple times.", + ) + + g = parser.add_argument_group('Windows and Mac OS X specific options') + g.add_argument( + "-c", + "--console", + "--nowindowed", + dest="console", + action="store_true", + default=None, + help="Open a console window for standard i/o (default). On Windows this option has no effect if the first " + "script is a '.pyw' file.", + ) + g.add_argument( + "-w", + "--windowed", + "--noconsole", + dest="console", + action="store_false", + default=None, + help="Windows and Mac OS X: do not provide a console window for standard i/o. On Mac OS this also triggers " + "building a Mac OS .app bundle. On Windows this option is automatically set if the first script is a '.pyw' " + "file. This option is ignored on *NIX systems.", + ) + g.add_argument( + "-i", + "--icon", + action='append', + dest="icon_file", + metavar='', + help="FILE.ico: apply the icon to a Windows executable. FILE.exe,ID: extract the icon with ID from an exe. " + "FILE.icns: apply the icon to the .app bundle on Mac OS. If an image file is entered that isn't in the " + "platform format (ico on Windows, icns on Mac), PyInstaller tries to use Pillow to translate the icon into " + "the correct format (if Pillow is installed). Use \"NONE\" to not apply any icon, thereby making the OS show " + "some default (default: apply PyInstaller's icon). This option can be used multiple times.", + ) + g.add_argument( + "--disable-windowed-traceback", + dest="disable_windowed_traceback", + action="store_true", + default=False, + help="Disable traceback dump of unhandled exception in windowed (noconsole) mode (Windows and macOS only), " + "and instead display a message that this feature is disabled.", + ) + + g = parser.add_argument_group('Windows specific options') + g.add_argument( + "--version-file", + dest="version_file", + metavar="FILE", + help="Add a version resource from FILE to the exe.", + ) + g.add_argument( + "-m", + "--manifest", + metavar="", + help="Add manifest FILE or XML to the exe.", + ) + g.add_argument( + "--no-embed-manifest", + dest="embed_manifest", + action="store_false", + help="Generate an external .exe.manifest file instead of embedding the manifest into the exe. Applicable only " + "to onedir mode; in onefile mode, the manifest is always embedded, regardless of this option.", + ) + g.add_argument( + "-r", + "--resource", + dest="resources", + metavar="RESOURCE", + action="append", + default=[], + help="Add or update a resource to a Windows executable. The RESOURCE is one to four items, " + "FILE[,TYPE[,NAME[,LANGUAGE]]]. FILE can be a data file or an exe/dll. For data files, at least TYPE and NAME " + "must be specified. LANGUAGE defaults to 0 or may be specified as wildcard * to update all resources of the " + "given TYPE and NAME. For exe/dll files, all resources from FILE will be added/updated to the final executable " + "if TYPE, NAME and LANGUAGE are omitted or specified as wildcard *. This option can be used multiple times.", + ) + g.add_argument( + '--uac-admin', + dest='uac_admin', + action="store_true", + default=False, + help="Using this option creates a Manifest that will request elevation upon application start.", + ) + g.add_argument( + '--uac-uiaccess', + dest='uac_uiaccess', + action="store_true", + default=False, + help="Using this option allows an elevated application to work with Remote Desktop.", + ) + + g = parser.add_argument_group('Windows Side-by-side Assembly searching options (advanced)') + g.add_argument( + "--win-private-assemblies", + dest="win_private_assemblies", + action="store_true", + help="Any Shared Assemblies bundled into the application will be changed into Private Assemblies. This means " + "the exact versions of these assemblies will always be used, and any newer versions installed on user machines " + "at the system level will be ignored.", + ) + g.add_argument( + "--win-no-prefer-redirects", + dest="win_no_prefer_redirects", + action="store_true", + help="While searching for Shared or Private Assemblies to bundle into the application, PyInstaller will " + "prefer not to follow policies that redirect to newer versions, and will try to bundle the exact versions of " + "the assembly.", + ) + + g = parser.add_argument_group('Mac OS specific options') + g.add_argument( + "--argv-emulation", + dest="argv_emulation", + action="store_true", + default=False, + help="Enable argv emulation for macOS app bundles. If enabled, the initial open document/URL event is " + "processed by the bootloader and the passed file paths or URLs are appended to sys.argv.", + ) + + g.add_argument( + '--osx-bundle-identifier', + dest='bundle_identifier', + help="Mac OS .app bundle identifier is used as the default unique program name for code signing purposes. " + "The usual form is a hierarchical name in reverse DNS notation. For example: com.mycompany.department.appname " + "(default: first script's basename)", + ) + + g.add_argument( + '--target-architecture', + '--target-arch', + dest='target_arch', + metavar='ARCH', + default=None, + help="Target architecture (macOS only; valid values: x86_64, arm64, universal2). Enables switching between " + "universal2 and single-arch version of frozen application (provided python installation supports the target " + "architecture). If not target architecture is not specified, the current running architecture is targeted.", + ) + + g.add_argument( + '--codesign-identity', + dest='codesign_identity', + metavar='IDENTITY', + default=None, + help="Code signing identity (macOS only). Use the provided identity to sign collected binaries and generated " + "executable. If signing identity is not provided, ad-hoc signing is performed instead.", + ) + + g.add_argument( + '--osx-entitlements-file', + dest='entitlements_file', + metavar='FILENAME', + default=None, + help="Entitlements file to use when code-signing the collected binaries (macOS only).", + ) + + g = parser.add_argument_group('Rarely used special options') + g.add_argument( + "--runtime-tmpdir", + dest="runtime_tmpdir", + metavar="PATH", + help="Where to extract libraries and support files in `onefile`-mode. If this option is given, the bootloader " + "will ignore any temp-folder location defined by the run-time OS. The ``_MEIxxxxxx``-folder will be created " + "here. Please use this option only if you know what you are doing.", + ) + g.add_argument( + "--bootloader-ignore-signals", + action="store_true", + default=False, + help="Tell the bootloader to ignore signals rather than forwarding them to the child process. Useful in " + "situations where for example a supervisor process signals both the bootloader and the child (e.g., via a " + "process group) to avoid signalling the child twice.", + ) + + +def main( + scripts, + name=None, + onefile=False, + console=True, + debug=[], + python_options=[], + strip=False, + noupx=False, + upx_exclude=None, + runtime_tmpdir=None, + pathex=[], + version_file=None, + specpath=None, + bootloader_ignore_signals=False, + disable_windowed_traceback=False, + datas=[], + binaries=[], + icon_file=None, + manifest=None, + embed_manifest=True, + resources=[], + bundle_identifier=None, + hiddenimports=[], + hookspath=[], + key=None, + runtime_hooks=[], + excludes=[], + uac_admin=False, + uac_uiaccess=False, + win_no_prefer_redirects=False, + win_private_assemblies=False, + collect_submodules=[], + collect_binaries=[], + collect_data=[], + collect_all=[], + copy_metadata=[], + splash=None, + recursive_copy_metadata=[], + target_arch=None, + codesign_identity=None, + entitlements_file=None, + argv_emulation=False, + **_kwargs +): + # Default values for onefile and console when not explicitly specified on command-line (indicated by None) + if onefile is None: + onefile = False + + if console is None: + console = True + + # If appname is not specified - use the basename of the main script as name. + if name is None: + name = os.path.splitext(os.path.basename(scripts[0]))[0] + + # If specpath not specified - use default value - current working directory. + if specpath is None: + specpath = DEFAULT_SPECPATH + else: + # Expand tilde to user's home directory. + specpath = expand_path(specpath) + # If cwd is the root directory of PyInstaller, generate the .spec file in ./appname/ subdirectory. + if specpath == HOMEPATH: + specpath = os.path.join(HOMEPATH, name) + # Create directory tree if missing. + if not os.path.exists(specpath): + os.makedirs(specpath) + + # Handle additional EXE options. + exe_options = '' + if version_file: + exe_options += "\n version='%s'," % escape_win_filepath(version_file) + if uac_admin: + exe_options += "\n uac_admin=True," + if uac_uiaccess: + exe_options += "\n uac_uiaccess=True," + if icon_file: + # Icon file for Windows. + # On Windows, the default icon is embedded in the bootloader executable. + if icon_file[0] == 'NONE': + exe_options += "\n icon='NONE'," + else: + exe_options += "\n icon=[%s]," % ','.join("'%s'" % escape_win_filepath(ic) for ic in icon_file) + # Icon file for Mac OS. + # We need to encapsulate it into apostrofes. + icon_file = "'%s'" % icon_file[0] + else: + # On Mac OS, the default icon has to be copied into the .app bundle. + # The the text value 'None' means - use default icon. + icon_file = 'None' + + if bundle_identifier: + # We need to encapsulate it into apostrofes. + bundle_identifier = "'%s'" % bundle_identifier + + if manifest: + if "<" in manifest: + # Assume XML string + exe_options += "\n manifest='%s'," % manifest.replace("'", "\\'") + else: + # Assume filename + exe_options += "\n manifest='%s'," % escape_win_filepath(manifest) + if not embed_manifest: + exe_options += "\n embed_manifest=False," + if resources: + resources = list(map(escape_win_filepath, resources)) + exe_options += "\n resources=%s," % repr(resources) + + hiddenimports = hiddenimports or [] + upx_exclude = upx_exclude or [] + + # If file extension of the first script is '.pyw', force --windowed option. + if is_win and os.path.splitext(scripts[0])[-1] == '.pyw': + console = False + + # If script paths are relative, make them relative to the directory containing .spec file. + scripts = [make_path_spec_relative(x, specpath) for x in scripts] + # With absolute paths replace prefix with variable HOMEPATH. + scripts = list(map(Path, scripts)) + + if key: + # Try to import tinyaes as we need it for bytecode obfuscation. + try: + import tinyaes # noqa: F401 (test import) + except ImportError: + logger.error( + 'We need tinyaes to use byte-code obfuscation but we could not find it. You can install it ' + 'with pip by running:\n pip install tinyaes' + ) + sys.exit(1) + cipher_init = cipher_init_template % {'key': key} + else: + cipher_init = cipher_absent_template + + # Translate the default of ``debug=None`` to an empty list. + if debug is None: + debug = [] + # Translate the ``all`` option. + if DEBUG_ALL_CHOICE[0] in debug: + debug = DEBUG_ARGUMENT_CHOICES + + # Create preamble (for collect_*() calls) + preamble = Preamble( + datas, binaries, hiddenimports, collect_data, collect_binaries, collect_submodules, collect_all, copy_metadata, + recursive_copy_metadata + ) + + if splash: + splash_init = splashtmpl % {'splash_image': splash} + splash_binaries = "\n splash.binaries," + splash_target = "\n splash," + else: + splash_init = splash_binaries = splash_target = "" + + # Create OPTIONs array + if 'imports' in debug and 'v' not in python_options: + python_options.append('v') + python_options_array = [(opt, None, 'OPTION') for opt in python_options] + + d = { + 'scripts': scripts, + 'pathex': pathex or [], + 'binaries': preamble.binaries, + 'datas': preamble.datas, + 'hiddenimports': preamble.hiddenimports, + 'preamble': preamble.content, + 'name': name, + 'noarchive': 'noarchive' in debug, + 'options': python_options_array, + 'debug_bootloader': 'bootloader' in debug, + 'bootloader_ignore_signals': bootloader_ignore_signals, + 'strip': strip, + 'upx': not noupx, + 'upx_exclude': upx_exclude, + 'runtime_tmpdir': runtime_tmpdir, + 'exe_options': exe_options, + 'cipher_init': cipher_init, + # Directory with additional custom import hooks. + 'hookspath': hookspath, + # List with custom runtime hook files. + 'runtime_hooks': runtime_hooks or [], + # List of modules/packages to ignore. + 'excludes': excludes or [], + # only Windows and Mac OS distinguish windowed and console apps + 'console': console, + 'disable_windowed_traceback': disable_windowed_traceback, + # Icon filename. Only Mac OS uses this item. + 'icon': icon_file, + # .app bundle identifier. Only OSX uses this item. + 'bundle_identifier': bundle_identifier, + # argv emulation (macOS only) + 'argv_emulation': argv_emulation, + # Target architecture (macOS only) + 'target_arch': target_arch, + # Code signing identity (macOS only) + 'codesign_identity': codesign_identity, + # Entitlements file (macOS only) + 'entitlements_file': entitlements_file, + # Windows assembly searching options + 'win_no_prefer_redirects': win_no_prefer_redirects, + 'win_private_assemblies': win_private_assemblies, + # splash screen + 'splash_init': splash_init, + 'splash_target': splash_target, + 'splash_binaries': splash_binaries, + } + + # Write down .spec file to filesystem. + specfnm = os.path.join(specpath, name + '.spec') + with open(specfnm, 'w', encoding='utf-8') as specfile: + if onefile: + specfile.write(onefiletmplt % d) + # For Mac OS create .app bundle. + if is_darwin and not console: + specfile.write(bundleexetmplt % d) + else: + specfile.write(onedirtmplt % d) + # For Mac OS create .app bundle. + if is_darwin and not console: + specfile.write(bundletmplt % d) + + return specfnm diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/osx.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/osx.py new file mode 100755 index 000000000..f804f2e52 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/osx.py @@ -0,0 +1,282 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +import os +import plistlib +import shutil + +from PyInstaller.building.api import COLLECT, EXE +from PyInstaller.building.datastruct import Target, logger, normalize_toc +from PyInstaller.building.utils import _check_path_overlap, _rmtree, checkCache +from PyInstaller.compat import is_darwin +from PyInstaller.building.icon import normalize_icon_type +import PyInstaller.utils.misc as miscutils + +if is_darwin: + import PyInstaller.utils.osx as osxutils + + +class BUNDLE(Target): + def __init__(self, *args, **kwargs): + from PyInstaller.config import CONF + + # BUNDLE only has a sense under Mac OS, it's a noop on other platforms + if not is_darwin: + return + + # Get a path to a .icns icon for the app bundle. + self.icon = kwargs.get('icon') + if not self.icon: + # --icon not specified; use the default in the pyinstaller folder + self.icon = os.path.join( + os.path.dirname(os.path.dirname(__file__)), 'bootloader', 'images', 'icon-windowed.icns' + ) + else: + # User gave an --icon=path. If it is relative, make it relative to the spec file location. + if not os.path.isabs(self.icon): + self.icon = os.path.join(CONF['specpath'], self.icon) + + super().__init__() + + # .app bundle is created in DISTPATH. + self.name = kwargs.get('name', None) + base_name = os.path.basename(self.name) + self.name = os.path.join(CONF['distpath'], base_name) + + self.appname = os.path.splitext(base_name)[0] + self.version = kwargs.get("version", "0.0.0") + self.toc = [] + self.strip = False + self.upx = False + self.console = True + self.target_arch = None + self.codesign_identity = None + self.entitlements_file = None + + # .app bundle identifier for Code Signing + self.bundle_identifier = kwargs.get('bundle_identifier') + if not self.bundle_identifier: + # Fallback to appname. + self.bundle_identifier = self.appname + + self.info_plist = kwargs.get('info_plist', None) + + for arg in args: + # Valid arguments: EXE object, COLLECT object, and TOC-like iterables + if isinstance(arg, EXE): + # Add EXE as an entry to the TOC, and merge its dependencies TOC + self.toc.append((os.path.basename(arg.name), arg.name, 'EXECUTABLE')) + self.toc.extend(arg.dependencies) + # Inherit settings + self.strip = arg.strip + self.upx = arg.upx + self.upx_exclude = arg.upx_exclude + self.console = arg.console + self.target_arch = arg.target_arch + self.codesign_identity = arg.codesign_identity + self.entitlements_file = arg.entitlements_file + elif isinstance(arg, COLLECT): + # Merge the TOC + self.toc.extend(arg.toc) + # Inherit settings + self.strip = arg.strip_binaries + self.upx = arg.upx_binaries + self.upx_exclude = arg.upx_exclude + self.console = arg.console + self.target_arch = arg.target_arch + self.codesign_identity = arg.codesign_identity + self.entitlements_file = arg.entitlements_file + elif miscutils.is_iterable(arg): + # TOC-like iterable + self.toc.extend(arg) + else: + raise TypeError(f"Invalid argument type for BUNDLE: {type(arg)!r}") + + # Infer the executable name from the first EXECUTABLE entry in the TOC; it might have come from the COLLECT + # (as opposed to the stand-alone EXE). + for dest_name, src_name, typecode in self.toc: + if typecode == "EXECUTABLE": + self.exename = src_name + break + else: + raise ValueError("No EXECUTABLE entry found in the TOC!") + + # Normalize TOC + self.toc = normalize_toc(self.toc) + + self.__postinit__() + + _GUTS = ( + # BUNDLE always builds, just want the toc to be written out + ('toc', None), + ) + + def _check_guts(self, data, last_build): + # BUNDLE always needs to be executed, in order to clean the output directory. + return True + + def assemble(self): + from PyInstaller.config import CONF + + if _check_path_overlap(self.name) and os.path.isdir(self.name): + _rmtree(self.name) + + logger.info("Building BUNDLE %s", self.tocbasename) + + # Create a minimal Mac bundle structure. + os.makedirs(os.path.join(self.name, "Contents", "MacOS")) + os.makedirs(os.path.join(self.name, "Contents", "Resources")) + os.makedirs(os.path.join(self.name, "Contents", "Frameworks")) + + # Makes sure the icon exists and attempts to convert to the proper format if applicable + self.icon = normalize_icon_type(self.icon, ("icns",), "icns", CONF["workpath"]) + + # Ensure icon path is absolute + self.icon = os.path.abspath(self.icon) + + # Copy icns icon to Resources directory. + shutil.copy(self.icon, os.path.join(self.name, 'Contents', 'Resources')) + + # Key/values for a minimal Info.plist file + info_plist_dict = { + "CFBundleDisplayName": self.appname, + "CFBundleName": self.appname, + + # Required by 'codesign' utility. + # The value for CFBundleIdentifier is used as the default unique name of your program for Code Signing + # purposes. It even identifies the APP for access to restricted OS X areas like Keychain. + # + # The identifier used for signing must be globally unique. The usual form for this identifier is a + # hierarchical name in reverse DNS notation, starting with the toplevel domain, followed by the company + # name, followed by the department within the company, and ending with the product name. Usually in the + # form: com.mycompany.department.appname + # CLI option --osx-bundle-identifier sets this value. + "CFBundleIdentifier": self.bundle_identifier, + "CFBundleExecutable": os.path.basename(self.exename), + "CFBundleIconFile": os.path.basename(self.icon), + "CFBundleInfoDictionaryVersion": "6.0", + "CFBundlePackageType": "APPL", + "CFBundleShortVersionString": self.version, + } + + # Set some default values. But they still can be overwritten by the user. + if self.console: + # Setting EXE console=True implies LSBackgroundOnly=True. + info_plist_dict['LSBackgroundOnly'] = True + else: + # Let's use high resolution by default. + info_plist_dict['NSHighResolutionCapable'] = True + + # Merge info_plist settings from spec file + if isinstance(self.info_plist, dict) and self.info_plist: + info_plist_dict.update(self.info_plist) + + plist_filename = os.path.join(self.name, "Contents", "Info.plist") + with open(plist_filename, "wb") as plist_fh: + plistlib.dump(info_plist_dict, plist_fh) + + links = [] + _QT_BASE_PATH = {'PySide2', 'PySide6', 'PyQt5', 'PySide6'} + for dest_name, src_name, typecode in self.toc: + # Copy files from cache. This ensures that are used files with relative paths to dynamic library + # dependencies (@executable_path). + base_path = dest_name.split('/', 1)[0] + if typecode in ('EXTENSION', 'BINARY'): + src_name = checkCache( + src_name, + strip=self.strip, + upx=self.upx, + upx_exclude=self.upx_exclude, + dist_nm=dest_name, + target_arch=self.target_arch, + codesign_identity=self.codesign_identity, + entitlements_file=self.entitlements_file, + strict_arch_validation=(typecode == 'EXTENSION'), + ) + # Add most data files to a list for symlinking later. + # Exempt python source files from this relocation, because their real path might need to resolve + # to the directory that also contains the extension module. + relocate_file = typecode == 'DATA' and base_path not in _QT_BASE_PATH + if relocate_file and os.path.splitext(dest_name)[1].lower() in {'.py', '.pyc'}: + relocate_file = False + if relocate_file: + links.append((dest_name, src_name)) + else: + # At this point, `src_name` should be a valid file. + if not os.path.isfile(src_name): + raise ValueError(f"Resource {src_name!r} is not a valid file!") + dest_path = os.path.join(self.name, "Contents", "MacOS", dest_name) + dest_dir = os.path.dirname(dest_path) + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) + shutil.copy2(src_name, dest_path) # Use copy2 to (attempt to) preserve metadata + + logger.info('Moving BUNDLE data files to Resource directory') + + # Mac OS Code Signing does not work when .app bundle contains data files in dir ./Contents/MacOS. + # Put all data files in ./Resources and create symlinks in ./MacOS. + bin_dir = os.path.join(self.name, 'Contents', 'MacOS') + res_dir = os.path.join(self.name, 'Contents', 'Resources') + for dest_name, src_name in links: + # At this point, `src_name` should be a valid file. + if not os.path.isfile(src_name): + raise ValueError(f"Resource {src_name!r} is not a valid file!") + dest_path = os.path.join(res_dir, dest_name) + dest_dir = os.path.dirname(dest_path) + if not os.path.exists(dest_dir): + os.makedirs(dest_dir) + shutil.copy2(src_name, dest_dir) # Use copy2 to (attempt to) preserve metadata + base_path = os.path.split(dest_name)[0] + if base_path: + if not os.path.exists(os.path.join(bin_dir, dest_name)): + path = '' + for part in iter(base_path.split(os.path.sep)): + # Build path from previous path and the next part of the base path + path = os.path.join(path, part) + try: + relative_source_path = os.path.relpath( + os.path.join(res_dir, path), + os.path.split(os.path.join(bin_dir, path))[0] + ) + dest_path = os.path.join(bin_dir, path) + os.symlink(relative_source_path, dest_path) + break + except FileExistsError: + pass + if not os.path.exists(os.path.join(bin_dir, dest_name)): + relative_source_path = os.path.relpath( + os.path.join(res_dir, dest_name), + os.path.split(os.path.join(bin_dir, dest_name))[0] + ) + dest_path = os.path.join(bin_dir, dest_name) + os.symlink(relative_source_path, dest_path) + else: + # If path is empty, e.g., a top-level file, try to just symlink the file. + relative_source_path = os.path.relpath( + os.path.join(res_dir, dest_name), + os.path.split(os.path.join(bin_dir, dest_name))[0] + ) + dest_path = os.path.join(bin_dir, dest_name) + os.symlink(relative_source_path, dest_path) + + # Sign the bundle + logger.info('Signing the BUNDLE...') + try: + osxutils.sign_binary(self.name, self.codesign_identity, self.entitlements_file, deep=True) + except Exception as e: + # Display a warning or re-raise the error, depending on the environment-variable setting. + if os.environ.get("PYINSTALLER_STRICT_BUNDLE_CODESIGN_ERROR", "0") == "0": + logger.warning("Error while signing the bundle: %s", e) + logger.warning("You will need to sign the bundle manually!") + else: + raise RuntimeError("Failed to codesign the bundle!") from e + + logger.info("Building BUNDLE %s completed successfully.", self.tocbasename) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/splash.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/splash.py new file mode 100755 index 000000000..b16cc2b17 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/splash.py @@ -0,0 +1,468 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +# ----------------------------------------------------------------------------- +import io +import os +import re +import struct +import pathlib + +from PyInstaller import log as logging +from PyInstaller.archive.writers import SplashWriter +from PyInstaller.building import splash_templates +from PyInstaller.building.datastruct import Target +from PyInstaller.building.utils import _check_guts_eq, _check_guts_toc, misc +from PyInstaller.compat import is_darwin +from PyInstaller.depend import bindepend +from PyInstaller.utils.hooks import tcl_tk as tcltk_utils + +try: + from PIL import Image as PILImage +except ImportError: + PILImage = None + +logger = logging.getLogger(__name__) + +# These requirement files are checked against the current splash screen script. If you wish to modify the splash screen +# and run into tcl errors/bad behavior, this is a good place to start and add components your implementation of the +# splash screen might use. +# NOTE: these paths use the *destination* layout for Tcl/Tk scripts, which uses unversioned tcl and tk directories +# (see `PyInstaller.utils.hooks.tcl_tk.collect_tcl_tk_files`). +splash_requirements = [ + # prepended tcl/tk binaries + os.path.join(tcltk_utils.TK_ROOTNAME, "license.terms"), + os.path.join(tcltk_utils.TK_ROOTNAME, "text.tcl"), + os.path.join(tcltk_utils.TK_ROOTNAME, "tk.tcl"), + # Used for customizable font + os.path.join(tcltk_utils.TK_ROOTNAME, "ttk", "ttk.tcl"), + os.path.join(tcltk_utils.TK_ROOTNAME, "ttk", "fonts.tcl"), + os.path.join(tcltk_utils.TK_ROOTNAME, "ttk", "cursors.tcl"), + os.path.join(tcltk_utils.TK_ROOTNAME, "ttk", "utils.tcl"), +] + + +class Splash(Target): + """ + Bundles the required resources for the splash screen into a file, which will be included in the CArchive. + + A Splash has two outputs, one is itself and one is stored in splash.binaries. Both need to be passed to other + build targets in order to enable the splash screen. + """ + def __init__(self, image_file, binaries, datas, **kwargs): + """ + :param str image_file: + A path-like object to the image to be used. Only the PNG file format is supported. + + .. note:: If a different file format is supplied and PIL (Pillow) is installed, the file will be converted + automatically. + + .. note:: *Windows*: The color ``'magenta'`` / ``'#ff00ff'`` must not be used in the image or text, as it is + used by splash screen to indicate transparent areas. Use a similar color (e.g., ``'#ff00fe'``) instead. + + .. note:: If PIL (Pillow) is installed and the image is bigger than max_img_size, the image will be resized + to fit into the specified area. + :param list binaries: + The TOC list of binaries the Analysis build target found. This TOC includes all extension modules and their + binary dependencies. This is required to determine whether the user's program uses `tkinter`. + :param list datas: + The TOC list of data the Analysis build target found. This TOC includes all data-file dependencies of the + modules. This is required to check if all splash screen requirements can be bundled. + + :keyword text_pos: + An optional two-integer tuple that represents the origin of the text on the splash screen image. The + origin of the text is its lower left corner. A unit in the respective coordinate system is a pixel of the + image, its origin lies in the top left corner of the image. This parameter also acts like a switch for + the text feature. If omitted, no text will be displayed on the splash screen. This text will be used to + show textual progress in onefile mode. + :type text_pos: Tuple[int, int] + :keyword text_size: + The desired size of the font. If the size argument is a positive number, it is interpreted as a size in + points. If size is a negative number, its absolute value is interpreted as a size in pixels. Default: ``12`` + :type text_size: int + :keyword text_font: + An optional name of a font for the text. This font must be installed on the user system, otherwise the + system default font is used. If this parameter is omitted, the default font is also used. + :keyword text_color: + An optional color for the text. HTML color codes (``'#40e0d0'``) and color names (``'turquoise'``) are + supported. Default: ``'black'`` + (Windows: the color ``'magenta'`` / ``'#ff00ff'`` is used to indicate transparency, and should not be used) + :type text_color: str + :keyword text_default: + The default text which will be displayed before the extraction starts. Default: ``"Initializing"`` + :type text_default: str + :keyword full_tk: + By default Splash bundles only the necessary files for the splash screen (some tk components). This + options enables adding full tk and making it a requirement, meaning all tk files will be unpacked before + the splash screen can be started. This is useful during development of the splash screen script. + Default: ``False`` + :type full_tk: bool + :keyword minify_script: + The splash screen is created by executing an Tcl/Tk script. This option enables minimizing the script, + meaning removing all non essential parts from the script. Default: ``True`` + :keyword rundir: + The folder name in which tcl/tk will be extracted at runtime. There should be no matching folder in your + application to avoid conflicts. Default: ``'__splash'`` + :type rundir: str + :keyword name: + An optional alternative filename for the .res file. If not specified, a name is generated. + :type name: str + :keyword script_name: + An optional alternative filename for the Tcl script, that will be generated. If not specified, a name is + generated. + :type script_name: str + :keyword max_img_size: + Maximum size of the splash screen image as a tuple. If the supplied image exceeds this limit, it will be + resized to fit the maximum width (to keep the original aspect ratio). This option can be disabled by + setting it to None. Default: ``(760, 480)`` + :type max_img_size: Tuple[int, int] + :keyword always_on_top: + Force the splashscreen to be always on top of other windows. If disabled, other windows (e.g., from other + applications) can cover the splash screen by user bringing them to front. This might be useful for + frozen applications with long startup times. Default: ``True`` + :type always_on_top: bool + """ + from ..config import CONF + Target.__init__(self) + + # Splash screen is not supported on macOS. It operates in a secondary thread and macOS disallows UI operations + # in any thread other than main. + if is_darwin: + raise SystemExit("Splash screen is not supported on macOS.") + + # Make image path relative to .spec file + if not os.path.isabs(image_file): + image_file = os.path.join(CONF['specpath'], image_file) + image_file = os.path.normpath(image_file) + if not os.path.exists(image_file): + raise ValueError("Image file '%s' not found" % image_file) + + # Copy all arguments + self.image_file = image_file + self.full_tk = kwargs.get("full_tk", False) + self.name = kwargs.get("name", None) + self.script_name = kwargs.get("script_name", None) + self.minify_script = kwargs.get("minify_script", True) + self.rundir = kwargs.get("rundir", None) + self.max_img_size = kwargs.get("max_img_size", (760, 480)) + + # text options + self.text_pos = kwargs.get("text_pos", None) + self.text_size = kwargs.get("text_size", 12) + self.text_font = kwargs.get("text_font", "TkDefaultFont") + self.text_color = kwargs.get("text_color", "black") + self.text_default = kwargs.get("text_default", "Initializing") + + # always-on-top behavior + self.always_on_top = kwargs.get("always_on_top", True) + + # Save the generated file separately so that it is not necessary to generate the data again and again + root = os.path.splitext(self.tocfilename)[0] + if self.name is None: + self.name = root + '.res' + if self.script_name is None: + self.script_name = root + '_script.tcl' + + if self.rundir is None: + self.rundir = self._find_rundir(binaries + datas) + + # Internal variables + try: + # Do not import _tkinter at the toplevel, because on some systems _tkinter will fail to load, since it is + # not installed. This would cause a runtime error in PyInstaller, since this module is imported from + # build_main.py, instead we just want to inform the user that the splash screen feature is not supported on + # his platform + import _tkinter + self._tkinter_module = _tkinter + self._tkinter_file = self._tkinter_module.__file__ + except ModuleNotFoundError: + raise SystemExit( + "You platform does not support the splash screen feature, since tkinter is not installed. Please " + "install tkinter and try again." + ) + + # Calculated / analysed values + self.uses_tkinter = self._uses_tkinter(self._tkinter_file, binaries) + logger.debug("Program uses tkinter: %r", self.uses_tkinter) + self.script = self.generate_script() + self.tcl_lib, self.tk_lib = tcltk_utils.find_tcl_tk_shared_libs(self._tkinter_file) + if is_darwin: + # Outdated Tcl/Tk 8.5 system framework is not supported. Depending on macOS version, the library path will + # come up empty (hidden system libraries on Big Sur), or will be + # [/System]/Library/Frameworks/Tcl.framework/Tcl + if self.tcl_lib[1] is None or 'Library/Frameworks/Tcl.framework' in self.tcl_lib[1]: + raise SystemExit("The splash screen feature does not support macOS system framework version of Tcl/Tk.") + # Check if tcl/tk was found + assert all(self.tcl_lib) + assert all(self.tk_lib) + logger.debug("Use Tcl Library from %s and Tk From %s", self.tcl_lib, self.tk_lib) + self.splash_requirements = set([self.tcl_lib[0], self.tk_lib[0]] + splash_requirements) + + logger.info("Collect tcl/tk binaries for the splash screen") + tcltk_tree = tcltk_utils.collect_tcl_tk_files(self._tkinter_file) + if self.full_tk: + # The user wants a full copy of tk, so make all tk files a requirement. + self.splash_requirements.update(entry[0] for entry in tcltk_tree) + + # Scan for binary dependencies of the Tcl/Tk shared libraries, and add them to `binaries` TOC list (which + # should really be called `dependencies` as it is not limited to binaries. But it is too late now, and + # existing spec files depend on this naming). We specify these binary dependencies (which include the + # Tcl and Tk shared libaries themselves) even if the user's program uses tkinter and they would be collected + # anyway; let the collection mechanism deal with potential duplicates. + tcltk_libs = [(dest_name, src_name, 'BINARY') for dest_name, src_name in (self.tcl_lib, self.tk_lib)] + self.binaries = bindepend.Dependencies(tcltk_libs) + + # Put all shared library dependencies in `splash_requirements`, so they are made available in onefile mode. + self.splash_requirements.update(entry[0] for entry in self.binaries) + + # If the user's program does not use tkinter, add resources from Tcl/Tk tree to the dependencies list. + # Do so only for the resources that are part of splash requirements. + if not self.uses_tkinter: + self.binaries.extend(entry for entry in tcltk_tree if entry[0] in self.splash_requirements) + + # Check if all requirements were found. + collected_files = set(entry[0] for entry in (binaries + datas + self.binaries)) + + def _filter_requirement(filename): + if filename not in collected_files: + # Item is not bundled, so warn the user about it. This actually may happen on some tkinter installations + # that are missing the license.terms file. + logger.warning( + "The local Tcl/Tk installation is missing the file %s. The behavior of the splash screen is " + "therefore undefined and may be unsupported.", filename + ) + return False + return True + + # Remove all files which were not found. + self.splash_requirements = set(filter(_filter_requirement, self.splash_requirements)) + + # Test if the tcl/tk version is supported by the bootloader. + self.test_tk_version() + + logger.debug("Splash Requirements: %s", self.splash_requirements) + + self.__postinit__() + + _GUTS = ( + # input parameters + ('image_file', _check_guts_eq), + ('name', _check_guts_eq), + ('script_name', _check_guts_eq), + ('text_pos', _check_guts_eq), + ('text_size', _check_guts_eq), + ('text_font', _check_guts_eq), + ('text_color', _check_guts_eq), + ('text_default', _check_guts_eq), + ('always_on_top', _check_guts_eq), + ('full_tk', _check_guts_eq), + ('minify_script', _check_guts_eq), + ('rundir', _check_guts_eq), + ('max_img_size', _check_guts_eq), + # calculated/analysed values + ('uses_tkinter', _check_guts_eq), + ('script', _check_guts_eq), + ('tcl_lib', _check_guts_eq), + ('tk_lib', _check_guts_eq), + ('splash_requirements', _check_guts_eq), + ('binaries', _check_guts_toc), + # internal value + # Check if the tkinter installation changed. This is theoretically possible if someone uses two different python + # installations of the same version. + ('_tkinter_file', _check_guts_eq), + ) + + def _check_guts(self, data, last_build): + if Target._check_guts(self, data, last_build): + return True + + # Check if the image has been modified. + if misc.mtime(self.image_file) > last_build: + logger.info("Building %s because file %s changed", self.tocbasename, self.image_file) + return True + + return False + + def assemble(self): + logger.info("Building Splash %s", self.name) + + # Function to resize a given image to fit into the area defined by max_img_size. + def _resize_image(_image, _orig_size): + if PILImage: + _w, _h = _orig_size + _ratio_w = self.max_img_size[0] / _w + if _ratio_w < 1: + # Image width exceeds limit + _h = int(_h * _ratio_w) + _w = self.max_img_size[0] + + _ratio_h = self.max_img_size[1] / _h + if _ratio_h < 1: + # Image height exceeds limit + _w = int(_w * _ratio_h) + _h = self.max_img_size[1] + + # If a file is given it will be open + if isinstance(_image, PILImage.Image): + _img = _image + else: + _img = PILImage.open(_image) + _img_resized = _img.resize((_w, _h)) + + # Save image into a stream + _image_stream = io.BytesIO() + _img_resized.save(_image_stream, format='PNG') + _img.close() + _img_resized.close() + _image_data = _image_stream.getvalue() + logger.info("Resized image %s from dimensions %s to (%d, %d)", self.image_file, str(_orig_size), _w, _h) + return _image_data + else: + raise ValueError( + "The splash image dimensions (w: %d, h: %d) exceed max_img_size (w: %d, h:%d), but the image " + "cannot be resized due to missing PIL.Image! Either install the Pillow package, adjust the " + "max_img_size, or use an image of compatible dimensions.", _orig_size[0], _orig_size[1], + self.max_img_size[0], self.max_img_size[1] + ) + + # Open image file + image_file = open(self.image_file, 'rb') + + # Check header of the file to identify it + if image_file.read(8) == b'\x89PNG\r\n\x1a\n': + # self.image_file is a PNG file + image_file.seek(16) + img_size = (struct.unpack("!I", image_file.read(4))[0], struct.unpack("!I", image_file.read(4))[0]) + + if img_size > self.max_img_size: + # The image exceeds the maximum image size, so resize it + image = _resize_image(self.image_file, img_size) + else: + image = os.path.abspath(self.image_file) + elif PILImage: + # Pillow is installed, meaning the image can be converted automatically + img = PILImage.open(self.image_file, mode='r') + + if img.size > self.max_img_size: + image = _resize_image(img, img.size) + else: + image_data = io.BytesIO() + img.save(image_data, format='PNG') + img.close() + image = image_data.getvalue() + logger.info("Converted image %s to PNG format", self.image_file) + else: + raise ValueError( + "The image %s needs to be converted to a PNG file, but PIL.Image is not available! Either install the " + "Pillow package, or use a PNG image for you splash screen.", self.image_file + ) + + image_file.close() + + SplashWriter( + self.name, + self.splash_requirements, + self.tcl_lib[0], # tcl86t.dll + self.tk_lib[0], # tk86t.dll + tcltk_utils.TK_ROOTNAME, + self.rundir, + image, + self.script + ) + + def test_tk_version(self): + tcl_version = float(self._tkinter_module.TCL_VERSION) + tk_version = float(self._tkinter_module.TK_VERSION) + + # Test if tcl/tk version is supported + if tcl_version < 8.6 or tk_version < 8.6: + logger.warning( + "The installed Tcl/Tk (%s/%s) version might not work with the splash screen feature of the bootloader. " + "The bootloader is tested against Tcl/Tk 8.6", self._tkinter_module.TCL_VERSION, + self._tkinter_module.TK_VERSION + ) + + # This should be impossible, since tcl/tk is released together with the same version number, but just in case + if tcl_version != tk_version: + logger.warning( + "The installed version of Tcl (%s) and Tk (%s) do not match. PyInstaller is tested against matching " + "versions", self._tkinter_module.TCL_VERSION, self._tkinter_module.TK_VERSION + ) + + # Ensure that Tcl is built with multi-threading support. + if not tcltk_utils.tcl_threaded: + # This is a feature breaking problem, so exit. + raise SystemExit( + "The installed tcl version is not threaded. PyInstaller only supports the splash screen " + "using threaded tcl." + ) + + def generate_script(self): + """ + Generate the script for the splash screen. + + If minify_script is True, all unnecessary parts will be removed. + """ + d = {} + if self.text_pos is not None: + logger.debug("Add text support to splash screen") + d.update({ + 'pad_x': self.text_pos[0], + 'pad_y': self.text_pos[1], + 'color': self.text_color, + 'font': self.text_font, + 'font_size': self.text_size, + 'default_text': self.text_default, + }) + script = splash_templates.build_script(text_options=d, always_on_top=self.always_on_top) + + if self.minify_script: + # Remove any documentation, empty lines and unnecessary spaces + script = '\n'.join( + line for line in map(lambda line: line.strip(), script.splitlines()) + if not line.startswith('#') # documentation + and line # empty lines + ) + # Remove unnecessary spaces + script = re.sub(' +', ' ', script) + + # Write script to disk, so that it is transparent to the user what script is executed. + with open(self.script_name, "w") as script_file: + script_file.write(script) + return script + + @staticmethod + def _uses_tkinter(tkinter_file, binaries): + # Test for _tkinter extension instead of tkinter module, because user might use a different wrapping library for + # Tk. Use `pathlib.PurePath˙ in comparisons to account for case normalization and separator normalization. + tkinter_file = pathlib.PurePath(tkinter_file) + for dest_name, src_name, typecode in binaries: + if pathlib.PurePath(src_name) == tkinter_file: + return True + return False + + @staticmethod + def _find_rundir(structure): + # First try a name the user could understand, if one would find the directory. + rundir = '__splash%s' + candidate = rundir % "" + counter = 0 + + # Run this loop as long as a folder exist named like rundir. In most cases __splash will be sufficient and this + # loop won't enter. + while any(e[0].startswith(candidate + os.sep) for e in structure): + # just append to rundir a counter + candidate = rundir % str(counter) + counter += 1 + + # The SPLASH_DATA_HEADER structure limits the name to be 16 bytes at maximum. So if we exceed the limit + # raise an error. This will never happen, since there are 10^8 different possibilities, but just in case. + assert len(candidate) <= 16 + + return candidate diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/splash_templates.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/splash_templates.py new file mode 100755 index 000000000..0db2cb0c0 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/splash_templates.py @@ -0,0 +1,229 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +# ----------------------------------------------------------------------------- +""" +Templates for the splash screen tcl script. +""" +from PyInstaller.compat import is_cygwin, is_darwin, is_win + +ipc_script = r""" +proc _ipc_server {channel clientaddr clientport} { + # This function is called if a new client connects to + # the server. This creates a channel, which calls + # _ipc_caller if data was send through the connection + set client_name [format <%s:%d> $clientaddr $clientport] + + chan configure $channel \ + -buffering none \ + -encoding utf-8 \ + -eofchar \x04 \ + -translation cr + chan event $channel readable [list _ipc_caller $channel $client_name] +} + +proc _ipc_caller {channel client_name} { + # This function is called if a command was sent through + # the tcp connection. The current implementation supports + # two commands: update_text and exit, although exit + # is implemented to be called if the connection gets + # closed (from python) or the character 0x04 was received + chan gets $channel cmd + + if {[chan eof $channel]} { + # This is entered if either the connection was closed + # or the char 0x04 was send + chan close $channel + exit + + } elseif {![chan blocked $channel]} { + # RPC methods + + # update_text command + if {[string match "update_text*" $cmd]} { + global status_text + set first [expr {[string first "(" $cmd] + 1}] + set last [expr {[string last ")" $cmd] - 1}] + + set status_text [string range $cmd $first $last] + } + # Implement other procedures here + } +} + +# By setting the port to 0 the os will assign a free port +set server_socket [socket -server _ipc_server -myaddr localhost 0] +set server_port [fconfigure $server_socket -sockname] + +# This environment variable is shared between the python and the tcl +# interpreter and publishes the port the tcp server socket is available +set env(_PYIBoot_SPLASH) [lindex $server_port 2] +""" + +image_script = r""" +# The variable $_image_data, which holds the data for the splash +# image is created by the bootloader. +image create photo splash_image +splash_image put $_image_data +# delete the variable, because the image now holds the data +unset _image_data + +proc canvas_text_update {canvas tag _var - -} { + # This function is rigged to be called if the a variable + # status_text gets changed. This updates the text on + # the canvas + upvar $_var var + $canvas itemconfigure $tag -text $var +} +""" + +splash_canvas_setup = r""" +package require Tk + +set image_width [image width splash_image] +set image_height [image height splash_image] +set display_width [winfo screenwidth .] +set display_height [winfo screenheight .] + +set x_position [expr {int(0.5*($display_width - $image_width))}] +set y_position [expr {int(0.5*($display_height - $image_height))}] + +# Toplevel frame in which all widgets should be positioned +frame .root + +# Configure the canvas on which the splash +# screen will be drawn +canvas .root.canvas \ + -width $image_width \ + -height $image_height \ + -borderwidth 0 \ + -highlightthickness 0 + +# Draw the image into the canvas, filling it. +.root.canvas create image \ + [expr {$image_width / 2}] \ + [expr {$image_height / 2}] \ + -image splash_image +""" + +splash_canvas_text = r""" +# Create a text on the canvas, which tracks the local +# variable status_text. status_text is changed via C to +# update the progress on the splash screen. +# We cannot use the default label, because it has a +# default background, which cannot be turned transparent +.root.canvas create text \ + %(pad_x)d \ + %(pad_y)d \ + -fill %(color)s \ + -justify center \ + -font myFont \ + -tag vartext \ + -anchor sw +trace variable status_text w \ + [list canvas_text_update .root.canvas vartext] +set status_text "%(default_text)s" +""" + +splash_canvas_default_font = r""" +font create myFont {*}[font actual TkDefaultFont] +font configure myFont -size %(font_size)d +""" + +splash_canvas_custom_font = r""" +font create myFont -family %(font)s -size %(font_size)d +""" + +if is_win or is_cygwin: + transparent_setup = r""" +# If the image is transparent, the background will be filled +# with magenta. The magenta background is later replaced with transparency. +# Here is the limitation of this implementation, that only +# sharp transparent image corners are possible +wm attributes . -transparentcolor magenta +.root.canvas configure -background magenta +""" + +elif is_darwin: + # This is untested, but should work following: https://stackoverflow.com/a/44296157/5869139 + transparent_setup = r""" +wm attributes . -transparent 1 +. configure -background systemTransparent +.root.canvas configure -background systemTransparent +""" + +else: + # For Linux there is no common way to create a transparent window + transparent_setup = r"" + +pack_widgets = r""" +# Position all widgets in the window +pack .root +grid .root.canvas -column 0 -row 0 -columnspan 1 -rowspan 2 +""" + +# Enable always-on-top behavior, by setting overrideredirect and the topmost attribute. +position_window_on_top = r""" +# Set position and mode of the window - always-on-top behavior +wm overrideredirect . 1 +wm geometry . +${x_position}+${y_position} +wm attributes . -topmost 1 +""" + +# Disable always-on-top behavior +if is_win or is_cygwin or is_darwin: + # On Windows, we disable the always-on-top behavior while still setting overrideredirect + # (to disable window decorations), but set topmost attribute to 0. + position_window = r""" +# Set position and mode of the window +wm overrideredirect . 1 +wm geometry . +${x_position}+${y_position} +wm attributes . -topmost 0 +""" +else: + # On Linux, we must not use overrideredirect; instead, we set X11-specific type attribute to splash, + # which lets the window manager to properly handle the splash screen (without window decorations + # but allowing other windows to be brought to front). + position_window = r""" +# Set position and mode of the window +wm geometry . +${x_position}+${y_position} +wm attributes . -type splash +""" + +raise_window = r""" +raise . +""" + + +def build_script(text_options=None, always_on_top=False): + """ + This function builds the tcl script for the splash screen. + """ + # Order is important! + script = [ + ipc_script, + image_script, + splash_canvas_setup, + ] + + if text_options: + # If the default font is used we need a different syntax + if text_options['font'] == "TkDefaultFont": + script.append(splash_canvas_default_font % text_options) + else: + script.append(splash_canvas_custom_font % text_options) + script.append(splash_canvas_text % text_options) + + script.append(transparent_setup) + + script.append(pack_widgets) + script.append(position_window_on_top if always_on_top else position_window) + script.append(raise_window) + + return '\n'.join(script) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/templates.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/templates.py new file mode 100755 index 000000000..ceb90f373 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/templates.py @@ -0,0 +1,142 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Templates to generate .spec files. +""" + +onefiletmplt = """# -*- mode: python ; coding: utf-8 -*- +%(preamble)s +%(cipher_init)s + +a = Analysis( + %(scripts)s, + pathex=%(pathex)s, + binaries=%(binaries)s, + datas=%(datas)s, + hiddenimports=%(hiddenimports)s, + hookspath=%(hookspath)r, + hooksconfig={}, + runtime_hooks=%(runtime_hooks)r, + excludes=%(excludes)s, + win_no_prefer_redirects=%(win_no_prefer_redirects)s, + win_private_assemblies=%(win_private_assemblies)s, + cipher=block_cipher, + noarchive=%(noarchive)s, +) +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) +%(splash_init)s +exe = EXE( + pyz, + a.scripts, + a.binaries, + a.zipfiles, + a.datas,%(splash_target)s%(splash_binaries)s + %(options)s, + name='%(name)s', + debug=%(debug_bootloader)s, + bootloader_ignore_signals=%(bootloader_ignore_signals)s, + strip=%(strip)s, + upx=%(upx)s, + upx_exclude=%(upx_exclude)s, + runtime_tmpdir=%(runtime_tmpdir)r, + console=%(console)s, + disable_windowed_traceback=%(disable_windowed_traceback)s, + argv_emulation=%(argv_emulation)r, + target_arch=%(target_arch)r, + codesign_identity=%(codesign_identity)r, + entitlements_file=%(entitlements_file)r,%(exe_options)s +) +""" + +onedirtmplt = """# -*- mode: python ; coding: utf-8 -*- +%(preamble)s +%(cipher_init)s + +a = Analysis( + %(scripts)s, + pathex=%(pathex)s, + binaries=%(binaries)s, + datas=%(datas)s, + hiddenimports=%(hiddenimports)s, + hookspath=%(hookspath)r, + hooksconfig={}, + runtime_hooks=%(runtime_hooks)r, + excludes=%(excludes)s, + win_no_prefer_redirects=%(win_no_prefer_redirects)s, + win_private_assemblies=%(win_private_assemblies)s, + cipher=block_cipher, + noarchive=%(noarchive)s, +) +pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher) +%(splash_init)s +exe = EXE( + pyz, + a.scripts,%(splash_target)s + %(options)s, + exclude_binaries=True, + name='%(name)s', + debug=%(debug_bootloader)s, + bootloader_ignore_signals=%(bootloader_ignore_signals)s, + strip=%(strip)s, + upx=%(upx)s, + console=%(console)s, + disable_windowed_traceback=%(disable_windowed_traceback)s, + argv_emulation=%(argv_emulation)r, + target_arch=%(target_arch)r, + codesign_identity=%(codesign_identity)r, + entitlements_file=%(entitlements_file)r,%(exe_options)s +) +coll = COLLECT( + exe, + a.binaries, + a.zipfiles, + a.datas,%(splash_binaries)s + strip=%(strip)s, + upx=%(upx)s, + upx_exclude=%(upx_exclude)s, + name='%(name)s', +) +""" + +cipher_absent_template = """ +block_cipher = None +""" + +cipher_init_template = """ +block_cipher = pyi_crypto.PyiBlockCipher(key=%(key)r) +""" + +bundleexetmplt = """app = BUNDLE( + exe, + name='%(name)s.app', + icon=%(icon)s, + bundle_identifier=%(bundle_identifier)s, +) +""" + +bundletmplt = """app = BUNDLE( + coll, + name='%(name)s.app', + icon=%(icon)s, + bundle_identifier=%(bundle_identifier)s, +) +""" + +splashtmpl = """splash = Splash( + %(splash_image)r, + binaries=a.binaries, + datas=a.datas, + text_pos=None, + text_size=12, + minify_script=True, + always_on_top=True, +) +""" diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/toc_conversion.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/toc_conversion.py new file mode 100755 index 000000000..ce43f7aa1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/toc_conversion.py @@ -0,0 +1,156 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +# ----------------------------------------------------------------------------- + +import os +import zipfile + +import pkg_resources + +from PyInstaller import log as logging +from PyInstaller.building.datastruct import Tree, normalize_toc +from PyInstaller.compat import ALL_SUFFIXES +from PyInstaller.depend.utils import get_path_to_egg + +logger = logging.getLogger(__name__) + +# create a list of excludes suitable for Tree. +PY_IGNORE_EXTENSIONS = { + *('*' + x for x in ALL_SUFFIXES), + # Exclude EGG-INFO, too, as long as we do not have a way to hold several in one archive. + 'EGG-INFO', +} + + +class DependencyProcessor: + """ + Class to convert final module dependency graph into TOC data structures. + TOC data structures are suitable for creating the final executable. + """ + def __init__(self, graph, additional_files): + self._binaries = set() + self._datas = set() + self._distributions = set() + self.__seen_distribution_paths = set() + # Include files that were found by hooks. graph.iter_graph() should include only those modules that are + # reachable from the top-level script. + for node in graph.iter_graph(start=graph._top_script_node): + # Update 'binaries', 'datas' + name = node.identifier + if name in additional_files: + self._binaries.update(additional_files.binaries(name)) + self._datas.update(additional_files.datas(name)) + # Any module can belong to a single distribution + self._distributions.update(self._get_distribution_for_node(node)) + + def _get_distribution_for_node(self, node): + """ + Get the distribution a module belongs to. + + Bug: This currently only handles packages in eggs. + """ + # TODO: Modulegraph could flag a module as residing in a zip file + # TODO add support for single modules in eggs (e.g. mock-1.0.1) + # TODO add support for egg-info: + # TODO add support for wheels (dist-info) + # + # TODO add support for unpacked eggs and for new .whl packages. + # Wheels: + # .../site-packages/pip/ # It seams this has to be a package + # .../site-packages/pip-6.1.1.dist-info + # Unzipped Eggs: + # .../site-packages/mock.py # this may be a single module, too! + # .../site-packages/mock-1.0.1-py2.7.egg-info + # Unzipped Eggs (I assume: multiple-versions externally managed): + # .../site-packages/pyPdf-1.13-py2.6.egg/pyPdf/ + # .../site-packages/pyPdf-1.13-py2.6.egg/EGG_INFO + # Zipped Egg: + # .../site-packages/zipped.egg/zipped_egg/ + # .../site-packages/zipped.egg/EGG_INFO + modpath = node.filename + if not modpath: + # e.g. namespace-package + return [] + # TODO: add other ways to get a distribution path + distpath = get_path_to_egg(modpath) + if not distpath or distpath in self.__seen_distribution_paths: + # no egg or already handled + return [] + self.__seen_distribution_paths.add(distpath) + dists = list(pkg_resources.find_distributions(distpath)) + assert len(dists) == 1 + dist = dists[0] + dist._pyinstaller_info = { + 'zipped': zipfile.is_zipfile(dist.location), + 'egg': True, # TODO when supporting other types + 'zip-safe': dist.has_metadata('zip-safe'), + } + return dists + + # Public methods. + + def make_binaries_toc(self): + toc = [(x, y, 'BINARY') for x, y in self._binaries] + return normalize_toc(toc) + + def make_datas_toc(self): + toc = [(x, y, 'DATA') for x, y in self._datas] + for dist in self._distributions: + if ( + dist._pyinstaller_info['egg'] and not dist._pyinstaller_info['zipped'] + and not dist._pyinstaller_info['zip-safe'] + ): + # this is a un-zipped, not-zip-safe egg + tree = Tree(dist.location, excludes=PY_IGNORE_EXTENSIONS) + toc.extend(tree) + return normalize_toc(toc) + + def make_zipfiles_toc(self): + # TODO create a real TOC when handling of more files is added. + toc = [] + for dist in self._distributions: + if dist._pyinstaller_info['zipped'] and not dist._pyinstaller_info['egg']: + # Hmm, this should never happen as normal zip-files are not associated with a distribution, are they? + toc.append(("eggs/" + os.path.basename(dist.location), dist.location, 'ZIPFILE')) + return normalize_toc(toc) + + @staticmethod + def __collect_data_files_from_zip(zipfilename): + # 'PyInstaller.config' cannot be imported as other top-level modules. + from PyInstaller.config import CONF + workpath = os.path.join(CONF['workpath'], os.path.basename(zipfilename)) + try: + os.makedirs(workpath) + except OSError as e: + import errno + if e.errno != errno.EEXIST: + raise + # TODO: extract only those file which would then be included + with zipfile.ZipFile(zipfilename) as zfh: + zfh.extractall(workpath) + return Tree(workpath, excludes=PY_IGNORE_EXTENSIONS) + + def make_zipped_data_toc(self): + toc = [] + logger.debug('Looking for egg data files...') + for dist in self._distributions: + if dist._pyinstaller_info['egg']: + if dist._pyinstaller_info['zipped']: + # this is a zipped egg + tree = self.__collect_data_files_from_zip(dist.location) + toc.extend(tree) + elif dist._pyinstaller_info['zip-safe']: + # this is an un-zipped, zip-safe egg + tree = Tree(dist.location, excludes=PY_IGNORE_EXTENSIONS) + toc.extend(tree) + else: + # this is an un-zipped, not-zip-safe egg, handled in make_datas_toc() + pass + return normalize_toc(toc) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/utils.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/utils.py new file mode 100755 index 000000000..ee948eb1d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/building/utils.py @@ -0,0 +1,857 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# --- functions for checking guts --- +# NOTE: by GUTS it is meant intermediate files and data structures that PyInstaller creates for bundling files and +# creating final executable. +import fnmatch +import glob +import hashlib +import marshal +import os +import pathlib +import platform +import py_compile +import shutil +import struct +import subprocess +import sys +import zipfile + +from PyInstaller import compat +from PyInstaller import log as logging +from PyInstaller.compat import (EXTENSION_SUFFIXES, is_darwin, is_win) +from PyInstaller.config import CONF +from PyInstaller.depend.bindepend import match_binding_redirect +from PyInstaller.utils import misc + +if is_win: + from PyInstaller.utils.win32 import versioninfo, winmanifest, winresource + +if is_darwin: + import PyInstaller.utils.osx as osxutils + +logger = logging.getLogger(__name__) + +# -- Helpers for checking guts. +# +# NOTE: by _GUTS it is meant intermediate files and data structures that PyInstaller creates for bundling files and +# creating final executable. + + +def _check_guts_eq(attr_name, old_value, new_value, last_build): + """ + Rebuild is required if values differ. + """ + if old_value != new_value: + logger.info("Building because %s changed", attr_name) + return True + return False + + +def _check_guts_toc_mtime(attr_name, old_toc, new_toc, last_build): + """ + Rebuild is required if mtimes of files listed in old TOC are newer than last_build. + + Use this for calculated/analysed values read from cache. + """ + for dest_name, src_name, typecode in old_toc: + if misc.mtime(src_name) > last_build: + logger.info("Building because %s changed", src_name) + return True + return False + + +def _check_guts_toc(attr_name, old_toc, new_toc, last_build): + """ + Rebuild is required if either TOC content changed or mtimes of files listed in old TOC are newer than last_build. + + Use this for input parameters. + """ + return _check_guts_eq(attr_name, old_toc, new_toc, last_build) or \ + _check_guts_toc_mtime(attr_name, old_toc, new_toc, last_build) + + +def add_suffix_to_extension(dest_name, src_name, typecode): + """ + Take a TOC entry (dest_name, src_name, typecode) and adjust the dest_name for EXTENSION to include the full library + suffix. + """ + # No-op for non-extension + if typecode != 'EXTENSION': + return dest_name, src_name, typecode + + # If dest_name completely fits into end of the src_name, it has already been processed. + if src_name.endswith(dest_name): + return dest_name, src_name, typecode + + # Change the dotted name into a relative path. This places C extensions in the Python-standard location. + dest_name = dest_name.replace('.', os.sep) + # In some rare cases extension might already contain a suffix. Skip it in this case. + if os.path.splitext(dest_name)[1] not in EXTENSION_SUFFIXES: + # Determine the base name of the file. + base_name = os.path.basename(dest_name) + assert '.' not in base_name + # Use this file's existing extension. For extensions such as ``libzmq.cp36-win_amd64.pyd``, we cannot use + # ``os.path.splitext``, which would give only the ```.pyd`` part of the extension. + dest_name = dest_name + os.path.basename(src_name)[len(base_name):] + + return dest_name, src_name, typecode + + +def applyRedirects(manifest, redirects): + """ + Apply the binding redirects specified by 'redirects' to the dependent assemblies of 'manifest'. + + :param manifest: + :type manifest: + :param redirects: + :type redirects: + :return: + :rtype: + """ + redirecting = False + for binding in redirects: + for dep in manifest.dependentAssemblies: + if match_binding_redirect(dep, binding): + logger.info("Redirecting %s version %s -> %s", binding.name, dep.version, binding.newVersion) + dep.version = binding.newVersion + redirecting = True + return redirecting + + +def checkCache( + fnm, + strip=False, + upx=False, + upx_exclude=None, + dist_nm=None, + target_arch=None, + codesign_identity=None, + entitlements_file=None, + strict_arch_validation=False +): + """ + Cache prevents preprocessing binary files again and again. + + 'dist_nm' Filename relative to dist directory. We need it on Mac to determine level of paths for @loader_path like + '@loader_path/../../' for qt4 plugins. + """ + from PyInstaller.config import CONF + + # Binding redirects should be taken into account to see if the file needs to be reprocessed. The redirects may + # change if the versions of dependent manifests change due to system updates. + redirects = CONF.get('binding_redirects', []) + # optionally change manifest to private assembly + win_private_assemblies = CONF.get('win_private_assemblies', False) + + # On Mac OS, a cache is required anyway to keep the libraries with relative install names. + # Caching on Mac OS does not work since we need to modify binary headers to use relative paths to dll dependencies + # and starting with '@loader_path'. + if not strip and not upx and not is_darwin and not (is_win and (redirects or win_private_assemblies)): + return fnm + + # Match against provided UPX exclude patterns. + upx_exclude = upx_exclude or [] + if upx: + fnm_path = pathlib.PurePath(fnm) + for upx_exclude_entry in upx_exclude: + # pathlib.PurePath.match() matches from right to left, and supports * wildcard, but does not support the + # "**" syntax for directory recursion. Case sensitivity follows the OS default. + if fnm_path.match(upx_exclude_entry): + logger.info("Disabling UPX for %s due to match in exclude pattern: %s", fnm, upx_exclude_entry) + upx = False + break + + # Load cache index. + # Make cachedir per Python major/minor version. + # This allows parallel building of executables with different Python versions as one user. + pyver = 'py%d%s' % (sys.version_info[0], sys.version_info[1]) + arch = platform.architecture()[0] + cachedir = os.path.join(CONF['cachedir'], 'bincache%d%d_%s_%s' % (strip, upx, pyver, arch)) + if target_arch: + cachedir = os.path.join(cachedir, target_arch) + if is_darwin: + # Separate by codesign identity + if codesign_identity: + # Compute hex digest of codesign identity string to prevent issues with invalid characters. + csi_hash = hashlib.sha256(codesign_identity.encode('utf-8')) + cachedir = os.path.join(cachedir, csi_hash.hexdigest()) + else: + cachedir = os.path.join(cachedir, 'adhoc') # ad-hoc signing + # Separate by entitlements + if entitlements_file: + # Compute hex digest of entitlements file contents + with open(entitlements_file, 'rb') as fp: + ef_hash = hashlib.sha256(fp.read()) + cachedir = os.path.join(cachedir, ef_hash.hexdigest()) + else: + cachedir = os.path.join(cachedir, 'no-entitlements') + if not os.path.exists(cachedir): + os.makedirs(cachedir) + cacheindexfn = os.path.join(cachedir, "index.dat") + if os.path.exists(cacheindexfn): + try: + cache_index = misc.load_py_data_struct(cacheindexfn) + except Exception: + # Tell the user they may want to fix their cache... However, do not delete it for them; if it keeps getting + # corrupted, we will never find out. + logger.warning("PyInstaller bincache may be corrupted; use pyinstaller --clean to fix it.") + raise + else: + cache_index = {} + + # Verify that the file we are looking for is present in the cache. Use the dist_mn if given to avoid different + # extension modules sharing the same basename get corrupted. + if dist_nm: + basenm = os.path.normcase(dist_nm) + else: + basenm = os.path.normcase(os.path.basename(fnm)) + + digest = cacheDigest(fnm, redirects) + cachedfile = os.path.join(cachedir, basenm) + cmd = None + if basenm in cache_index: + if digest != cache_index[basenm]: + os.remove(cachedfile) + else: + return cachedfile + + # Optionally change manifest and its dependencies to private assemblies. + if fnm.lower().endswith(".manifest") and is_win: + manifest = winmanifest.Manifest() + manifest.filename = fnm + with open(fnm, "rb") as f: + manifest.parse_string(f.read()) + if CONF.get('win_private_assemblies', False): + if manifest.publicKeyToken: + logger.info("Changing %s into private assembly", os.path.basename(fnm)) + manifest.publicKeyToken = None + for dep in manifest.dependentAssemblies: + # Exclude common-controls which is not bundled + if dep.name != "Microsoft.Windows.Common-Controls": + dep.publicKeyToken = None + + applyRedirects(manifest, redirects) + + manifest.writeprettyxml(cachedfile) + return cachedfile + + if upx: + if strip: + fnm = checkCache( + fnm, + strip=True, + upx=False, + dist_nm=dist_nm, + target_arch=target_arch, + codesign_identity=codesign_identity, + entitlements_file=entitlements_file, + strict_arch_validation=strict_arch_validation, + ) + # We need to avoid using UPX with Windows DLLs that have Control Flow Guard enabled, as it breaks them. + if is_win and versioninfo.pefile_check_control_flow_guard(fnm): + logger.info('Disabling UPX for %s due to CFG!', fnm) + elif misc.is_file_qt_plugin(fnm): + logger.info('Disabling UPX for %s due to it being a Qt plugin!', fnm) + else: + upx_exe = 'upx' + upx_dir = CONF['upx_dir'] + if upx_dir: + upx_exe = os.path.join(upx_dir, upx_exe) + + upx_options = [ + # Do not compress icons, so that they can still be accessed externally. + '--compress-icons=0', + # Use LZMA compression. + '--lzma', + # Quiet mode. + '-q', + ] + if is_win: + # Binaries built with Visual Studio 7.1 require --strip-loadconf or they will not compress. + upx_options.append('--strip-loadconf') + + cmd = [upx_exe, *upx_options, cachedfile] + else: + if strip: + strip_options = [] + if is_darwin: + # The default strip behavior breaks some shared libraries under Mac OS. + strip_options = ["-S"] # -S = strip only debug symbols. + cmd = ["strip", *strip_options, cachedfile] + + if not os.path.exists(os.path.dirname(cachedfile)): + os.makedirs(os.path.dirname(cachedfile)) + + # There are known some issues with 'shutil.copy2' on Mac OS 10.11 with copying st_flags. Issue #1650. + # 'shutil.copy' copies also permission bits and it should be sufficient for PyInstaller's purposes. + shutil.copy(fnm, cachedfile) + # TODO: find out if this is still necessary when no longer using shutil.copy2() + if hasattr(os, 'chflags'): + # Some libraries on FreeBSD have immunable flag (libthr.so.3, for example). If this flag is preserved, + # os.chmod() fails with: OSError: [Errno 1] Operation not permitted. + try: + os.chflags(cachedfile, 0) + except OSError: + pass + os.chmod(cachedfile, 0o755) + + if os.path.splitext(fnm.lower())[1] in (".pyd", ".dll") and is_win: + # When shared assemblies are bundled into the app, they may optionally be changed into private assemblies. + try: + res = winmanifest.GetManifestResources(os.path.abspath(cachedfile)) + except winresource.pywintypes.error as e: + if e.args[0] == winresource.ERROR_BAD_EXE_FORMAT: + # Not a win32 PE file + pass + else: + logger.error(os.path.abspath(cachedfile)) + raise + else: + if winmanifest.RT_MANIFEST in res and len(res[winmanifest.RT_MANIFEST]): + for name in res[winmanifest.RT_MANIFEST]: + for language in res[winmanifest.RT_MANIFEST][name]: + try: + manifest = winmanifest.Manifest() + manifest.filename = ":".join([ + cachedfile, str(winmanifest.RT_MANIFEST), + str(name), str(language) + ]) + manifest.parse_string(res[winmanifest.RT_MANIFEST][name][language], False) + except Exception: + logger.error("Cannot parse manifest resource %s, =%s", name, language) + logger.error("From file %s", cachedfile, exc_info=1) + else: + if win_private_assemblies: + if manifest.publicKeyToken: + logger.info("Changing %s into a private assembly", os.path.basename(fnm)) + manifest.publicKeyToken = None + + # Change dep to private assembly + for dep in manifest.dependentAssemblies: + # Exclude common-controls which is not bundled + if dep.name != "Microsoft.Windows.Common-Controls": + dep.publicKeyToken = None + redirecting = applyRedirects(manifest, redirects) + if redirecting or win_private_assemblies: + try: + manifest.update_resources(os.path.abspath(cachedfile), [name], [language]) + except Exception: + logger.error(os.path.abspath(cachedfile)) + raise + + if cmd: + logger.info("Executing: %s", " ".join(cmd)) + subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + + # update cache index + cache_index[basenm] = digest + misc.save_py_data_struct(cacheindexfn, cache_index) + + # On macOS, we need to modify the given binary's paths to the dependent libraries, in order to ensure they are + # relocatable and always refer to location within the frozen application. Specifically, we make all dependent + # library paths relative to @rpath, and set @rpath to point to the top-level application directory, relative to + # the binary's location (i.e., @loader_path). + # + # While modifying the headers invalidates existing signatures, we avoid removing them in order to speed things up + # (and to avoid potential bugs in the codesign utility, like the one reported on Mac OS 10.13 in #6167). + # The forced re-signing at the end should take care of the invalidated signatures. + if is_darwin: + try: + osxutils.binary_to_target_arch(cachedfile, target_arch, display_name=fnm) + #osxutils.remove_signature_from_binary(cachedfile) # Disabled as per comment above. + target_rpath = str( + pathlib.PurePath('@loader_path', *['..' for level in pathlib.PurePath(dist_nm).parent.parts]) + ) + osxutils.set_dylib_dependency_paths(cachedfile, target_rpath) + osxutils.sign_binary(cachedfile, codesign_identity, entitlements_file) + except osxutils.InvalidBinaryError: + # Raised by osxutils.binary_to_target_arch when the given file is not a valid macOS binary (for example, + # a linux .so file; see issue #6327). The error prevents any further processing, so just ignore it. + pass + except osxutils.IncompatibleBinaryArchError: + # Raised by osxutils.binary_to_target_arch when the given file does not contain (all) required arch slices. + # Depending on the strict validation mode, re-raise or swallow the error. + # + # Strict validation should be enabled only for binaries where the architecture *must* match the target one, + # i.e., the extension modules. Everything else is pretty much a gray area, for example: + # * a universal2 extension may have its x86_64 and arm64 slices linked against distinct single-arch/thin + # shared libraries + # * a collected executable that is launched by python code via a subprocess can be x86_64-only, even though + # the actual python code is running on M1 in native arm64 mode. + if strict_arch_validation: + raise + logger.debug("File %s failed optional architecture validation - collecting as-is!", fnm) + except Exception as e: + raise SystemError(f"Failed to process binary {cachedfile!r}!") from e + + return cachedfile + + +def cacheDigest(fnm, redirects): + hasher = hashlib.md5() + with open(fnm, "rb") as f: + for chunk in iter(lambda: f.read(16 * 1024), b""): + hasher.update(chunk) + if redirects: + redirects = str(redirects).encode('utf-8') + hasher.update(redirects) + digest = bytearray(hasher.digest()) + return digest + + +def _check_path_overlap(path): + """ + Check that path does not overlap with WORKPATH or SPECPATH (i.e., WORKPATH and SPECPATH may not start with path, + which could be caused by a faulty hand-edited specfile). + + Raise SystemExit if there is overlap, return True otherwise + """ + from PyInstaller.config import CONF + specerr = 0 + if CONF['workpath'].startswith(path): + logger.error('Specfile error: The output path "%s" contains WORKPATH (%s)', path, CONF['workpath']) + specerr += 1 + if CONF['specpath'].startswith(path): + logger.error('Specfile error: The output path "%s" contains SPECPATH (%s)', path, CONF['specpath']) + specerr += 1 + if specerr: + raise SystemExit( + 'Error: Please edit/recreate the specfile (%s) and set a different output name (e.g. "dist").' % + CONF['spec'] + ) + return True + + +def _make_clean_directory(path): + """ + Create a clean directory from the given directory name. + """ + if _check_path_overlap(path): + if os.path.isdir(path) or os.path.isfile(path): + try: + os.remove(path) + except OSError: + _rmtree(path) + + os.makedirs(path, exist_ok=True) + + +def _rmtree(path): + """ + Remove directory and all its contents, but only after user confirmation, or if the -y option is set. + """ + from PyInstaller.config import CONF + if CONF['noconfirm']: + choice = 'y' + elif sys.stdout.isatty(): + choice = input( + 'WARNING: The output directory "%s" and ALL ITS CONTENTS will be REMOVED! Continue? (y/N)' % path + ) + else: + raise SystemExit( + 'Error: The output directory "%s" is not empty. Please remove all its contents or use the -y option (remove' + ' output directory without confirmation).' % path + ) + if choice.strip().lower() == 'y': + if not CONF['noconfirm']: + print("On your own risk, you can use the option `--noconfirm` to get rid of this question.") + logger.info('Removing dir %s', path) + shutil.rmtree(path) + else: + raise SystemExit('User aborted') + + +# TODO Refactor to prohibit empty target directories. As the docstring below documents, this function currently permits +# the second item of each 2-tuple in "hook.datas" to be the empty string, in which case the target directory defaults to +# the source directory's basename. However, this functionality is very fragile and hence bad. Instead: +# +# * An exception should be raised if such item is empty. +# * All hooks currently passing the empty string for such item (e.g., +# "hooks/hook-babel.py", "hooks/hook-matplotlib.py") should be refactored +# to instead pass such basename. +def format_binaries_and_datas(binaries_or_datas, workingdir=None): + """ + Convert the passed list of hook-style 2-tuples into a returned set of `TOC`-style 2-tuples. + + Elements of the passed list are 2-tuples `(source_dir_or_glob, target_dir)`. + Elements of the returned set are 2-tuples `(target_file, source_file)`. + For backwards compatibility, the order of elements in the former tuples are the reverse of the order of elements in + the latter tuples! + + Parameters + ---------- + binaries_or_datas : list + List of hook-style 2-tuples (e.g., the top-level `binaries` and `datas` attributes defined by hooks) whose: + * The first element is either: + * A glob matching only the absolute or relative paths of source non-Python data files. + * The absolute or relative path of a source directory containing only source non-Python data files. + * The second element is the relative path of the target directory into which these source files will be + recursively copied. + + If the optional `workingdir` parameter is passed, source paths may be either absolute or relative; else, source + paths _must_ be absolute. + workingdir : str + Optional absolute path of the directory to which all relative source paths in the `binaries_or_datas` + parameter will be prepended by (and hence converted into absolute paths) _or_ `None` if these paths are to be + preserved as relative. Defaults to `None`. + + Returns + ---------- + set + Set of `TOC`-style 2-tuples whose: + * First element is the absolute or relative path of a target file. + * Second element is the absolute or relative path of the corresponding source file to be copied to this target + file. + """ + toc_datas = set() + + for src_root_path_or_glob, trg_root_dir in binaries_or_datas: + # Disallow empty source path. Those are typically result of errors, and result in implicit collection of the + # whole current working directory, which is never a good idea. + if not src_root_path_or_glob: + raise SystemExit( + "Empty SRC is not allowed when adding binary and data files, as it would result in collection of the " + "whole current working directory." + ) + if not trg_root_dir: + raise SystemExit( + "Empty DEST not allowed when adding binary and data files. Maybe you want to used %r.\nCaused by %r." % + (os.curdir, src_root_path_or_glob) + ) + # Convert relative to absolute paths if required. + if workingdir and not os.path.isabs(src_root_path_or_glob): + src_root_path_or_glob = os.path.join(workingdir, src_root_path_or_glob) + + # Normalize paths. + src_root_path_or_glob = os.path.normpath(src_root_path_or_glob) + if os.path.isfile(src_root_path_or_glob): + src_root_paths = [src_root_path_or_glob] + else: + # List of the absolute paths of all source paths matching the current glob. + src_root_paths = glob.glob(src_root_path_or_glob) + + if not src_root_paths: + msg = 'Unable to find "%s" when adding binary and data files.' % src_root_path_or_glob + # on Debian/Ubuntu, missing pyconfig.h files can be fixed with installing python-dev + if src_root_path_or_glob.endswith("pyconfig.h"): + msg += """This means your Python installation does not come with proper shared library files. +This usually happens due to missing development package, or unsuitable build parameters of the Python installation. + +* On Debian/Ubuntu, you need to install Python development packages: + * apt-get install python3-dev + * apt-get install python-dev +* If you are building Python by yourself, rebuild with `--enable-shared` (or, `--enable-framework` on macOS). +""" + raise SystemExit(msg) + + for src_root_path in src_root_paths: + if os.path.isfile(src_root_path): + # Normalizing the result to remove redundant relative paths (e.g., removing "./" from "trg/./file"). + toc_datas.add(( + os.path.normpath(os.path.join(trg_root_dir, os.path.basename(src_root_path))), + os.path.normpath(src_root_path), + )) + elif os.path.isdir(src_root_path): + for src_dir, src_subdir_basenames, src_file_basenames in os.walk(src_root_path): + # Ensure the current source directory is a subdirectory of the passed top-level source directory. + # Since os.walk() does *NOT* follow symlinks by default, this should be the case. (But let's make + # sure.) + assert src_dir.startswith(src_root_path) + + # Relative path of the current target directory, obtained by: + # + # * Stripping the top-level source directory from the current source directory (e.g., removing + # "/top" from "/top/dir"). + # * Normalizing the result to remove redundant relative paths (e.g., removing "./" from + # "trg/./file"). + trg_dir = os.path.normpath(os.path.join(trg_root_dir, os.path.relpath(src_dir, src_root_path))) + + for src_file_basename in src_file_basenames: + src_file = os.path.join(src_dir, src_file_basename) + if os.path.isfile(src_file): + # Normalize the result to remove redundant relative paths (e.g., removing "./" from + # "trg/./file"). + toc_datas.add(( + os.path.normpath(os.path.join(trg_dir, src_file_basename)), os.path.normpath(src_file) + )) + + return toc_datas + + +def get_code_object(modname, filename): + """ + Get the code-object for a module. + + This is a simplifed non-performant version which circumvents __pycache__. + """ + + if filename in ('-', None): + # This is a NamespacePackage, modulegraph marks them by using the filename '-'. (But wants to use None, so + # check for None, too, to be forward-compatible.) + logger.debug('Compiling namespace package %s', modname) + txt = '#\n' + code_object = compile(txt, filename, 'exec') + else: + _, ext = os.path.splitext(filename) + ext = ext.lower() + + if ext == '.pyc': + # The module is available in binary-only form. Read the contents of .pyc file using helper function, which + # supports reading from either stand-alone or archive-embedded .pyc files. + logger.debug('Reading code object from .pyc file %s', filename) + pyc_data = _read_pyc_data(filename) + code_object = marshal.loads(pyc_data[16:]) + else: + # Assume this is a source .py file, but allow an arbitrary extension (other than .pyc, which is taken in + # the above branch). This allows entry-point scripts to have an arbitrary (or no) extension, as tested by + # the `test_arbitrary_ext` in `test_basic.py`. + logger.debug('Compiling python script/module file %s', filename) + + with open(filename, 'rb') as f: + source = f.read() + + try: + code_object = compile(source, filename, 'exec') + except SyntaxError: + logger.warning("Sytnax error while compiling %s", filename) + raise + + return code_object + + +def strip_paths_in_code(co, new_filename=None): + # Paths to remove from filenames embedded in code objects + replace_paths = sys.path + CONF['pathex'] + # Make sure paths end with os.sep and the longest paths are first + replace_paths = sorted((os.path.join(f, '') for f in replace_paths), key=len, reverse=True) + + if new_filename is None: + original_filename = os.path.normpath(co.co_filename) + for f in replace_paths: + if original_filename.startswith(f): + new_filename = original_filename[len(f):] + break + + else: + return co + + code_func = type(co) + + consts = tuple( + strip_paths_in_code(const_co, new_filename) if isinstance(const_co, code_func) else const_co + for const_co in co.co_consts + ) + + if hasattr(co, 'replace'): # is_py38 + return co.replace(co_consts=consts, co_filename=new_filename) + elif hasattr(co, 'co_kwonlyargcount'): + # co_kwonlyargcount was added in some version of Python 3 + return code_func( + co.co_argcount, co.co_kwonlyargcount, co.co_nlocals, co.co_stacksize, co.co_flags, co.co_code, consts, + co.co_names, co.co_varnames, new_filename, co.co_name, co.co_firstlineno, co.co_lnotab, co.co_freevars, + co.co_cellvars + ) + else: + return code_func( + co.co_argcount, co.co_nlocals, co.co_stacksize, co.co_flags, co.co_code, consts, co.co_names, + co.co_varnames, new_filename, co.co_name, co.co_firstlineno, co.co_lnotab, co.co_freevars, co.co_cellvars + ) + + +def _should_include_system_binary(binary_tuple, exceptions): + """ + Return True if the given binary_tuple describes a system binary that should be included. + + Exclude all system library binaries other than those with "lib-dynload" in the destination or "python" in the + source, except for those matching the patterns in the exceptions list. Intended to be used from the Analysis + exclude_system_libraries method. + """ + dest = binary_tuple[0] + if dest.startswith('lib-dynload'): + return True + src = binary_tuple[1] + if fnmatch.fnmatch(src, '*python*'): + return True + if not src.startswith('/lib') and not src.startswith('/usr/lib'): + return True + for exception in exceptions: + if fnmatch.fnmatch(dest, exception): + return True + return False + + +def compile_pymodule(name, src_path, workpath, code_cache=None): + """ + Given the TOC entry (name, path, typecode) for a pure-python module, compile the module in the specified working + directory, and return the TOC entry for collecting the byte-compiled module. No-op for typecodes other than + PYMODULE. + """ + + # Construct the target .pyc filename in the workpath + split_name = name.split(".") + if "__init__" in src_path: + # __init__ module; use "__init__" as module name, and construct parent path using all components of the + # fully-qualified name + parent_dirs = split_name + mod_basename = "__init__" + else: + # Regular module; use last component of the fully-qualified name as module name, and the rest as the parent + # path. + parent_dirs = split_name[:-1] + mod_basename = split_name[-1] + pyc_path = os.path.join(workpath, *parent_dirs, mod_basename + '.pyc') + + # If .pyc file already exists in our workpath, check if we can re-use it. For that: + # - its modification timestamp must be newer than that of the source file + # - it must be compiled for compatible python version + if os.path.exists(pyc_path): + can_reuse = False + if misc.mtime(pyc_path) > misc.mtime(src_path): + with open(pyc_path, 'rb') as fh: + can_reuse = fh.read(4) == compat.BYTECODE_MAGIC + + if can_reuse: + return pyc_path + + # Ensure the existence of parent directories for the target pyc path + os.makedirs(os.path.dirname(pyc_path), exist_ok=True) + + # Check if optional cache contains module entry + code_object = code_cache.get(name, None) if code_cache else None + + if code_object is None: + _, ext = os.path.splitext(src_path) + ext = ext.lower() + + if ext == '.py': + # Source py file; compile... + py_compile.compile(src_path, pyc_path) + # ... and read the contents + with open(pyc_path, 'rb') as fp: + pyc_data = fp.read() + elif ext == '.pyc': + # The module is available in binary-only form. Read the contents of .pyc file using helper function, which + # supports reading from either stand-alone or archive-embedded .pyc files. + pyc_data = _read_pyc_data(src_path) + else: + raise ValueError(f"Invalid python module file {src_path}; unhandled extension {ext}!") + + # Unmarshal code object; this is necessary if we want to strip paths from it + code_object = marshal.loads(pyc_data[16:]) + + # Strip code paths from the code object + code_object = strip_paths_in_code(code_object) + + # Write module file + with open(pyc_path, 'wb') as fh: + fh.write(compat.BYTECODE_MAGIC) + fh.write(struct.pack(' 2**32 + +# Distinguish specific code for various Python versions. Variables 'is_pyXY' mean that Python X.Y and up is supported. +# Keep even unsupported versions here to keep 3rd-party hooks working. +is_py35 = sys.version_info >= (3, 5) +is_py36 = sys.version_info >= (3, 6) +is_py37 = sys.version_info >= (3, 7) +is_py38 = sys.version_info >= (3, 8) +is_py39 = sys.version_info >= (3, 9) +is_py310 = sys.version_info >= (3, 10) +is_py311 = sys.version_info >= (3, 11) +is_py312 = sys.version_info >= (3, 12) + +is_win = sys.platform.startswith('win') +is_win_10 = is_win and (platform.win32_ver()[0] == '10') +is_win_wine = False # Running under Wine; determined later on. +is_cygwin = sys.platform == 'cygwin' +is_darwin = sys.platform == 'darwin' # Mac OS X + +# Unix platforms +is_linux = sys.platform.startswith('linux') +is_solar = sys.platform.startswith('sun') # Solaris +is_aix = sys.platform.startswith('aix') +is_freebsd = sys.platform.startswith('freebsd') +is_openbsd = sys.platform.startswith('openbsd') +is_hpux = sys.platform.startswith('hp-ux') + +# Some code parts are similar to several unix platforms (e.g. Linux, Solaris, AIX). +# Mac OS is not considered as unix since there are many platform-specific details for Mac in PyInstaller. +is_unix = is_linux or is_solar or is_aix or is_freebsd or is_hpux or is_openbsd + +# Linux distributions such as Alpine or OpenWRT use musl as their libc implementation and resultantly need specially +# compiled bootloaders. On musl systems, ldd with no arguments prints 'musl' and its version. +is_musl = is_linux and "musl" in subprocess.getoutput(["ldd"]) + +# macOS version +_macos_ver = tuple(int(x) for x in platform.mac_ver()[0].split('.')) if is_darwin else None + +# macOS 11 (Big Sur): if python is not compiled with Big Sur support, it ends up in compatibility mode by default, which +# is indicated by platform.mac_ver() returning '10.16'. The lack of proper Big Sur support breaks find_library() +# function from ctypes.util module, as starting with Big Sur, shared libraries are not visible on disk anymore. Support +# for the new library search mechanism was added in python 3.9 when compiled with Big Sur support. In such cases, +# platform.mac_ver() reports version as '11.x'. The behavior can be further modified via SYSTEM_VERSION_COMPAT +# environment variable; which allows explicitly enabling or disabling the compatibility mode. However, note that +# disabling the compatibility mode and using python that does not properly support Big Sur still leaves find_library() +# broken (which is a scenario that we ignore at the moment). +# The same logic applies to macOS 12 (Monterey). +is_macos_11_compat = bool(_macos_ver) and _macos_ver[0:2] == (10, 16) # Big Sur or newer in compat mode +is_macos_11_native = bool(_macos_ver) and _macos_ver[0:2] >= (11, 0) # Big Sur or newer in native mode +is_macos_11 = is_macos_11_compat or is_macos_11_native # Big Sur or newer + +# On different platforms is different file for dynamic python library. +# TODO: When removing support for is_py37, the "m" variants can be +# removed, see +_pyver = sys.version_info[:2] +if is_win or is_cygwin: + PYDYLIB_NAMES = { + 'python%d%d.dll' % _pyver, + 'libpython%d%d.dll' % _pyver, + 'libpython%d%dm.dll' % _pyver, + 'libpython%d.%d.dll' % _pyver, + 'libpython%d.%dm.dll' % _pyver + } # For MSYS2 environment +elif is_darwin: + # libpython%d.%dm.dylib for Conda virtual environment installations + PYDYLIB_NAMES = { + 'Python', '.Python', + 'Python%d' % _pyver[0], + 'libpython%d.%d.dylib' % _pyver, + 'libpython%d.%dm.dylib' % _pyver + } +elif is_aix: + # Shared libs on AIX may be archives with shared object members, hence the ".a" suffix. However, starting with + # python 2.7.11 libpython?.?.so and Python3 libpython?.?m.so files are produced. + PYDYLIB_NAMES = { + 'libpython%d.%d.a' % _pyver, + 'libpython%d.%dm.a' % _pyver, + 'libpython%d.%d.so' % _pyver, + 'libpython%d.%dm.so' % _pyver + } +elif is_freebsd: + PYDYLIB_NAMES = { + 'libpython%d.%d.so.1' % _pyver, + 'libpython%d.%dm.so.1' % _pyver, + 'libpython%d.%d.so.1.0' % _pyver, + 'libpython%d.%dm.so.1.0' % _pyver + } +elif is_openbsd: + PYDYLIB_NAMES = {'libpython%d.%d.so.0.0' % _pyver, 'libpython%d.%dm.so.0.0' % _pyver} +elif is_hpux: + PYDYLIB_NAMES = {'libpython%d.%d.so' % _pyver} +elif is_unix: + # Other *nix platforms. + # Python 2 .so library on Linux is: libpython2.7.so.1.0 + # Python 3 .so library on Linux is: libpython3.2mu.so.1.0, libpython3.3m.so.1.0 + PYDYLIB_NAMES = { + 'libpython%d.%d.so.1.0' % _pyver, + 'libpython%d.%dm.so.1.0' % _pyver, + 'libpython%d.%dmu.so.1.0' % _pyver, + 'libpython%d.%dm.so' % _pyver, + 'libpython%d.%d.so' % _pyver + } +else: + raise SystemExit('Your platform is not yet supported. Please define constant PYDYLIB_NAMES for your platform.') + +# In a virtual environment created by virtualenv (github.com/pypa/virtualenv) there exists sys.real_prefix with the path +# to the base Python installation from which the virtual environment was created. This is true regardless of the version +# of Python used to execute the virtualenv command. +# +# In a virtual environment created by the venv module available in the Python standard lib, there exists sys.base_prefix +# with the path to the base implementation. This does not exist in a virtual environment created by virtualenv. +# +# The following code creates compat.is_venv and is.virtualenv that are True when running a virtual environment, and also +# compat.base_prefix with the path to the base Python installation. + +base_prefix: str = os.path.abspath(getattr(sys, 'real_prefix', getattr(sys, 'base_prefix', sys.prefix))) +# Ensure `base_prefix` is not containing any relative parts. +is_venv = is_virtualenv = base_prefix != os.path.abspath(sys.prefix) + +# Conda environments sometimes have different paths or apply patches to packages that can affect how a hook or package +# should access resources. Method for determining conda taken from https://stackoverflow.com/questions/47610844#47610844 +is_conda = os.path.isdir(os.path.join(base_prefix, 'conda-meta')) + +# Similar to ``is_conda`` but is ``False`` using another ``venv``-like manager on top. In this case, no packages +# encountered will be conda packages meaning that the default non-conda behaviour is generally desired from PyInstaller. +is_pure_conda = os.path.isdir(os.path.join(sys.prefix, 'conda-meta')) + +# Full path to python interpreter. +python_executable = getattr(sys, '_base_executable', sys.executable) + +# Is this Python from Microsoft App Store (Windows only)? Python from Microsoft App Store has executable pointing at +# empty shims. +is_ms_app_store = is_win and os.path.getsize(python_executable) == 0 + +if is_ms_app_store: + # Locate the actual executable inside base_prefix. + python_executable = os.path.join(base_prefix, os.path.basename(python_executable)) + if not os.path.exists(python_executable): + raise SystemExit( + 'PyInstaller cannot locate real python executable belonging to Python from Microsoft App Store!' + ) + +# Bytecode magic value +BYTECODE_MAGIC = importlib.util.MAGIC_NUMBER + +# List of suffixes for Python C extension modules. +EXTENSION_SUFFIXES = importlib.machinery.EXTENSION_SUFFIXES +ALL_SUFFIXES = importlib.machinery.all_suffixes() + +# On Windows we require pywin32-ctypes. +# -> all pyinstaller modules should use win32api from PyInstaller.compat to +# ensure that it can work on MSYS2 (which requires pywin32-ctypes) +if is_win: + try: + from win32ctypes.pywin32 import pywintypes # noqa: F401, E402 + from win32ctypes.pywin32 import win32api # noqa: F401, E402 + except ImportError: + # This environment variable is set by setup.py + # - It's not an error for pywin32 to not be installed at that point + if not os.environ.get('PYINSTALLER_NO_PYWIN32_FAILURE'): + raise SystemExit( + 'PyInstaller cannot check for assembly dependencies.\n' + 'Please install pywin32-ctypes.\n\n' + 'pip install pywin32-ctypes\n' + ) + except Exception: + if sys.flags.optimize == 2: + raise SystemExit( + "pycparser, a Windows only indirect dependency of PyInstaller, is incompatible with " + "Python's \"discard docstrings\" (-OO) flag mode. For more information see:\n" + " https://github.com/pyinstaller/pyinstaller/issues/6345" + ) + raise + +# macOS's platform.architecture() can be buggy, so we do this manually here. Based off the python documentation: +# https://docs.python.org/3/library/platform.html#platform.architecture +if is_darwin: + architecture = '64bit' if sys.maxsize > 2**32 else '32bit' +else: + architecture = platform.architecture()[0] + +# Cygwin needs special handling, because platform.system() contains identifiers such as MSYS_NT-10.0-19042 and +# CYGWIN_NT-10.0-19042 that do not fit PyInstaller's OS naming scheme. Explicitly set `system` to 'Cygwin'. +system = 'Cygwin' if is_cygwin else platform.system() + +# Machine suffix for bootloader. +machine = _pyi_machine(platform.machine(), platform.system()) + + +# Wine detection and support +def is_wine_dll(filename: str | os.PathLike): + """ + Check if the given PE file is a Wine DLL (PE-converted built-in, or fake/placeholder one). + + Returns True if the given file is a Wine DLL, False if not (or if file cannot be analyzed or does not exist). + """ + _WINE_SIGNATURES = ( + b'Wine builtin DLL', # PE-converted Wine DLL + b'Wine placeholder DLL', # Fake/placeholder Wine DLL + ) + _MAX_LEN = max([len(sig) for sig in _WINE_SIGNATURES]) + + # Wine places their DLL signature in the padding area between the IMAGE_DOS_HEADER and IMAGE_NT_HEADERS. So we need + # to compare the bytes that come right after IMAGE_DOS_HEADER, i.e., after initial 64 bytes. We can read the file + # directly and avoid using the pefile library to avoid performance penalty associated with full header parsing. + try: + with open(filename, 'rb') as fp: + fp.seek(64) + signature = fp.read(_MAX_LEN) + return signature.startswith(_WINE_SIGNATURES) + except Exception: + pass + return False + + +if is_win: + try: + import ctypes.util # noqa: E402 + is_win_wine = is_wine_dll(ctypes.util.find_library('kernel32')) + except Exception: + pass + +# Set and get environment variables does not handle unicode strings correctly on Windows. + +# Acting on os.environ instead of using getenv()/setenv()/unsetenv(), as suggested in +# : "Calling putenv() directly does not change os.environ, so it is +# better to modify os.environ." (Same for unsetenv.) + + +def getenv(name: str, default: str | None = None): + """ + Returns unicode string containing value of environment variable 'name'. + """ + return os.environ.get(name, default) + + +def setenv(name: str, value: str): + """ + Accepts unicode string and set it as environment variable 'name' containing value 'value'. + """ + os.environ[name] = value + + +def unsetenv(name: str): + """ + Delete the environment variable 'name'. + """ + # Some platforms (e.g., AIX) do not support `os.unsetenv()` and thus `del os.environ[name]` has no effect on the + # real environment. For this case, we set the value to the empty string. + os.environ[name] = "" + del os.environ[name] + + +# Exec commands in subprocesses. + + +def exec_command( + *cmdargs: str, encoding: str | None = None, raise_enoent: bool | None = None, **kwargs: int | bool | list | None +): + """ + Run the command specified by the passed positional arguments, optionally configured by the passed keyword arguments. + + .. DANGER:: + **Ignore this function's return value** -- unless this command's standard output contains _only_ pathnames, in + which case this function returns the correct filesystem-encoded string expected by PyInstaller. In all other + cases, this function's return value is _not_ safely usable. Consider calling the general-purpose + `exec_command_stdout()` function instead. + + For backward compatibility, this function's return value non-portably depends on the current Python version and + passed keyword arguments: + + * Under Python 2.7, this value is an **encoded `str` string** rather than a decoded `unicode` string. This value + _cannot_ be safely used for any purpose (e.g., string manipulation or parsing), except to be passed directly to + another non-Python command. + * Under Python 3.x, this value is a **decoded `str` string**. However, even this value is _not_ necessarily + safely usable: + * If the `encoding` parameter is passed, this value is guaranteed to be safely usable. + * Else, this value _cannot_ be safely used for any purpose (e.g., string manipulation or parsing), except to be + passed directly to another non-Python command. Why? Because this value has been decoded with the encoding + specified by `sys.getfilesystemencoding()`, the encoding used by `os.fsencode()` and `os.fsdecode()` to + convert from platform-agnostic to platform-specific pathnames. This is _not_ necessarily the encoding with + which this command's standard output was encoded. Cue edge-case decoding exceptions. + + Parameters + ---------- + cmdargs : + Variadic list whose: + 1. Mandatory first element is the absolute path, relative path, or basename in the current `${PATH}` of the + command to run. + 2. Optional remaining elements are arguments to pass to this command. + encoding : str, optional + Optional keyword argument specifying the encoding with which to decode this command's standard output under + Python 3. As this function's return value should be ignored, this argument should _never_ be passed. + raise_enoent : boolean, optional + Optional keyword argument to simply raise the exception if the executing the command fails since to the command + is not found. This is useful to checking id a command exists. + + All remaining keyword arguments are passed as is to the `subprocess.Popen()` constructor. + + Returns + ---------- + str + Ignore this value. See discussion above. + """ + + proc = subprocess.Popen(cmdargs, stdout=subprocess.PIPE, **kwargs) + try: + out = proc.communicate(timeout=60)[0] + except OSError as e: + if raise_enoent and e.errno == errno.ENOENT: + raise + print('--' * 20, file=sys.stderr) + print("Error running '%s':" % " ".join(cmdargs), file=sys.stderr) + print(e, file=sys.stderr) + print('--' * 20, file=sys.stderr) + raise ExecCommandFailed("Error: Executing command failed!") from e + except subprocess.TimeoutExpired: + proc.kill() + raise + + # stdout/stderr are returned as a byte array NOT as string, so we need to convert that to proper encoding. + try: + if encoding: + out = out.decode(encoding) + else: + # If no encoding is given, assume we are reading filenames from stdout only because it is the common case. + out = os.fsdecode(out) + except UnicodeDecodeError as e: + # The sub-process used a different encoding; provide more information to ease debugging. + print('--' * 20, file=sys.stderr) + print(str(e), file=sys.stderr) + print('These are the bytes around the offending byte:', file=sys.stderr) + print('--' * 20, file=sys.stderr) + raise + return out + + +def exec_command_rc(*cmdargs: str, **kwargs: float | bool | list | None): + """ + Return the exit code of the command specified by the passed positional arguments, optionally configured by the + passed keyword arguments. + + Parameters + ---------- + cmdargs : list + Variadic list whose: + 1. Mandatory first element is the absolute path, relative path, or basename in the current `${PATH}` of the + command to run. + 2. Optional remaining elements are arguments to pass to this command. + + All keyword arguments are passed as is to the `subprocess.call()` function. + + Returns + ---------- + int + This command's exit code as an unsigned byte in the range `[0, 255]`, where 0 signifies success and all other + values signal a failure. + """ + + # 'encoding' keyword is not supported for 'subprocess.call'; remove it from kwargs. + if 'encoding' in kwargs: + kwargs.pop('encoding') + return subprocess.call(cmdargs, **kwargs) + + +def exec_command_stdout( + *command_args: str, encoding: str | None = None, **kwargs: float | str | bytes | bool | list | None +): + """ + Capture and return the standard output of the command specified by the passed positional arguments, optionally + configured by the passed keyword arguments. + + Unlike the legacy `exec_command()` and `exec_command_all()` functions, this modern function is explicitly designed + for cross-platform portability. The return value may be safely used for any purpose, including string manipulation + and parsing. + + .. NOTE:: + If this command's standard output contains _only_ pathnames, this function does _not_ return the correct + filesystem-encoded string expected by PyInstaller. If this is the case, consider calling the filesystem-specific + `exec_command()` function instead. + + Parameters + ---------- + command_args : List[str] + Variadic list whose: + 1. Mandatory first element is the absolute path, relative path, or basename in the current `${PATH}` of the + command to run. + 2. Optional remaining elements are arguments to pass to this command. + encoding : str, optional + Optional name of the encoding with which to decode this command's standard output (e.g., `utf8`), passed as a + keyword argument. If unpassed , this output will be decoded in a portable manner specific to to the current + platform, shell environment, and system settings with Python's built-in `universal_newlines` functionality. + + All remaining keyword arguments are passed as is to the `subprocess.check_output()` function. + + Returns + ---------- + str + Unicode string of this command's standard output decoded according to the "encoding" keyword argument. + """ + + # If no encoding was specified, the current locale is defaulted to. Else, an encoding was specified. To ensure this + # encoding is respected, the "universal_newlines" option is disabled if also passed. Nice, eh? + kwargs['universal_newlines'] = encoding is None + + # Standard output captured from this command as a decoded Unicode string if "universal_newlines" is enabled or an + # encoded byte array otherwise. + stdout = subprocess.check_output(command_args, **kwargs) + + # Return a Unicode string, decoded from this encoded byte array if needed. + return stdout if encoding is None else stdout.decode(encoding) + + +def exec_command_all(*cmdargs: str, encoding: str | None = None, **kwargs: int | bool | list | None): + """ + Run the command specified by the passed positional arguments, optionally configured by the passed keyword arguments. + + .. DANGER:: + **Ignore this function's return value.** If this command's standard output consists solely of pathnames, consider + calling `exec_command()`; otherwise, consider calling `exec_command_stdout()`. + + Parameters + ---------- + cmdargs : str + Variadic list whose: + 1. Mandatory first element is the absolute path, relative path, or basename in the current `${PATH}` of the + command to run. + 2. Optional remaining elements are arguments to pass to this command. + encoding : str, optional + Optional keyword argument specifying the encoding with which to decode this command's standard output. As this + function's return value should be ignored, this argument should _never_ be passed. + + All remaining keyword arguments are passed as is to the `subprocess.Popen()` constructor. + + Returns + ---------- + (int, str, str) + Ignore this 3-element tuple `(exit_code, stdout, stderr)`. See the `exec_command()` function for discussion. + """ + proc = subprocess.Popen( + cmdargs, + bufsize=-1, # Default OS buffer size. + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + **kwargs + ) + # Waits for subprocess to complete. + try: + out, err = proc.communicate(timeout=60) + except subprocess.TimeoutExpired: + proc.kill() + raise + # stdout/stderr are returned as a byte array NOT as string. Thus we need to convert that to proper encoding. + try: + if encoding: + out = out.decode(encoding) + err = err.decode(encoding) + else: + # If no encoding is given, assume we're reading filenames from stdout only because it's the common case. + out = os.fsdecode(out) + err = os.fsdecode(err) + except UnicodeDecodeError as e: + # The sub-process used a different encoding, provide more information to ease debugging. + print('--' * 20, file=sys.stderr) + print(str(e), file=sys.stderr) + print('These are the bytes around the offending byte:', file=sys.stderr) + print('--' * 20, file=sys.stderr) + raise + + return proc.returncode, out, err + + +def __wrap_python(args, kwargs): + cmdargs = [sys.executable] + + # Mac OS X supports universal binaries (binary for multiple architectures. We need to ensure that subprocess + # binaries are running for the same architecture as python executable. It is necessary to run binaries with 'arch' + # command. + if is_darwin: + if architecture == '64bit': + if platform.machine() == 'arm64': + py_prefix = ['arch', '-arm64'] # Apple M1 + else: + py_prefix = ['arch', '-x86_64'] # Intel + elif architecture == '32bit': + py_prefix = ['arch', '-i386'] + else: + py_prefix = [] + # Since Mac OS 10.11, the environment variable DYLD_LIBRARY_PATH is no more inherited by child processes, so we + # proactively propagate the current value using the `-e` option of the `arch` command. + if 'DYLD_LIBRARY_PATH' in os.environ: + path = os.environ['DYLD_LIBRARY_PATH'] + py_prefix += ['-e', 'DYLD_LIBRARY_PATH=%s' % path] + cmdargs = py_prefix + cmdargs + + if not __debug__: + cmdargs.append('-O') + + cmdargs.extend(args) + + env = kwargs.get('env') + if env is None: + env = dict(**os.environ) + + # Ensure python 3 subprocess writes 'str' as utf-8 + env['PYTHONIOENCODING'] = 'UTF-8' + # ... and ensure we read output as utf-8 + kwargs['encoding'] = 'UTF-8' + + return cmdargs, kwargs + + +def exec_python(*args: str, **kwargs: str | None): + """ + Wrap running python script in a subprocess. + + Return stdout of the invoked command. + """ + cmdargs, kwargs = __wrap_python(args, kwargs) + return exec_command(*cmdargs, **kwargs) + + +def exec_python_rc(*args: str, **kwargs: str | None): + """ + Wrap running python script in a subprocess. + + Return exit code of the invoked command. + """ + cmdargs, kwargs = __wrap_python(args, kwargs) + return exec_command_rc(*cmdargs, **kwargs) + + +# Path handling. + + +def expand_path(path: str | os.PathLike): + """ + Replace initial tilde '~' in path with user's home directory, and also expand environment variables + (i.e., ${VARNAME} on Unix, %VARNAME% on Windows). + """ + return os.path.expandvars(os.path.expanduser(path)) + + +# Site-packages functions - use native function if available. +def getsitepackages(prefixes: list | None = None): + """ + Returns a list containing all global site-packages directories. + + For each directory present in ``prefixes`` (or the global ``PREFIXES``), this function finds its `site-packages` + subdirectory depending on the system environment, and returns a list of full paths. + """ + # This implementation was copied from the ``site`` module, python 3.7.3. + sitepackages = [] + seen = set() + + if prefixes is None: + prefixes = [sys.prefix, sys.exec_prefix] + + for prefix in prefixes: + if not prefix or prefix in seen: + continue + seen.add(prefix) + + if os.sep == '/': + sitepackages.append(os.path.join(prefix, "lib", "python%d.%d" % sys.version_info[:2], "site-packages")) + else: + sitepackages.append(prefix) + sitepackages.append(os.path.join(prefix, "lib", "site-packages")) + return sitepackages + + +# Backported for virtualenv. Module 'site' in virtualenv might not have this attribute. +getsitepackages = getattr(site, 'getsitepackages', getsitepackages) + + +# Wrapper to load a module from a Python source file. This function loads import hooks when processing them. +def importlib_load_source(name: str, pathname: str): + # Import module from a file. + mod_loader = importlib.machinery.SourceFileLoader(name, pathname) + return mod_loader.load_module() + + +# Patterns of module names that should be bundled into the base_library.zip to be available during bootstrap. +# These modules include direct or indirect dependencies of encodings.* modules. The encodings modules must be +# recursively included to set the I/O encoding during python startup. Similarly, this list should include +# modules used by PyInstaller's bootstrap scripts and modules (loader/pyi*.py) + +PY3_BASE_MODULES = { + '_collections_abc', + '_weakrefset', + 'abc', + 'codecs', + 'collections', + 'copyreg', + 'encodings', + 'enum', + 'fnmatch', # dependency of pathlib + 'functools', + 'genericpath', # dependency of os.path + 'io', # used by loader/pymod02_importers.py + 'heapq', + 'keyword', + 'linecache', + 'locale', + 'ntpath', # dependency of os.path + 'operator', + 'os', + 'pathlib', # used by loader/pymod02_importers.py + 'posixpath', # dependency of os.path + 're', + 'reprlib', + 'sre_compile', + 'sre_constants', + 'sre_parse', + 'stat', # dependency of os.path + 'token', # depdendency of tokenize + 'tokenize', # used by loader/pymod02_importers.py + 'traceback', # for startup errors + 'types', + 'urllib', # dependency of pathlib + 'weakref', + 'warnings', +} + +if not is_py310: + PY3_BASE_MODULES.add('_bootlocale') + +if sys.version_info >= (3, 11, 4): + # required by loader/pymod02_importers.py -> pathlib -> urllib + PY3_BASE_MODULES.add('ipaddress') + +# Object types of Pure Python modules in modulegraph dependency graph. +# Pure Python modules have code object (attribute co_code). +PURE_PYTHON_MODULE_TYPES = { + 'SourceModule', + 'CompiledModule', + 'Package', + 'NamespacePackage', + # Deprecated. + # TODO Could these module types be removed? + 'FlatPackage', + 'ArchiveModule', +} +# Object types of special Python modules (built-in, run-time, namespace package) in modulegraph dependency graph that do +# not have code object. +SPECIAL_MODULE_TYPES = { + 'AliasNode', + 'BuiltinModule', + 'RuntimeModule', + 'RuntimePackage', + + # PyInstaller handles scripts differently and not as standard Python modules. + 'Script', +} +# Object types of Binary Python modules (extensions, etc) in modulegraph dependency graph. +BINARY_MODULE_TYPES = { + 'Extension', + 'ExtensionPackage', +} +# Object types of valid Python modules in modulegraph dependency graph. +VALID_MODULE_TYPES = PURE_PYTHON_MODULE_TYPES | SPECIAL_MODULE_TYPES | BINARY_MODULE_TYPES +# Object types of bad/missing/invalid Python modules in modulegraph dependency graph. +# TODO: should be 'Invalid' module types also in the 'MISSING' set? +BAD_MODULE_TYPES = { + 'BadModule', + 'ExcludedModule', + 'InvalidSourceModule', + 'InvalidCompiledModule', + 'MissingModule', + + # Runtime modules and packages are technically valid rather than bad, but exist only in-memory rather than on-disk + # (typically due to pre_safe_import_module() hooks), and hence cannot be physically frozen. For simplicity, these + # nodes are categorized as bad rather than valid. + 'RuntimeModule', + 'RuntimePackage', +} +ALL_MODULE_TYPES = VALID_MODULE_TYPES | BAD_MODULE_TYPES +# TODO: review this mapping to TOC, remove useless entries. +# Dictionary to map ModuleGraph node types to TOC typecodes. +MODULE_TYPES_TO_TOC_DICT = { + # Pure modules. + 'AliasNode': 'PYMODULE', + 'Script': 'PYSOURCE', + 'SourceModule': 'PYMODULE', + 'CompiledModule': 'PYMODULE', + 'Package': 'PYMODULE', + 'FlatPackage': 'PYMODULE', + 'ArchiveModule': 'PYMODULE', + # Binary modules. + 'Extension': 'EXTENSION', + 'ExtensionPackage': 'EXTENSION', + # Special valid modules. + 'BuiltinModule': 'BUILTIN', + 'NamespacePackage': 'PYMODULE', + # Bad modules. + 'BadModule': 'bad', + 'ExcludedModule': 'excluded', + 'InvalidSourceModule': 'invalid', + 'InvalidCompiledModule': 'invalid', + 'MissingModule': 'missing', + 'RuntimeModule': 'runtime', + 'RuntimePackage': 'runtime', + # Other. + 'does not occur': 'BINARY', +} + + +def check_requirements(): + """ + Verify that all requirements to run PyInstaller are met. + + Fail hard if any requirement is not met. + """ + # Fail hard if Python does not have minimum required version + if sys.version_info < (3, 7): + raise EnvironmentError('PyInstaller requires at Python 3.7 or newer.') + + # There are some old packages which used to be backports of libraries which are now part of the standard library. + # These backports are now unmaintained and contain only an older subset of features leading to obscure errors like + # "enum has not attribute IntFlag" if installed. + if is_py38: + from importlib.metadata import distribution, PackageNotFoundError + else: + from importlib_metadata import distribution, PackageNotFoundError + + for name in ["enum34", "typing", "pathlib"]: + try: + dist = distribution(name) + except PackageNotFoundError: + continue + remove = "conda remove" if is_conda else f'"{sys.executable}" -m pip uninstall {name}' + raise SystemExit( + f"The '{name}' package is an obsolete backport of a standard library package and is incompatible with " + f"PyInstaller. Please remove this package (located in {dist.locate_file('')}) using\n {remove}\n" + "then try again." + ) + + # Bail out if binutils is not installed. + if is_linux and shutil.which("objdump") is None: + raise SystemExit( + "On Linux, objdump is required. It is typically provided by the 'binutils' package " + "installable via your Linux distribution's package manager." + ) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/config.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/config.py new file mode 100755 index 000000000..e6cb6956f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/config.py @@ -0,0 +1,56 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +This module holds run-time PyInstaller configuration. + +Variable CONF is a dict() with all configuration options that are necessary for the build phase. Build phase is done by +passing .spec file to exec() function. CONF variable is the only way how to pass arguments to exec() and how to avoid +using 'global' variables. + +NOTE: Having 'global' variables does not play well with the test suite because it does not provide isolated environments +for tests. Some tests might fail in this case. + +NOTE: The 'CONF' dict() is cleaned after building phase to not interfere with any other possible test. + +To pass any arguments to build phase, just do: + + from PyInstaller.config import CONF + CONF['my_var_name'] = my_value + +And to use this variable in the build phase: + + from PyInstaller.config import CONF + foo = CONF['my_var_name'] + + +This is the list of known variables. (Please update it if necessary.) + +cachedir +hiddenimports +noconfirm +pathex +ui_admin +ui_access +upx_available +upx_dir +workpath + +tests_modgraph - cached PyiModuleGraph object to speed up tests + +code_cache - dictionary associating `Analysis.pure` list instances with code cache dictionaries. Used by PYZ writer. +""" + +# NOTE: Do not import other PyInstaller modules here. Just define constants here. + +CONF = { + # Unit tests require this key to exist. + 'pathex': [], +} diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/configure.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/configure.py new file mode 100755 index 000000000..6bb50cad0 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/configure.py @@ -0,0 +1,107 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Configure PyInstaller for the current Python installation. +""" + +import os +import subprocess + +from PyInstaller import compat +from PyInstaller import log as logging + +logger = logging.getLogger(__name__) + + +def _check_upx_availability(upx_dir): + logger.debug('Testing UPX availability ...') + + upx_exe = "upx" + if upx_dir: + upx_exe = os.path.normpath(os.path.join(upx_dir, upx_exe)) + + # Check if we can call `upx -V`. + try: + output = subprocess.check_output( + [upx_exe, '-V'], + stdin=subprocess.DEVNULL, + stderr=subprocess.DEVNULL, + universal_newlines=True, + ) + except Exception: + logger.debug('UPX is not available.') + return False + + # Read the first line to display version string + try: + version_string = output.splitlines()[0] + except IndexError: + version_string = 'version string unavailable' + + logger.debug('UPX is available: %s', version_string) + return True + + +def _get_pyinstaller_cache_dir(): + old_cache_dir = None + if compat.getenv('PYINSTALLER_CONFIG_DIR'): + cache_dir = compat.getenv('PYINSTALLER_CONFIG_DIR') + elif compat.is_win: + cache_dir = compat.getenv('LOCALAPPDATA') + if not cache_dir: + cache_dir = os.path.expanduser('~\\Application Data') + elif compat.is_darwin: + cache_dir = os.path.expanduser('~/Library/Application Support') + else: + # According to XDG specification: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html + old_cache_dir = compat.getenv('XDG_DATA_HOME') + if not old_cache_dir: + old_cache_dir = os.path.expanduser('~/.local/share') + cache_dir = compat.getenv('XDG_CACHE_HOME') + if not cache_dir: + cache_dir = os.path.expanduser('~/.cache') + cache_dir = os.path.join(cache_dir, 'pyinstaller') + # Move old cache-dir, if any, to new location. + if old_cache_dir and not os.path.exists(cache_dir): + old_cache_dir = os.path.join(old_cache_dir, 'pyinstaller') + if os.path.exists(old_cache_dir): + parent_dir = os.path.dirname(cache_dir) + if not os.path.exists(parent_dir): + os.makedirs(parent_dir) + os.rename(old_cache_dir, cache_dir) + return cache_dir + + +def get_config(upx_dir=None): + config = {} + + config['cachedir'] = _get_pyinstaller_cache_dir() + config['upx_dir'] = upx_dir + + # Disable UPX on non-Windows. Using UPX (3.96) on modern Linux shared libraries (for example, the python3.x.so + # shared library) seems to result in segmentation fault when they are dlopen'd. This happens in recent versions + # of Fedora and Ubuntu linux, as well as in Alpine containers. On macOS, UPX (3.96) fails with + # UnknownExecutableFormatException on most .dylibs (and interferes with code signature on other occasions). And + # even when it would succeed, compressed libraries cannot be (re)signed due to failed strict validation. + upx_available = _check_upx_availability(upx_dir) + if upx_available: + if compat.is_win or compat.is_cygwin: + logger.info("UPX is available and will be used if enabled on build targets.") + elif os.environ.get("PYINSTALLER_FORCE_UPX", "0") != "0": + logger.warning( + "UPX is available and force-enabled on platform with known compatibility problems - use at own risk!" + ) + else: + upx_available = False + logger.info("UPX is available but is disabled on non-Windows due to known compatibility problems.") + config['upx_available'] = upx_available + + return config diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/__init__.py new file mode 100755 index 000000000..792d60054 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/__init__.py @@ -0,0 +1 @@ +# diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/analysis.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/analysis.py new file mode 100755 index 000000000..5d68cee30 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/analysis.py @@ -0,0 +1,946 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Define a modified ModuleGraph that can return its contents as a TOC and in other ways act like the old ImpTracker. +TODO: This class, along with TOC and Tree, should be in a separate module. + +For reference, the ModuleGraph node types and their contents: + + nodetype identifier filename + + Script full path to .py full path to .py + SourceModule basename full path to .py + BuiltinModule basename None + CompiledModule basename full path to .pyc + Extension basename full path to .so + MissingModule basename None + Package basename full path to __init__.py + packagepath is ['path to package'] + globalnames is set of global names __init__.py defines + ExtensionPackage basename full path to __init__.{so,dll} + packagepath is ['path to package'] + +The main extension here over ModuleGraph is a method to extract nodes from the flattened graph and return them as a +TOC, or added to a TOC. Other added methods look up nodes by identifier and return facts about them, replacing what +the old ImpTracker list could do. +""" + +import ast +import os +import re +import sys +import traceback +from collections import defaultdict +from copy import deepcopy + +from PyInstaller import HOMEPATH, PACKAGEPATH +from PyInstaller import log as logging +from PyInstaller.building.utils import add_suffix_to_extension +from PyInstaller.compat import ( + BAD_MODULE_TYPES, BINARY_MODULE_TYPES, MODULE_TYPES_TO_TOC_DICT, PURE_PYTHON_MODULE_TYPES, PY3_BASE_MODULES, + VALID_MODULE_TYPES, importlib_load_source, is_win +) +from PyInstaller.depend import bytecode +from PyInstaller.depend.imphook import AdditionalFilesCache, ModuleHookCache +from PyInstaller.depend.imphookapi import (PreFindModulePathAPI, PreSafeImportModuleAPI) +from PyInstaller.lib.modulegraph.find_modules import get_implies +from PyInstaller.lib.modulegraph.modulegraph import ModuleGraph, DEFAULT_IMPORT_LEVEL, ABSOLUTE_IMPORT_LEVEL +from PyInstaller.log import DEBUG, INFO, TRACE +from PyInstaller.utils.hooks import collect_submodules, is_package + +logger = logging.getLogger(__name__) + + +class PyiModuleGraph(ModuleGraph): + """ + Directed graph whose nodes represent modules and edges represent dependencies between these modules. + + This high-level subclass wraps the lower-level `ModuleGraph` class with support for graph and runtime hooks. + While each instance of `ModuleGraph` represents a set of disconnected trees, each instance of this class *only* + represents a single connected tree whose root node is the Python script originally passed by the user on the + command line. For that reason, while there may (and typically do) exist more than one `ModuleGraph` instance, + there typically exists only a singleton instance of this class. + + Attributes + ---------- + _hooks : ModuleHookCache + Dictionary mapping the fully-qualified names of all modules with normal (post-graph) hooks to the absolute paths + of such hooks. See the the `_find_module_path()` method for details. + _hooks_pre_find_module_path : ModuleHookCache + Dictionary mapping the fully-qualified names of all modules with pre-find module path hooks to the absolute + paths of such hooks. See the the `_find_module_path()` method for details. + _hooks_pre_safe_import_module : ModuleHookCache + Dictionary mapping the fully-qualified names of all modules with pre-safe import module hooks to the absolute + paths of such hooks. See the `_safe_import_module()` method for details. + _user_hook_dirs : list + List of the absolute paths of all directories containing user-defined hooks for the current application. + _excludes : list + List of module names to be excluded when searching for dependencies. + _additional_files_cache : AdditionalFilesCache + Cache of all external dependencies (e.g., binaries, datas) listed in hook scripts for imported modules. + _module_collection_mode : dict + A dictionary of module/package collection mode settings set by hook scripts for their modules. + _base_modules: list + Dependencies for `base_library.zip` (which remain the same for every executable). + """ + + # Note: these levels are completely arbitrary and may be adjusted if needed. + LOG_LEVEL_MAPPING = {0: INFO, 1: DEBUG, 2: TRACE, 3: TRACE, 4: TRACE} + + def __init__(self, pyi_homepath, user_hook_dirs=(), excludes=(), **kwargs): + super().__init__(excludes=excludes, **kwargs) + # Homepath to the place where is PyInstaller located. + self._homepath = pyi_homepath + # modulegraph Node for the main python script that is analyzed by PyInstaller. + self._top_script_node = None + + # Absolute paths of all user-defined hook directories. + self._excludes = excludes + self._reset(user_hook_dirs) + self._analyze_base_modules() + + def _reset(self, user_hook_dirs): + """ + Reset for another set of scripts. This is primary required for running the test-suite. + """ + self._top_script_node = None + self._additional_files_cache = AdditionalFilesCache() + self._module_collection_mode = dict() + # Command line, Entry Point, and then builtin hook dirs. + self._user_hook_dirs = [*user_hook_dirs, os.path.join(PACKAGEPATH, 'hooks')] + # Hook-specific lookup tables. These need to reset when reusing cached PyiModuleGraph to avoid hooks to refer to + # files or data from another test-case. + logger.info('Caching module graph hooks...') + self._hooks = self._cache_hooks("") + self._hooks_pre_safe_import_module = self._cache_hooks('pre_safe_import_module') + self._hooks_pre_find_module_path = self._cache_hooks('pre_find_module_path') + + # Search for run-time hooks in all hook directories. + self._available_rthooks = defaultdict(list) + for uhd in self._user_hook_dirs: + uhd_path = os.path.abspath(os.path.join(uhd, 'rthooks.dat')) + try: + with open(uhd_path, 'r', encoding='utf-8') as f: + rthooks = ast.literal_eval(f.read()) + except FileNotFoundError: + # Ignore if this hook path doesn't have run-time hooks. + continue + except Exception as e: + logger.error('Unable to read run-time hooks from %r: %s' % (uhd_path, e)) + continue + + self._merge_rthooks(rthooks, uhd, uhd_path) + + # Convert back to a standard dict. + self._available_rthooks = dict(self._available_rthooks) + + def _merge_rthooks(self, rthooks, uhd, uhd_path): + """ + The expected data structure for a run-time hook file is a Python dictionary of type ``Dict[str, List[str]]``, + where the dictionary keys are module names and the sequence strings are Python file names. + + Check then merge this data structure, updating the file names to be absolute. + """ + # Check that the root element is a dict. + assert isinstance(rthooks, dict), 'The root element in %s must be a dict.' % uhd_path + for module_name, python_file_name_list in rthooks.items(): + # Ensure the key is a string. + assert isinstance(module_name, str), \ + '%s must be a dict whose keys are strings; %s is not a string.' % (uhd_path, module_name) + # Ensure the value is a list. + assert isinstance(python_file_name_list, list), \ + 'The value of %s key %s must be a list.' % (uhd_path, module_name) + if module_name in self._available_rthooks: + logger.warning( + 'Runtime hooks for %s have already been defined. Skipping the runtime hooks for %s that are ' + 'defined in %s.', module_name, module_name, os.path.join(uhd, 'rthooks') + ) + # Skip this module + continue + # Merge this with existing run-time hooks. + for python_file_name in python_file_name_list: + # Ensure each item in the list is a string. + assert isinstance(python_file_name, str), \ + '%s key %s, item %r must be a string.' % (uhd_path, module_name, python_file_name) + # Transform it into an absolute path. + abs_path = os.path.join(uhd, 'rthooks', python_file_name) + # Make sure this file exists. + assert os.path.exists(abs_path), \ + 'In %s, key %s, the file %r expected to be located at %r does not exist.' % \ + (uhd_path, module_name, python_file_name, abs_path) + # Merge it. + self._available_rthooks[module_name].append(abs_path) + + @staticmethod + def _findCaller(*args, **kwargs): + # Used to add an additional stack-frame above logger.findCaller. findCaller expects the caller to be three + # stack-frames above itself. + return logger.findCaller(*args, **kwargs) + + def msg(self, level, s, *args): + """ + Print a debug message with the given level. + + 1. Map the msg log level to a logger log level. + 2. Generate the message format (the same format as ModuleGraph) + 3. Find the caller, which findCaller expects three stack-frames above itself: + [3] caller -> [2] msg (here) -> [1] _findCaller -> [0] logger.findCaller + 4. Create a logRecord with the caller's information. + 5. Handle the logRecord. + """ + try: + level = self.LOG_LEVEL_MAPPING[level] + except KeyError: + return + if not logger.isEnabledFor(level): + return + + msg = "%s %s" % (s, ' '.join(map(repr, args))) + + try: + fn, lno, func, sinfo = self._findCaller() + except ValueError: # pragma: no cover + fn, lno, func, sinfo = "(unknown file)", 0, "(unknown function)", None + record = logger.makeRecord(logger.name, level, fn, lno, msg, [], None, func, None, sinfo) + + logger.handle(record) + + # Set logging methods so that the stack is correctly detected. + msgin = msg + msgout = msg + + def _cache_hooks(self, hook_type): + """ + Get a cache of all hooks of the passed type. + + The cache will include all official hooks defined by the PyInstaller codebase _and_ all unofficial hooks + defined for the current application. + + Parameters + ---------- + hook_type : str + Type of hooks to be cached, equivalent to the basename of the subpackage of the `PyInstaller.hooks` + package containing such hooks (e.g., `post_create_package` for post-create package hooks). + """ + # Cache of this type of hooks. + hook_dirs = [] + for user_hook_dir in self._user_hook_dirs: + # Absolute path of the user-defined subdirectory of this hook type. If this directory exists, add it to the + # list to be cached. + user_hook_type_dir = os.path.join(user_hook_dir, hook_type) + if os.path.isdir(user_hook_type_dir): + hook_dirs.append(user_hook_type_dir) + + return ModuleHookCache(self, hook_dirs) + + def _analyze_base_modules(self): + """ + Analyze dependencies of the the modules in base_library.zip. + """ + logger.info('Analyzing base_library.zip ...') + required_mods = [] + # Collect submodules from required modules in base_library.zip. + for m in PY3_BASE_MODULES: + if is_package(m): + required_mods += collect_submodules(m) + else: + required_mods.append(m) + # Initialize ModuleGraph. + self._base_modules = [mod for req in required_mods for mod in self.import_hook(req)] + + def add_script(self, pathname, caller=None): + """ + Wrap the parent's 'run_script' method and create graph from the first script in the analysis, and save its + node to use as the "caller" node for all others. This gives a connected graph rather than a collection of + unrelated trees. + """ + if self._top_script_node is None: + # Remember the node for the first script. + try: + self._top_script_node = super().add_script(pathname) + except SyntaxError: + print("\nSyntax error in", pathname, file=sys.stderr) + formatted_lines = traceback.format_exc().splitlines(True) + print(*formatted_lines[-4:], file=sys.stderr) + sys.exit(1) + # Create references from the top script to the base_modules in graph. + for node in self._base_modules: + self.add_edge(self._top_script_node, node) + # Return top-level script node. + return self._top_script_node + else: + if not caller: + # Defaults to as any additional script is called from the top-level script. + caller = self._top_script_node + return super().add_script(pathname, caller=caller) + + def process_post_graph_hooks(self, analysis): + """ + For each imported module, run this module's post-graph hooks if any. + + Parameters + ---------- + analysis: build_main.Analysis + The Analysis that calls the hooks + + """ + # For each iteration of the infinite "while" loop below: + # + # 1. All hook() functions defined in cached hooks for imported modules are called. This may result in new + # modules being imported (e.g., as hidden imports) that were ignored earlier in the current iteration: if + # this is the case, all hook() functions defined in cached hooks for these modules will be called by the next + # iteration. + # 2. All cached hooks whose hook() functions were called are removed from this cache. If this cache is empty, no + # hook() functions will be called by the next iteration and this loop will be terminated. + # 3. If no hook() functions were called, this loop is terminated. + logger.info('Processing module hooks...') + while True: + # Set of the names of all imported modules whose post-graph hooks are run by this iteration, preventing the + # next iteration from re- running these hooks. If still empty at the end of this iteration, no post-graph + # hooks were run; thus, this loop will be terminated. + hooked_module_names = set() + + # For each remaining hookable module and corresponding hooks... + for module_name, module_hooks in self._hooks.items(): + # Graph node for this module if imported or "None" otherwise. + module_node = self.find_node(module_name, create_nspkg=False) + + # If this module has not been imported, temporarily ignore it. This module is retained in the cache, as + # a subsequently run post-graph hook could import this module as a hidden import. + if module_node is None: + continue + + # If this module is unimportable, permanently ignore it. + if type(module_node).__name__ not in VALID_MODULE_TYPES: + hooked_module_names.add(module_name) + continue + + # For each hook script for this module... + for module_hook in module_hooks: + # Run this script's post-graph hook. + module_hook.post_graph(analysis) + + # Cache all external dependencies listed by this script after running this hook, which could add + # dependencies. + self._additional_files_cache.add(module_name, module_hook.binaries, module_hook.datas) + + # Update package collection mode settings. + self._module_collection_mode.update(module_hook.module_collection_mode) + + # Prevent this module's hooks from being run again. + hooked_module_names.add(module_name) + + # Prevent all post-graph hooks run above from being run again by the next iteration. + self._hooks.remove_modules(*hooked_module_names) + + # If no post-graph hooks were run, terminate iteration. + if not hooked_module_names: + break + + def _find_all_excluded_imports(self, module_name): + """ + Collect excludedimports from the hooks of the specified module and all its parents. + """ + excluded_imports = set() + while module_name: + # Gather excluded imports from hook(s) belonging to the module + for module_hook in self._hooks.get(module_name, []): + excluded_imports.update(module_hook.excludedimports) + # Change module name to the module's parent name + module_name = module_name.rpartition('.')[0] + return excluded_imports + + def _safe_import_hook( + self, target_module_partname, source_module, target_attr_names, level=DEFAULT_IMPORT_LEVEL, edge_attr=None + ): + if source_module is not None: + # Gather all excluded imports for the referring modules, as well as its parents. + # For example, we want the excluded imports specified by hook for PIL to be also applied when the referring + # module is its submodule, PIL.Image. + excluded_imports = self._find_all_excluded_imports(source_module.identifier) + + # Apply extra processing only if we have any excluded-imports rules + if excluded_imports: + # Resolve the base module name. Level can be ABSOLUTE_IMPORT_LEVEL (= 0) for absolute imports, or an + # integer indicating the relative level. We do not use equality comparison just in case we ever happen + # to get ABSOLUTE_OR_RELATIVE_IMPORT_LEVEL (-1), which is a remnant of python2 days. + if level > ABSOLUTE_IMPORT_LEVEL: + if target_module_partname: + base_module_name = source_module.identifier + '.' + target_module_partname + else: + base_module_name = source_module.identifier + + # Adjust the base module name based on level + if level > 1: + base_module_name = '.'.join(base_module_name.split('.')[:-(level - 1)]) + else: + base_module_name = target_module_partname + + def _exclude_module(module_name, excluded_imports): + """ + Helper for checking whether given module should be excluded. + Returns the name of exclusion rule if module should be excluded, None otherwise. + """ + module_name_parts = module_name.split('.') + for excluded_import in excluded_imports: + excluded_import_parts = excluded_import.split('.') + match = module_name_parts[:len(excluded_import_parts)] == excluded_import_parts + if match: + return excluded_import + return None + + # First, check if base module name is to be excluded. + # This covers both basic `import a` and `import a.b.c`, as well as `from d import e, f` where base + # module `d` is excluded. + excluded_import_rule = _exclude_module(base_module_name, excluded_imports) + if excluded_import_rule: + logger.debug( + "Suppressing import of %r from module %r due to excluded import %r specified in a hook for %r " + "(or its parent package(s)).", base_module_name, source_module.identifier, excluded_import_rule, + source_module.identifier + ) + return [] + + # If we have target attribute names, check each of them, and remove excluded ones from the + # `target_attr_names` list. + if target_attr_names: + filtered_target_attr_names = [] + for target_attr_name in target_attr_names: + submodule_name = base_module_name + '.' + target_attr_name + excluded_import_rule = _exclude_module(submodule_name, excluded_imports) + if excluded_import_rule: + logger.debug( + "Suppressing import of %r from module %r due to excluded import %r specified in a hook " + "for %r (or its parent package(s)).", submodule_name, source_module.identifier, + excluded_import_rule, source_module.identifier + ) + else: + filtered_target_attr_names.append(target_attr_name) + + # Swap with filtered target attribute names list; if no elements remain after the filtering, pass + # None... + target_attr_names = filtered_target_attr_names or None + + return super()._safe_import_hook(target_module_partname, source_module, target_attr_names, level, edge_attr) + + def _safe_import_module(self, module_basename, module_name, parent_package): + """ + Create a new graph node for the module with the passed name under the parent package signified by the passed + graph node. + + This method wraps the superclass method with support for pre-import module hooks. If such a hook exists for + this module (e.g., a script `PyInstaller.hooks.hook-{module_name}` containing a function + `pre_safe_import_module()`), that hook will be run _before_ the superclass method is called. + + Pre-Safe-Import-Hooks are performed just *prior* to importing the module. When running the hook, the modules + parent package has already been imported and ti's `__path__` is set up. But the module is just about to be + imported. + + See the superclass method for description of parameters and return value. + """ + # If this module has pre-safe import module hooks, run these first. + if module_name in self._hooks_pre_safe_import_module: + # For the absolute path of each such hook... + for hook in self._hooks_pre_safe_import_module[module_name]: + # Dynamically import this hook as a fabricated module. + logger.info('Processing pre-safe import module hook %s from %r.', module_name, hook.hook_filename) + hook_module_name = 'PyInstaller_hooks_pre_safe_import_module_' + module_name.replace('.', '_') + hook_module = importlib_load_source(hook_module_name, hook.hook_filename) + + # Object communicating changes made by this hook back to us. + hook_api = PreSafeImportModuleAPI( + module_graph=self, + module_basename=module_basename, + module_name=module_name, + parent_package=parent_package, + ) + + # Run this hook, passed this object. + if not hasattr(hook_module, 'pre_safe_import_module'): + raise NameError('pre_safe_import_module() function not defined by hook %r.' % hook_module) + hook_module.pre_safe_import_module(hook_api) + + # Respect method call changes requested by this hook. + module_basename = hook_api.module_basename + module_name = hook_api.module_name + + # Prevent subsequent calls from rerunning these hooks. + del self._hooks_pre_safe_import_module[module_name] + + # Call the superclass method. + return super()._safe_import_module(module_basename, module_name, parent_package) + + def _find_module_path(self, fullname, module_name, search_dirs): + """ + Get a 3-tuple detailing the physical location of the module with the passed name if that module exists _or_ + raise `ImportError` otherwise. + + This method wraps the superclass method with support for pre-find module path hooks. If such a hook exists + for this module (e.g., a script `PyInstaller.hooks.hook-{module_name}` containing a function + `pre_find_module_path()`), that hook will be run _before_ the superclass method is called. + + See superclass method for parameter and return value descriptions. + """ + # If this module has pre-find module path hooks, run these first. + if fullname in self._hooks_pre_find_module_path: + # For the absolute path of each such hook... + for hook in self._hooks_pre_find_module_path[fullname]: + # Dynamically import this hook as a fabricated module. + logger.info('Processing pre-find module path hook %s from %r.', fullname, hook.hook_filename) + hook_fullname = 'PyInstaller_hooks_pre_find_module_path_' + fullname.replace('.', '_') + hook_module = importlib_load_source(hook_fullname, hook.hook_filename) + + # Object communicating changes made by this hook back to us. + hook_api = PreFindModulePathAPI( + module_graph=self, + module_name=fullname, + search_dirs=search_dirs, + ) + + # Run this hook, passed this object. + if not hasattr(hook_module, 'pre_find_module_path'): + raise NameError('pre_find_module_path() function not defined by hook %r.' % hook_module) + hook_module.pre_find_module_path(hook_api) + + # Respect method call changes requested by this hook. + search_dirs = hook_api.search_dirs + + # Prevent subsequent calls from rerunning these hooks. + del self._hooks_pre_find_module_path[fullname] + + # Call the superclass method. + return super()._find_module_path(fullname, module_name, search_dirs) + + def get_code_objects(self): + """ + Get code objects from ModuleGraph for pure Python modules. This allows to avoid writing .pyc/pyo files to hdd + at later stage. + + :return: Dict with module name and code object. + """ + code_dict = {} + mod_types = PURE_PYTHON_MODULE_TYPES + for node in self.iter_graph(start=self._top_script_node): + # TODO This is terrible. To allow subclassing, types should never be directly compared. Use isinstance() + # instead, which is safer, simpler, and accepts sets. Most other calls to type() in the codebase should also + # be refactored to call isinstance() instead. + + # get node type e.g. Script + mg_type = type(node).__name__ + if mg_type in mod_types: + if node.code: + code_dict[node.identifier] = node.code + return code_dict + + def _make_toc(self, typecode=None): + """ + Return the name, path and type of selected nodes as a TOC. The selection is determined by the given list + of PyInstaller TOC typecodes. If that list is empty we return the complete flattened graph as a TOC with the + ModuleGraph note types in place of typecodes -- meant for debugging only. Normally we return ModuleGraph + nodes whose types map to the requested PyInstaller typecode(s) as indicated in the MODULE_TYPES_TO_TOC_DICT. + + We use the ModuleGraph (really, ObjectGraph) flatten() method to scan all the nodes. This is patterned after + ModuleGraph.report(). + """ + # Construct regular expression for matching modules that should be excluded because they are bundled in + # base_library.zip. + # + # This expression matches the base module name, optionally followed by a period and then any number of + # characters. This matches the module name and the fully qualified names of any of its submodules. + regex_str = '(' + '|'.join(PY3_BASE_MODULES) + r')(\.|$)' + module_filter = re.compile(regex_str) + + toc = list() + for node in self.iter_graph(start=self._top_script_node): + # Skip modules that are in base_library.zip. + if module_filter.match(node.identifier): + continue + entry = self._node_to_toc(node, typecode) + # Append the entry. We do not check for duplicates here; the TOC normalization is left to caller. + # However, as entries are obtained from modulegraph, there should not be any duplicates at this stage. + if entry is not None: + toc.append(entry) + return toc + + def make_pure_toc(self): + """ + Return all pure Python modules formatted as TOC. + """ + # PyInstaller should handle special module types without code object. + return self._make_toc(PURE_PYTHON_MODULE_TYPES) + + def make_binaries_toc(self): + """ + Return all binary Python modules formatted as TOC. + """ + return self._make_toc(BINARY_MODULE_TYPES) + + def make_missing_toc(self): + """ + Return all MISSING Python modules formatted as TOC. + """ + return self._make_toc(BAD_MODULE_TYPES) + + @staticmethod + def _node_to_toc(node, typecode=None): + # TODO This is terrible. Everything in Python has a type. It is nonsensical to even speak of "nodes [that] are + # not typed." How would that even occur? After all, even "None" has a type! (It is "NoneType", for the curious.) + # Remove this, please. + + # Get node type, e.g., Script + mg_type = type(node).__name__ + assert mg_type is not None + + if typecode and mg_type not in typecode: + # Type is not a to be selected one, skip this one + return None + # Extract the identifier and a path if any. + if mg_type == 'Script': + # for Script nodes only, identifier is a whole path + (name, ext) = os.path.splitext(node.filename) + name = os.path.basename(name) + elif mg_type == 'ExtensionPackage': + # Package with __init__ module being an extension module. This needs to end up as e.g. 'mypkg/__init__.so'. + # Convert the packages name ('mypkg') into the module name ('mypkg.__init__') *here* to keep special cases + # away elsewhere (where the module name is converted to a filename). + name = node.identifier + ".__init__" + else: + name = node.identifier + path = node.filename if node.filename is not None else '' + # Ensure name is really 'str'. Module graph might return object type 'modulegraph.Alias' which inherits fromm + # 'str'. But 'marshal.dumps()' function is able to marshal only 'str'. Otherwise on Windows PyInstaller might + # fail with message like: + # ValueError: unmarshallable object + name = str(name) + # Translate to the corresponding TOC typecode. + toc_type = MODULE_TYPES_TO_TOC_DICT[mg_type] + return name, path, toc_type + + def nodes_to_toc(self, nodes): + """ + Given a list of nodes, create a TOC representing those nodes. This is mainly used to initialize a TOC of + scripts with the ones that are runtime hooks. The process is almost the same as _make_toc(), but the caller + guarantees the nodes are valid, so minimal checking. + """ + return [self._node_to_toc(node) for node in nodes] + + # Return true if the named item is in the graph as a BuiltinModule node. The passed name is a basename. + def is_a_builtin(self, name): + node = self.find_node(name) + if node is None: + return False + return type(node).__name__ == 'BuiltinModule' + + def get_importers(self, name): + """ + List all modules importing the module with the passed name. + + Returns a list of (identifier, DependencyIinfo)-tuples. If the names module has not yet been imported, this + method returns an empty list. + + Parameters + ---------- + name : str + Fully-qualified name of the module to be examined. + + Returns + ---------- + list + List of (fully-qualified names, DependencyIinfo)-tuples of all modules importing the module with the passed + fully-qualified name. + + """ + def get_importer_edge_data(importer): + edge = self.graph.edge_by_node(importer, name) + # edge might be None in case an AliasModule was added. + if edge is not None: + return self.graph.edge_data(edge) + + node = self.find_node(name) + if node is None: + return [] + _, importers = self.get_edges(node) + importers = (importer.identifier for importer in importers if importer is not None) + return [(importer, get_importer_edge_data(importer)) for importer in importers] + + # TODO: create a class from this function. + def analyze_runtime_hooks(self, custom_runhooks): + """ + Analyze custom run-time hooks and run-time hooks implied by found modules. + + :return : list of Graph nodes. + """ + rthooks_nodes = [] + logger.info('Analyzing run-time hooks ...') + # Process custom runtime hooks (from --runtime-hook options). The runtime hooks are order dependent. First hooks + # in the list are executed first. Put their graph nodes at the head of the priority_scripts list Pyinstaller + # defined rthooks and thus they are executed first. + if custom_runhooks: + for hook_file in custom_runhooks: + logger.info("Including custom run-time hook %r", hook_file) + hook_file = os.path.abspath(hook_file) + # Not using "try" here because the path is supposed to exist, if it does not, the raised error will + # explain. + rthooks_nodes.append(self.add_script(hook_file)) + + # Find runtime hooks that are implied by packages already imported. Get a temporary TOC listing all the scripts + # and packages graphed so far. Assuming that runtime hooks apply only to modules and packages. + temp_toc = self._make_toc(VALID_MODULE_TYPES) + for (mod_name, path, typecode) in temp_toc: + # Look if there is any run-time hook for given module. + if mod_name in self._available_rthooks: + # There could be several run-time hooks for a module. + for abs_path in self._available_rthooks[mod_name]: + logger.info("Including run-time hook %r", abs_path) + rthooks_nodes.append(self.add_script(abs_path)) + + return rthooks_nodes + + def add_hiddenimports(self, module_list): + """ + Add hidden imports that are either supplied as CLI option --hidden-import=MODULENAME or as dependencies from + some PyInstaller features when enabled (e.g., crypto feature). + """ + assert self._top_script_node is not None + # Analyze the script's hidden imports (named on the command line). + for modnm in module_list: + node = self.find_node(modnm) + if node is not None: + logger.debug('Hidden import %r already found', modnm) + else: + logger.info("Analyzing hidden import %r", modnm) + # ModuleGraph throws ImportError if import not found. + try: + nodes = self.import_hook(modnm) + assert len(nodes) == 1 + node = nodes[0] + except ImportError: + logger.error("Hidden import %r not found", modnm) + continue + # Create references from the top script to the hidden import, even if found otherwise. Do not waste time + # checking whether it is actually added by this (test-) script. + self.add_edge(self._top_script_node, node) + + def get_code_using(self, module: str) -> dict: + """ + Find modules that import a given **module**. + """ + co_dict = {} + pure_python_module_types = PURE_PYTHON_MODULE_TYPES | { + 'Script', + } + node = self.find_node(module) + if node: + referrers = self.incoming(node) + for r in referrers: + # Under python 3.7 and earlier, if `module` is added to hidden imports, one of referrers ends up being + # None, causing #3825. Work around it. + if r is None: + continue + # Ensure that modulegraph objects have 'code' attribute. + if type(r).__name__ not in pure_python_module_types: + continue + identifier = r.identifier + if identifier == module or identifier.startswith(module + '.'): + # Skip self references or references from `modules`'s own submodules. + continue + # The code object may be None if referrer ends up shadowed by eponymous directory that ends up treated + # as a namespace package. See #6873 for an example. + if r.code is None: + continue + co_dict[r.identifier] = r.code + return co_dict + + def metadata_required(self) -> set: + """ + Collect metadata for all packages that appear to need it. + """ + + # List every function that we can think of which is known to require metadata. + out = set() + + out |= self._metadata_from( + "pkg_resources", + ["get_distribution"], # Requires metadata for one distribution. + ["require"], # Requires metadata for all dependencies. + ) + + # importlib.metadata is often `import ... as` aliased to importlib_metadata for compatibility with < py38. + # Assume both are valid. + for importlib_metadata in ["importlib.metadata", "importlib_metadata"]: + out |= self._metadata_from( + importlib_metadata, + ["metadata", "distribution", "version", "files", "requires"], + [], + ) + + return out + + def _metadata_from(self, package, methods=(), recursive_methods=()) -> set: + """ + Collect metadata whose requirements are implied by given function names. + + Args: + package: + The module name that must be imported in a source file to trigger the search. + methods: + Function names from **package** which take a distribution name as an argument and imply that metadata + is required for that distribution. + recursive_methods: + Like **methods** but also implies that a distribution's dependencies' metadata must be collected too. + Returns: + Required metadata in hook data ``(source, dest)`` format as returned by + :func:`PyInstaller.utils.hooks.copy_metadata()`. + + Scan all source code to be included for usage of particular *key* functions which imply that that code will + require metadata for some distribution (which may not be its own) at runtime. In the case of a match, + collect the required metadata. + """ + from pkg_resources import DistributionNotFound + + from PyInstaller.utils.hooks import copy_metadata + + # Generate sets of possible function names to search for. + need_metadata = set() + need_recursive_metadata = set() + for method in methods: + need_metadata.update(bytecode.any_alias(package + "." + method)) + for method in recursive_methods: + need_recursive_metadata.update(bytecode.any_alias(package + "." + method)) + + out = set() + + for name, code in self.get_code_using(package).items(): + for calls in bytecode.recursive_function_calls(code).values(): + for function_name, args in calls: + # Only consider function calls taking one argument. + if len(args) != 1: + continue + package = args[0] + try: + if function_name in need_metadata: + out.update(copy_metadata(package)) + elif function_name in need_recursive_metadata: + out.update(copy_metadata(package, recursive=True)) + + except DistributionNotFound: + # Currently, we opt to silently skip over missing metadata. + continue + + return out + + def get_collected_packages(self) -> list: + """ + Return the list of collected python packages. + """ + # `node.identifier` might be an instance of `modulegraph.Alias`, hence explicit conversion to `str`. + return [ + str(node.identifier) for node in self.iter_graph(start=self._top_script_node) + if type(node).__name__ == 'Package' + ] + + +_cached_module_graph_ = None + + +def initialize_modgraph(excludes=(), user_hook_dirs=()): + """ + Create the cached module graph. + + This function might appear weird but is necessary for speeding up test runtime because it allows caching basic + ModuleGraph object that gets created for 'base_library.zip'. + + Parameters + ---------- + excludes : list + List of the fully-qualified names of all modules to be "excluded" and hence _not_ frozen into the executable. + user_hook_dirs : list + List of the absolute paths of all directories containing user-defined hooks for the current application or + `None` if no such directories were specified. + + Returns + ---------- + PyiModuleGraph + Module graph with core dependencies. + """ + # Normalize parameters to ensure tuples and make comparison work. + user_hook_dirs = user_hook_dirs or () + excludes = excludes or () + + # If there is a graph cached with the same excludes, reuse it. See ``PyiModulegraph._reset()`` for what is + # reset. This cache is used primarily to speed up the test-suite. Fixture `pyi_modgraph` calls this function with + # empty excludes, creating a graph suitable for the huge majority of tests. + global _cached_module_graph_ + if _cached_module_graph_ and _cached_module_graph_._excludes == excludes: + logger.info('Reusing cached module dependency graph...') + graph = deepcopy(_cached_module_graph_) + graph._reset(user_hook_dirs) + return graph + + logger.info('Initializing module dependency graph...') + + # Construct the initial module graph by analyzing all import statements. + graph = PyiModuleGraph( + HOMEPATH, + excludes=excludes, + # get_implies() are hidden imports known by modulgraph. + implies=get_implies(), + user_hook_dirs=user_hook_dirs, + ) + + if not _cached_module_graph_: + # Only cache the first graph, see above for explanation. + logger.info('Caching module dependency graph...') + # cache a deep copy of the graph + _cached_module_graph_ = deepcopy(graph) + # Clear data which does not need to be copied from the cached graph since it will be reset by + # ``PyiModulegraph._reset()`` anyway. + _cached_module_graph_._hooks = None + _cached_module_graph_._hooks_pre_safe_import_module = None + _cached_module_graph_._hooks_pre_find_module_path = None + + return graph + + +def get_bootstrap_modules(): + """ + Get TOC with the bootstrapping modules and their dependencies. + :return: TOC with modules + """ + # Import 'struct' modules to get real paths to module file names. + mod_struct = __import__('struct') + # Basic modules necessary for the bootstrap process. + loader_mods = list() + loaderpath = os.path.join(HOMEPATH, 'PyInstaller', 'loader') + # On some platforms (Windows, Debian/Ubuntu) '_struct' and zlib modules are built-in modules (linked statically) + # and thus does not have attribute __file__. 'struct' module is required for reading Python bytecode from + # executable. 'zlib' is required to decompress this bytecode. + for mod_name in ['_struct', 'zlib']: + mod = __import__(mod_name) # C extension. + if hasattr(mod, '__file__'): + mod_file = os.path.abspath(mod.__file__) + if os.path.basename(os.path.dirname(mod_file)) == 'lib-dynload': + # Divert extensions originating from python's lib-dynload directory, to match behavior of #5604. + mod_name = os.path.join('lib-dynload', mod_name) + loader_mods.append(add_suffix_to_extension(mod_name, mod_file, 'EXTENSION')) + loader_mods.append(('struct', os.path.abspath(mod_struct.__file__), 'PYMODULE')) + # Loader/bootstrap modules. + # NOTE: These modules should be kept simple without any complicated dependencies. + loader_mods += [ + ('pyimod01_archive', os.path.join(loaderpath, 'pyimod01_archive.py'), 'PYMODULE'), + ('pyimod02_importers', os.path.join(loaderpath, 'pyimod02_importers.py'), 'PYMODULE'), + ('pyimod03_ctypes', os.path.join(loaderpath, 'pyimod03_ctypes.py'), 'PYMODULE'), + ] + if is_win: + loader_mods.append(('pyimod04_pywin32', os.path.join(loaderpath, 'pyimod04_pywin32.py'), 'PYMODULE')) + # The bootstrap script + loader_mods.append(('pyiboot01_bootstrap', os.path.join(loaderpath, 'pyiboot01_bootstrap.py'), 'PYSOURCE')) + return loader_mods diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/bindepend.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/bindepend.py new file mode 100755 index 000000000..332d25d34 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/bindepend.py @@ -0,0 +1,1037 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Find external dependencies of binary libraries. +""" + +import collections +import ctypes.util +import os +import pathlib +import re +import sys +# Required for extracting eggs. +import zipfile +import subprocess + +from PyInstaller import compat +from PyInstaller import log as logging +from PyInstaller.depend import dylib, utils +from PyInstaller.utils.win32 import winutils + +logger = logging.getLogger(__name__) + +seen = set() + +# Import windows specific stuff. +if compat.is_win: + from distutils.sysconfig import get_python_lib + + import pefile + + from PyInstaller.utils.win32 import winmanifest, winresource + + +def getfullnameof(mod, xtrapath=None): + """ + Return the full path name of MOD. + + * MOD is the basename of a dll or pyd. + * XTRAPATH is a path or list of paths to search first. + + Return the full path name of MOD. Will search the full Windows search path, as well as sys.path + """ + pywin32_paths = [] + if compat.is_win: + pywin32_paths = [os.path.join(get_python_lib(), 'pywin32_system32')] + if compat.is_venv: + pywin32_paths.append(os.path.join(compat.base_prefix, 'Lib', 'site-packages', 'pywin32_system32')) + + epath = ( + sys.path + # Search sys.path first! + pywin32_paths + winutils.get_system_path() + compat.getenv('PATH', '').split(os.pathsep) + ) + if xtrapath is not None: + if isinstance(xtrapath, str): + epath.insert(0, xtrapath) + else: + epath = xtrapath + epath + for p in epath: + npth = os.path.join(p, mod) + if os.path.exists(npth) and matchDLLArch(npth): + return npth + return '' + + +def _getImports_pe(pth): + """ + Find the binary dependencies of PTH. + + This implementation walks through the PE header and uses library pefile for that and supports 32/64bit Windows + """ + dlls = set() + # By default, pefile library parses all PE information. We are only interested in the list of dependent dlls. + # Performance is improved by reading only needed information. https://code.google.com/p/pefile/wiki/UsageExamples + + pe = pefile.PE(pth, fast_load=True) + pe.parse_data_directories( + directories=[ + pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_IMPORT'], + pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_EXPORT'], + ], + forwarded_exports_only=True, + import_dllnames_only=True, + ) + + # Some libraries have no other binary dependencies. Use empty list in that case. Otherwise pefile would return None. + # e.g., C:\windows\system32\kernel32.dll on Wine + for entry in getattr(pe, 'DIRECTORY_ENTRY_IMPORT', []): + dll_str = winutils.convert_dll_name_to_str(entry.dll) + dlls.add(dll_str) + + # We must also read the exports table to find forwarded symbols: + # http://blogs.msdn.com/b/oldnewthing/archive/2006/07/19/671238.aspx + exportSymbols = getattr(pe, 'DIRECTORY_ENTRY_EXPORT', None) + if exportSymbols: + for sym in exportSymbols.symbols: + if sym.forwarder is not None: + # sym.forwarder is a bytes object. Convert it to a string. + forwarder = winutils.convert_dll_name_to_str(sym.forwarder) + # sym.forwarder is for example 'KERNEL32.EnterCriticalSection' + dll = forwarder.split('.')[0] + dlls.add(dll + ".dll") + + pe.close() + return dlls + + +def _extract_from_egg(toc): + """ + Ensure all binary modules in zipped eggs get extracted and included with the frozen executable. + + return modified table of content + """ + new_toc = [] + for item in toc: + # Item is a tuple + # (mod_name, path, type) + modname, pth, typ = item + if not os.path.isfile(pth): + pth = check_extract_from_egg(pth)[0][0] + + # Add value to new data structure. + new_toc.append((modname, pth, typ)) + return new_toc + + +BindingRedirect = collections.namedtuple('BindingRedirect', 'name language arch oldVersion newVersion publicKeyToken') + + +def match_binding_redirect(manifest, redirect): + return all([ + manifest.name == redirect.name, + manifest.version == redirect.oldVersion, + manifest.language == redirect.language, + manifest.processorArchitecture == redirect.arch, + manifest.publicKeyToken == redirect.publicKeyToken, + ]) + + +_exe_machine_type = None + + +def matchDLLArch(filename): + """ + Return True if the DLL given by filename matches the CPU type/architecture of the Python process running + PyInstaller. + + Always returns True on non-Windows platforms. + + :param filename: + :type filename: + :return: + :rtype: + """ + # TODO: check machine type on other platforms? + if not compat.is_win: + return True + + global _exe_machine_type + try: + if _exe_machine_type is None: + pefilename = compat.python_executable # for exception handling + exe_pe = pefile.PE(pefilename, fast_load=True) + _exe_machine_type = exe_pe.FILE_HEADER.Machine + exe_pe.close() + + pefilename = filename # for exception handling + pe = pefile.PE(filename, fast_load=True) + match_arch = pe.FILE_HEADER.Machine == _exe_machine_type + pe.close() + except pefile.PEFormatError as exc: + raise SystemExit('Cannot get architecture from file: %s\n Reason: %s' % (pefilename, exc)) + return match_arch + + +def _get_paths_for_parent_directory_preservation(): + """ + Return list of paths that serve as prefixes for parent-directory preservation of collected binaries and/or + shared libraries. If a binary is collected from a location that starts with a path from this list, the relative + directory structure is preserved within the frozen application bundle; otherwise, the binary is collected to the + frozen application's top-level directory. + """ + + # Use only site-packages paths. We have no control over contents of `sys.path`, so using all paths from that may + # lead to unintended behavior in corner cases. For example, if `sys.path` contained the drive root (see #7028), + # all paths that do not match some other sub-path rooted in that drive will end up recognized as relative to the + # drive root. In such case, any DLL collected from `c:\Windows\system32` will be collected into `Windows\system32` + # sub-directory; ucrt DLLs collected from MSVC or Windows SDK installed in `c:\Program Files\...` will end up + # collected into `Program Files\...` subdirectory; etc. + # + # On the other hand, the DLL parent directory preservation is primarily aimed at packages installed via PyPI + # wheels, which are typically installed into site-packages. Therefore, limiting the directory preservation for + # shared libraries collected from site-packages should do the trick, and should be reasonably safe. + import site + + orig_paths = site.getsitepackages() + orig_paths.append(site.getusersitepackages()) + + # Explicitly excluded paths. `site.getsitepackages` seems to include `sys.prefix`, which we need to exclude, to + # avoid issue swith DLLs in its sub-directories. + excluded_paths = { + pathlib.Path(sys.base_prefix).resolve(), + pathlib.Path(sys.prefix).resolve(), + } + + paths = [] + for path in orig_paths: + if not path: + continue + path = pathlib.Path(path).resolve() + # Filter out non-directories (e.g., /path/to/python3x.zip) or non-existent paths + if not path.is_dir(): + continue + # Filter out explicitly excluded paths + if path in excluded_paths: + continue + paths.append(path) + + # Sort by length (in term of path components) to ensure match against the longest common prefix (for example, match + # /path/to/venv/lib/site-packages instead of /path/to/venv when both paths are in site paths). + paths = sorted(paths, key=lambda x: len(x.parents), reverse=True) + + return paths + + +def _select_destination_directory(src_filename, parent_dir_preservation_paths): + # Check parent directory preservation paths + for parent_dir_preservation_path in parent_dir_preservation_paths: + if parent_dir_preservation_path in src_filename.parents: + # Collect into corresponding sub-directory. + return src_filename.relative_to(parent_dir_preservation_path) + + # Collect into top-level directory. + return src_filename.name + + +def Dependencies(lTOC, xtrapath=None, manifest=None, redirects=None): + """ + Expand LTOC to include all the closure of binary dependencies. + + `LTOC` is a logical table of contents, ie, a seq of tuples (name, path). Return LTOC expanded by all the binary + dependencies of the entries in LTOC, except those listed in the module global EXCLUDES + + `manifest` may be a winmanifest.Manifest instance for a program manifest, so that all dependent assemblies of + python.exe can be added to the built exe. + + `redirects` may be a list. Any assembly redirects found via policy files will be added to the list as + BindingRedirect objects so they can later be used to modify any manifests that reference the redirected assembly. + """ + + # Get all path prefixes for binaries' parent-directory preservation. For binaries collected from packages in (for + # example) site-packages directory, we should try to preserve the parent directory structure. Currently, this + # behavior is active only on Windows. For macOS and linux, we need to implement symlink support first. + parent_dir_preservation_paths = [] + if compat.is_win: + parent_dir_preservation_paths = _get_paths_for_parent_directory_preservation() + + # Extract all necessary binary modules from Python eggs to be included directly with PyInstaller. + lTOC = _extract_from_egg(lTOC) + + for nm, pth, typ in lTOC: + if nm.upper() in seen: + continue + logger.debug("Analyzing %s", pth) + seen.add(nm.upper()) + if compat.is_win: + for ftocnm, fn in getAssemblyFiles(pth, manifest, redirects): + lTOC.append((ftocnm, fn, 'BINARY')) + for lib, npth in selectImports(pth, xtrapath): + if lib.upper() in seen or npth.upper() in seen: + continue + seen.add(npth.upper()) + + # Try to preserve parent directory structure, if applicable. + # NOTE: do not resolve the source path, because on macOS and linux, it may be a versioned .so (e.g., + # libsomething.so.1, pointing at libsomething.so.1.2.3), and we need to collect it under original + # name! + src_path = pathlib.Path(npth) + dst_path = _select_destination_directory(src_path, parent_dir_preservation_paths) + lTOC.append((str(dst_path), npth, 'BINARY')) + + return lTOC + + +def pkg_resources_get_default_cache(): + """ + Determine the default cache location + + This returns the ``PYTHON_EGG_CACHE`` environment variable, if set. Otherwise, on Windows, it returns a + 'Python-Eggs' subdirectory of the 'Application Data' directory. On all other systems, it's '~/.python-eggs'. + """ + # This function borrowed from setuptools/pkg_resources + egg_cache = compat.getenv('PYTHON_EGG_CACHE') + if egg_cache is not None: + return egg_cache + + if os.name != 'nt': + return os.path.expanduser('~/.python-eggs') + + app_data = 'Application Data' # XXX this may be locale-specific! + app_homes = [ + (('APPDATA',), None), # best option, should be locale-safe + (('USERPROFILE',), app_data), + (('HOMEDRIVE', 'HOMEPATH'), app_data), + (('HOMEPATH',), app_data), + (('HOME',), None), + (('WINDIR',), app_data), # 95/98/ME + ] + + for keys, subdir in app_homes: + dirname = '' + for key in keys: + if key in os.environ: + dirname = os.path.join(dirname, compat.getenv(key)) + else: + break + else: + if subdir: + dirname = os.path.join(dirname, subdir) + return os.path.join(dirname, 'Python-Eggs') + else: + raise RuntimeError("Please set the PYTHON_EGG_CACHE environment variable") + + +def check_extract_from_egg(pth, todir=None): + r""" + Check if path points to a file inside a python egg file, extract the file from the egg to a cache directory ( + following pkg_resources convention) and return [(extracted path, egg file path, relative path inside egg file)]. + + Otherwise, just return [(original path, None, None)]. If path points to an egg file directly, return a list with + all files from the egg formatted like above. + + Example: + >>> check_extract_from_egg(r'C:\Python26\Lib\site-packages\my.egg\mymodule\my.pyd') + [(r'C:\Users\UserName\AppData\Roaming\Python-Eggs\my.egg-tmp\mymodule\my.pyd', + r'C:\Python26\Lib\site-packages\my.egg', r'mymodule/my.pyd')] + """ + rv = [] + if os.path.altsep: + pth = pth.replace(os.path.altsep, os.path.sep) + components = pth.split(os.path.sep) + for i, name in enumerate(components): + if name.lower().endswith(".egg"): + eggpth = os.path.sep.join(components[:i + 1]) + if os.path.isfile(eggpth): + # eggs can also be directories! + try: + egg = zipfile.ZipFile(eggpth) + except zipfile.BadZipFile as e: + raise SystemExit("Error: %s %s" % (eggpth, e)) + if todir is None: + # Use the same directory as setuptools/pkg_resources. So, if the specific egg was accessed before + # (not necessarily by pyinstaller), the extracted contents already exist (pkg_resources puts them + # there) and can be used. + todir = os.path.join(pkg_resources_get_default_cache(), name + "-tmp") + if components[i + 1:]: + members = ["/".join(components[i + 1:])] + else: + members = egg.namelist() + for member in members: + pth = os.path.join(todir, member) + if not os.path.isfile(pth): + dirname = os.path.dirname(pth) + if not os.path.isdir(dirname): + os.makedirs(dirname) + with open(pth, "wb") as f: + f.write(egg.read(member)) + rv.append((pth, eggpth, member)) + return rv + return [(pth, None, None)] + + +def getAssemblies(pth): + """ + On Windows return the dependent Side-by-Side (SxS) assemblies of a binary as a list of Manifest objects. + + Dependent assemblies are required only by binaries compiled with MSVC 9.0. Python 2.7 and 3.2 are compiled with + MSVC 9.0 and thus depend on Microsoft Redistributable runtime libraries 9.0. + + Python 3.3+ is compiled with version 10.0 and does not use SxS assemblies. + + FIXME: Can this be removed since we now only support Python 3.5+? + FIXME: IS there some test-case covering this? + """ + if pth.lower().endswith(".manifest"): + return [] + # check for manifest file + manifestnm = pth + ".manifest" + if os.path.isfile(manifestnm): + with open(manifestnm, "rb") as fd: + res = {winmanifest.RT_MANIFEST: {1: {0: fd.read()}}} + else: + # check the binary for embedded manifest + try: + res = winmanifest.GetManifestResources(pth) + except winresource.pywintypes.error as exc: + if exc.args[0] == winresource.ERROR_BAD_EXE_FORMAT: + logger.info('Cannot get manifest resource from non-PE file %s', pth) + return [] + raise + rv = [] + if winmanifest.RT_MANIFEST in res and len(res[winmanifest.RT_MANIFEST]): + for name in res[winmanifest.RT_MANIFEST]: + for language in res[winmanifest.RT_MANIFEST][name]: + # check the manifest for dependent assemblies + try: + manifest = winmanifest.Manifest() + manifest.filename = ":".join([ + pth, + str(winmanifest.RT_MANIFEST), + str(name), + str(language), + ]) + manifest.parse_string(res[winmanifest.RT_MANIFEST][name][language], False) + except Exception: + logger.error("Cannot parse manifest resource %s, %s from %s", name, language, pth, exc_info=1) + else: + if manifest.dependentAssemblies: + logger.debug("Dependent assemblies of %s:", pth) + logger.debug(", ".join([assembly.getid() for assembly in manifest.dependentAssemblies])) + rv.extend(manifest.dependentAssemblies) + return rv + + +def getAssemblyFiles(pth, manifest=None, redirects=None): + """ + Find all assemblies that are dependencies of the given binary and return the files that make up the assemblies as + (name, fullpath) tuples. + + If a WinManifest object is passed as `manifest`, also updates that manifest to reference the returned assemblies. + This is done only to update the built app's .exe with the dependencies of python.exe + + If a list is passed as `redirects`, and binding redirects in policy files are applied when searching for + assemblies, BindingRedirect objects are appended to this list. + + Return a list of pairs (name, fullpath) + """ + rv = [] + if manifest: + _depNames = set(dep.name for dep in manifest.dependentAssemblies) + for assembly in getAssemblies(pth): + if assembly.getid().upper() in seen: + continue + if manifest and assembly.name not in _depNames: + # Add assembly as dependency to our final output exe's manifest + logger.info("Adding %s to dependent assemblies of final executable\n required by %s", assembly.name, pth) + manifest.dependentAssemblies.append(assembly) + _depNames.add(assembly.name) + if not dylib.include_library(assembly.name): + logger.debug("Skipping assembly %s", assembly.getid()) + continue + if assembly.optional: + logger.debug("Skipping optional assembly %s", assembly.getid()) + continue + + from PyInstaller.config import CONF + if CONF.get("win_no_prefer_redirects"): + files = assembly.find_files() + else: + files = [] + if not len(files): + # If no files were found, it may be the case that the required version of the assembly is not installed, and + # the policy file is redirecting it to a newer version. So, we collect the newer version instead. + files = assembly.find_files(ignore_policies=False) + if len(files) and redirects is not None: + # New version was found, old version was not. Add a redirect in the app configuration. + old_version = assembly.version + new_version = assembly.get_policy_redirect() + logger.info("Adding redirect %s version %s -> %s", assembly.name, old_version, new_version) + redirects.append( + BindingRedirect( + name=assembly.name, + language=assembly.language, + arch=assembly.processorArchitecture, + publicKeyToken=assembly.publicKeyToken, + oldVersion=old_version, + newVersion=new_version, + ) + ) + + if files: + seen.add(assembly.getid().upper()) + for fn in files: + fname, fext = os.path.splitext(fn) + if fext.lower() == ".manifest": + nm = assembly.name + fext + else: + nm = os.path.basename(fn) + ftocnm = nm + if assembly.language not in (None, "", "*", "neutral"): + ftocnm = os.path.join(assembly.getlanguage(), ftocnm) + nm, ftocnm, fn = [item.encode(sys.getfilesystemencoding()) for item in (nm, ftocnm, fn)] + if fn.upper() not in seen: + logger.debug("Adding %s", ftocnm) + seen.add(nm.upper()) + seen.add(fn.upper()) + rv.append((ftocnm, fn)) + else: + #logger.info("skipping %s part of assembly %s dependency of %s", ftocnm, assembly.name, pth) + pass + else: + logger.error("Assembly %s not found", assembly.getid()) + + # Convert items in list from 'bytes' type to 'str' type. + # NOTE: with Python 3 we somehow get type 'bytes' and it then causes other issues and failures with PyInstaller. + new_rv = [] + for item in rv: + a = item[0].decode('ascii') + b = item[1].decode('ascii') + new_rv.append((a, b)) + rv = new_rv + + return rv + + +def selectImports(pth, xtrapath=None): + """ + Return the dependencies of a binary that should be included. + + Return a list of pairs (name, fullpath) + """ + rv = [] + if xtrapath is None: + xtrapath = [os.path.dirname(pth)] + else: + assert isinstance(xtrapath, list) + xtrapath = [os.path.dirname(pth)] + xtrapath # make a copy + dlls = getImports(pth) + for lib in dlls: + if lib.upper() in seen: + continue + if not compat.is_win: + # all other platforms + npth = lib + lib = os.path.basename(lib) + else: + # plain win case + npth = getfullnameof(lib, xtrapath) + + # Now npth is a candidate lib if found. Check again for excludes, but with regex. FIXME: split the list. + if npth: + candidatelib = npth + else: + candidatelib = lib + + if not dylib.include_library(candidatelib): + if candidatelib.find('libpython') < 0 and candidatelib.find('Python.framework') < 0: + # skip libs not containing (libpython or Python.framework) + if npth.upper() not in seen: + logger.debug("Skipping %s dependency of %s", lib, os.path.basename(pth)) + continue + else: + pass + + if npth: + if npth.upper() not in seen: + logger.debug("Adding %s dependency of %s from %s", lib, os.path.basename(pth), npth) + rv.append((lib, npth)) + elif dylib.warn_missing_lib(lib): + logger.warning("lib not found: %s dependency of %s", lib, pth) + + return rv + + +def _getImports_ldd(pth): + """ + Find the binary dependencies of PTH. + + This implementation is for ldd platforms (mostly unix). + """ + rslt = set() + if compat.is_aix: + # Match libs of the form + # 'archivelib.a(objectmember.so/.o)' + # or + # 'sharedlib.so' + # Will not match the fake lib '/unix' + lddPattern = re.compile(r"^\s*(((?P(.*\.a))(?P\(.*\)))|((?P(.*\.so))))$") + elif compat.is_hpux: + # Match libs of the form + # 'sharedlib.so => full-path-to-lib + # e.g. + # 'libpython2.7.so => /usr/local/lib/hpux32/libpython2.7.so' + lddPattern = re.compile(r"^\s+(.*)\s+=>\s+(.*)$") + elif compat.is_solar: + # Match libs of the form + # 'sharedlib.so => full-path-to-lib + # e.g. + # 'libpython2.7.so.1.0 => /usr/local/lib/libpython2.7.so.1.0' + # Will not match the platform specific libs starting with '/platform' + lddPattern = re.compile(r"^\s+(.*)\s+=>\s+(.*)$") + else: + lddPattern = re.compile(r"\s*(.*?)\s+=>\s+(.*?)\s+\(.*\)") + + p = subprocess.run(['ldd', pth], stderr=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=True) + + for line in p.stderr.splitlines(): + if not line: + continue + # Python extensions (including stdlib ones) are not linked against python.so but rely on Python's symbols having + # already been loaded into symbol space at runtime. musl's ldd issues a series of harmless warnings to stderr + # telling us that those symbols are unfindable. These should be suppressed. + elif line.startswith("Error relocating ") and line.endswith(" symbol not found"): + continue + # Propagate any other warnings it might have. + print(line, file=sys.stderr) + + for line in p.stdout.splitlines(): + m = lddPattern.search(line) + if m: + if compat.is_aix: + libarchive = m.group('libarchive') + if libarchive: + # We matched an archive lib with a request for a particular embedded shared object. + # 'archivelib.a(objectmember.so/.o)' + lib = libarchive + name = os.path.basename(lib) + m.group('objectmember') + else: + # We matched a stand-alone shared library. + # 'sharedlib.so' + lib = m.group('libshared') + name = os.path.basename(lib) + elif compat.is_hpux: + name, lib = m.group(1), m.group(2) + else: + name, lib = m.group(1), m.group(2) + if name[:10] in ('linux-gate', 'linux-vdso'): + # linux-gate is a fake library which does not exist and should be ignored. See also: + # http://www.trilithium.com/johan/2005/08/linux-gate/ + continue + + if compat.is_cygwin: + # exclude Windows system library + if lib.lower().startswith('/cygdrive/c/windows/system'): + continue + + if os.path.exists(lib): + # Add lib if it is not already found. + if lib not in rslt: + rslt.add(lib) + elif dylib.warn_missing_lib(name): + logger.warning('Cannot find %s in path %s (needed by %s)', name, lib, pth) + elif line.endswith("not found"): + # On glibc-based linux distributions, missing libraries are marked with name.so => not found + tokens = line.split('=>') + if len(tokens) != 2: + continue + name = tokens[0].strip() + if dylib.warn_missing_lib(name): + logger.warning('Cannot find %s (needed by %s)', name, pth) + return rslt + + +def _getImports_macholib(pth): + """ + Find the binary dependencies of PTH. + + This implementation is for Mac OS X and uses library macholib. + """ + from macholib.dyld import dyld_find + from macholib.mach_o import LC_RPATH + from macholib.MachO import MachO + from macholib.util import in_system_path + rslt = set() + seen = set() # Libraries read from binary headers. + + #- Walk through mach binary headers. + + m = MachO(pth) + for header in m.headers: + for idx, name, lib in header.walkRelocatables(): + # Sometimes libraries are present multiple times. + if lib not in seen: + seen.add(lib) + + # Walk through mach binary headers and look for LC_RPATH. macholib can't handle @rpath. LC_RPATH has to be read from + # the MachO header. + # TODO Do we need to remove LC_RPATH from MachO load commands? Will it cause any harm to leave them untouched? + # Removing LC_RPATH should be implemented when getting files from the bincache if it is necessary. + run_paths = set() + for header in m.headers: + for command in header.commands: + # A command is a tuple like: + # (, + # , + # '../lib\x00\x00') + cmd_type = command[0].cmd + if cmd_type == LC_RPATH: + rpath = command[2].decode('utf-8') + # Remove trailing '\x00' characters. E.g., '../lib\x00\x00' + rpath = rpath.rstrip('\x00') + # Replace the @executable_path and @loader_path keywords with the actual path to the binary. + executable_path = os.path.dirname(pth) + rpath = re.sub('^@(executable_path|loader_path|rpath)(/|$)', executable_path + r'\2', rpath) + # Make rpath absolute. According to Apple doc LC_RPATH is always relative to the binary location. + rpath = os.path.normpath(os.path.join(executable_path, rpath)) + run_paths.update([rpath]) + else: + # Frameworks that have this structure Name.framework/Versions/N/Name need to search at the same level + # as the framework dir. This is specifically needed so that the QtWebEngine dependencies can be found. + if '.framework' in pth: + run_paths.update(['../../../']) + + # For distributions like Anaconda, all of the dylibs are stored in the lib directory of the Python distribution, not + # alongside of the .so's in each module's subdirectory. + run_paths.add(os.path.join(compat.base_prefix, 'lib')) + + #- Try to find files in file system. + + # In cases with @loader_path or @executable_path try to look in the same directory as the checked binary is. This + # seems to work in most cases. + exec_path = os.path.abspath(os.path.dirname(pth)) + python_bin_path = os.path.abspath(os.path.dirname(sys.executable)) + + for lib in seen: + # Suppose that @rpath is not used for system libraries and using macholib can be avoided. macholib cannot handle + # @rpath. + if lib.startswith('@rpath'): + lib = lib.replace('@rpath', '.') # Make path relative. + final_lib = None # Absolute path to existing lib on disk. + # Try multiple locations. + for run_path in run_paths: + # @rpath may contain relative value. Use exec_path as base path. + if not os.path.isabs(run_path): + run_path = os.path.join(exec_path, run_path) + # Stop looking for lib when found in first location. + if os.path.exists(os.path.join(run_path, lib)): + final_lib = os.path.abspath(os.path.join(run_path, lib)) + rslt.add(final_lib) + break + # Log warning if no existing file found. + if not final_lib and dylib.warn_missing_lib(lib): + logger.warning('Cannot find path %s (needed by %s)', lib, pth) + + # Macholib has to be used to get absolute path to libraries. + else: + # macholib cannot handle @loader_path. It has to be handled the same way as @executable_path. It is also + # replaced by 'exec_path'. + if lib.startswith('@loader_path'): + lib = lib.replace('@loader_path', '@executable_path') + try: + lib = dyld_find(lib, executable_path=exec_path) + rslt.add(lib) + except ValueError: + # try to resolve the executable path with the path of the executable binary for the Python interpreter + try: + lib = dyld_find(lib, executable_path=python_bin_path) + rslt.add(lib) + except ValueError: + # Starting with Big Sur, system libraries are hidden. And we do not collect system libraries on any + # macOS version anyway, so suppress the corresponding error messages. + if not in_system_path(lib) and dylib.warn_missing_lib(lib): + logger.warning('Cannot find path %s (needed by %s)', lib, pth) + + return rslt + + +def getImports(pth): + """ + Forwards to the correct getImports implementation for the platform. + """ + if compat.is_win: + if pth.lower().endswith(".manifest"): + return [] + try: + return _getImports_pe(pth) + except Exception as exception: + # Assemblies can pull in files which aren't necessarily PE, but are still needed by the assembly. Any + # additional binary dependencies should already have been handled by selectAssemblies in that case, so just + # warn, return an empty list and continue. For less specific errors also log the traceback. + logger.warning('Cannot get binary dependencies for file: %s', pth) + logger.warning(' Reason: %s', exception, exc_info=not isinstance(exception, pefile.PEFormatError)) + return [] + elif compat.is_darwin: + return _getImports_macholib(pth) + else: + return _getImports_ldd(pth) + + +def findLibrary(name): + """ + Look for a library in the system. + + Emulate the algorithm used by dlopen. `name` must include the prefix, e.g., ``libpython2.4.so``. + """ + assert compat.is_unix, "Current implementation for Unix only (Linux, Solaris, AIX, FreeBSD)" + + # Look in the LD_LIBRARY_PATH according to platform. + if compat.is_aix: + lp = compat.getenv('LIBPATH', '') + elif compat.is_darwin: + lp = compat.getenv('DYLD_LIBRARY_PATH', '') + else: + lp = compat.getenv('LD_LIBRARY_PATH', '') + lib = _which_library(name, filter(None, lp.split(os.pathsep))) + + # Look in /etc/ld.so.cache + # Solaris does not have /sbin/ldconfig. Just check if this file exists. + if lib is None: + utils.load_ldconfig_cache() + lib = utils.LDCONFIG_CACHE.get(name) + if lib: + assert os.path.isfile(lib) + + # Look in the known safe paths. + if lib is None: + # Architecture independent locations. + paths = ['/lib', '/usr/lib'] + # Architecture dependent locations. + if compat.architecture == '32bit': + paths.extend(['/lib32', '/usr/lib32']) + else: + paths.extend(['/lib64', '/usr/lib64']) + # Machine dependent locations. + if compat.machine == 'intel': + if compat.architecture == '32bit': + paths.extend(['/usr/lib/i386-linux-gnu']) + else: + paths.extend(['/usr/lib/x86_64-linux-gnu']) + + # On Debian/Ubuntu /usr/bin/python is linked statically with libpython. Newer Debian/Ubuntu with multiarch + # support puts the libpythonX.Y.so in paths like /usr/lib/i386-linux-gnu/. + try: + # Module available only in Python 2.7+ + import sysconfig + + # 'multiarchsubdir' works on Debian/Ubuntu only in Python 2.7 and 3.3+. + arch_subdir = sysconfig.get_config_var('multiarchsubdir') + # Ignore if None is returned. + if arch_subdir: + arch_subdir = os.path.basename(arch_subdir) + paths.append(os.path.join('/usr/lib', arch_subdir)) + else: + logger.debug('Multiarch directory not detected.') + except ImportError: + logger.debug('Multiarch directory not detected.') + + # Termux (a Ubuntu like subsystem for Android) has an additional libraries directory. + if os.path.isdir('/data/data/com.termux/files/usr/lib'): + paths.append('/data/data/com.termux/files/usr/lib') + + if compat.is_aix: + paths.append('/opt/freeware/lib') + elif compat.is_hpux: + if compat.architecture == '32bit': + paths.append('/usr/local/lib/hpux32') + else: + paths.append('/usr/local/lib/hpux64') + elif compat.is_freebsd or compat.is_openbsd: + paths.append('/usr/local/lib') + lib = _which_library(name, paths) + + # Give up :( + if lib is None: + return None + + # Resolve the file name into the soname + if compat.is_freebsd or compat.is_aix or compat.is_openbsd: + # On FreeBSD objdump does not show SONAME, and on AIX objdump does not exist, so we just return the lib we + # have found. + return lib + else: + dir = os.path.dirname(lib) + return os.path.join(dir, _get_so_name(lib)) + + +def _which_library(name, dirs): + """ + Search for a shared library in a list of directories. + + Args: + name: + The library name including the `lib` prefix but excluding any `.so` suffix. + dirs: + An iterable of folders to search in. + Returns: + The path to the library if found or None otherwise. + + """ + matcher = _library_matcher(name) + for path in filter(os.path.exists, dirs): + for _path in os.listdir(path): + if matcher(_path): + return os.path.join(path, _path) + + +def _library_matcher(name): + """ + Create a callable that matches libraries if **name** is a valid library prefix for input library full names. + """ + return re.compile(name + r"[0-9]*\.").match + + +def _get_so_name(filename): + """ + Return the soname of a library. + + Soname is useful when there are multiple symplinks to one library. + """ + # TODO verify that objdump works on other unixes and not Linux only. + cmd = ["objdump", "-p", filename] + pattern = r'\s+SONAME\s+([^\s]+)' + if compat.is_solar: + cmd = ["elfdump", "-d", filename] + pattern = r'\s+SONAME\s+[^\s]+\s+([^\s]+)' + m = re.search(pattern, compat.exec_command(*cmd)) + return m.group(1) + + +def get_python_library_path(): + """ + Find dynamic Python library that will be bundled with frozen executable. + + NOTE: This is a fallback option when the Python executable is likely statically linked with the Python library and + we need to search more for it. For example, this is the case on Debian/Ubuntu. + + Return full path to Python dynamic library or None when not found. + + We need to know name of the Python dynamic library for the bootloader. Bootloader has to know what library to + load and not try to guess. + + Some linux distributions (e.g. debian-based) statically link the Python executable to the libpython, + so bindepend does not include it in its output. In this situation let's try to find it. + + Custom Mac OS builds could possibly also have non-framework style libraries, so this method also checks for that + variant as well. + """ + def _find_lib_in_libdirs(*libdirs): + for libdir in libdirs: + for name in compat.PYDYLIB_NAMES: + full_path = os.path.join(libdir, name) + if not os.path.exists(full_path): + continue + # Resolve potential symbolic links to achieve consistent results with linker-based search; e.g., on + # POSIX systems, linker resolves unversioned library names (python3.X.so) to versioned ones + # (libpython3.X.so.1.0) due to former being symbolic linkes to the latter. See #6831. + full_path = os.path.realpath(full_path) + if not os.path.exists(full_path): + continue + return full_path + return None + + # If this is Microsoft App Store Python, check the compat.base_path first. While compat.python_executable resolves + # to actual python.exe file, the latter contains relative library reference that does not get properly resolved by + # getfullnameof(). + if compat.is_ms_app_store: + python_libname = _find_lib_in_libdirs(compat.base_prefix) + if python_libname: + return python_libname + + # Try to get Python library name from the Python executable. It assumes that Python library is not statically + # linked. + dlls = getImports(compat.python_executable) + for filename in dlls: + for name in compat.PYDYLIB_NAMES: + if os.path.basename(filename) == name: + # On Windows filename is just like 'python27.dll'. Convert it to absolute path. + if compat.is_win and not os.path.isabs(filename): + filename = getfullnameof(filename) + # Python library found. Return absolute path to it. + return filename + + # Python library NOT found. Resume searching using alternative methods. + + # Work around for python venv having VERSION.dll rather than pythonXY.dll + if compat.is_win and 'VERSION.dll' in dlls: + pydll = 'python%d%d.dll' % sys.version_info[:2] + return getfullnameof(pydll) + + # Applies only to non Windows platforms and conda. + + if compat.is_conda: + # Conda needs to be the first here since it overrules the operating system specific paths. + python_libname = _find_lib_in_libdirs(os.path.join(compat.base_prefix, 'lib')) + if python_libname: + return python_libname + + elif compat.is_unix: + for name in compat.PYDYLIB_NAMES: + python_libname = findLibrary(name) + if python_libname: + return python_libname + + if compat.is_darwin or compat.is_linux: + # On MacPython, Analysis.assemble is able to find the libpython with no additional help, asking for + # sys.executable dependencies. However, this fails on system python, because the shared library is not listed as + # a dependency of the binary (most probably it is opened at runtime using some dlopen trickery). This happens on + # Mac OS when Python is compiled as Framework. + # Linux using pyenv is similarly linked so that sys.executable dependencies does not yield libpython.so. + + # Python compiled as Framework contains same values in sys.prefix and exec_prefix. That is why we can use just + # sys.prefix. In virtualenv, PyInstaller is not able to find Python library. We need special care for this case. + python_libname = _find_lib_in_libdirs( + compat.base_prefix, + os.path.join(compat.base_prefix, 'lib'), + ) + if python_libname: + return python_libname + + # Python library NOT found. Provide helpful feedback. + msg = """Python library not found: %s + This means your Python installation does not come with proper shared library files. + This usually happens due to missing development package, or unsuitable build parameters of the Python installation. + + * On Debian/Ubuntu, you need to install Python development packages: + * apt-get install python3-dev + * apt-get install python-dev + * If you are building Python by yourself, rebuild with `--enable-shared` (or, `--enable-framework` on macOS). + """ % (", ".join(compat.PYDYLIB_NAMES),) + raise IOError(msg) + + +def findSystemLibrary(name): + """ + Given a library name, try to resolve the path to that library. + + If the path is already an absolute path, return it without searching. + """ + + if os.path.isabs(name): + return name + + if compat.is_unix: + return findLibrary(name) + elif compat.is_win: + return getfullnameof(name) + else: + # This seems to work, and is similar to what we have above.. + return ctypes.util.find_library(name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/bytecode.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/bytecode.py new file mode 100755 index 000000000..a37a96509 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/bytecode.py @@ -0,0 +1,337 @@ +# -*- coding: utf-8 -*- +""" +Tools for searching bytecode for key statements that indicate the need for additional resources, such as data files +and package metadata. + +By *bytecode* I mean the ``code`` object given by ``compile()``, accessible from the ``__code__`` attribute of any +non-builtin function or, in PyInstallerLand, the ``PyiModuleGraph.node("some.module").code`` attribute. The best +guide for bytecode format I have found is the disassembler reference: https://docs.python.org/3/library/dis.html + +This parser implementation aims to combine the flexibility and speed of regex with the clarity of the output of +``dis.dis(code)``. It has not achieved the 2nd, but C'est la vie... + +The biggest clarity killer here is the ``EXTENDED_ARG`` opcode which can appear almost anywhere and therefore needs +to be tiptoed around at every step. If this code needs to expand significantly, I would recommend an upgrade to a +regex-based grammar parsing library such as Reparse. This way, little steps like unpacking ``EXTENDED_ARGS`` can be +defined once then simply referenced forming a nice hierarchy rather than copied everywhere its needed. +""" + +import dis +import re +from types import CodeType +from typing import Pattern + +from PyInstaller import compat + +# opcode name -> opcode map +# Python 3.11 introduced specialized opcodes that are not covered by opcode.opmap (and equivalent dis.opmap), but dis +# has a private map of all opcodes called _all_opmap. So use the latter, if available. +opmap = getattr(dis, '_all_opmap', dis.opmap) + + +def _instruction_to_regex(x: str): + """ + Get a regex-escaped opcode byte from its human readable name. + """ + return re.escape(bytes([opmap[x]])) + + +def bytecode_regex(pattern: bytes, flags=re.VERBOSE | re.DOTALL): + """ + A regex-powered Python bytecode matcher. + + ``bytecode_regex`` provides a very thin wrapper around :func:`re.compile`. + + * Any opcode names wrapped in backticks are substituted for their corresponding opcode bytes. + * Patterns are compiled in VERBOSE mode by default so that whitespace and comments may be used. + + This aims to mirror the output of :func:`dis.dis`, which is far more readable than looking at raw byte strings. + """ + assert isinstance(pattern, bytes) + + # Replace anything wrapped in backticks with regex-escaped opcodes. + pattern = re.sub( + rb"`(\w+)`", + lambda m: _instruction_to_regex(m[1].decode()), + pattern, + ) + return re.compile(pattern, flags=flags) + + +def finditer(pattern: Pattern, string: bytes): + """ + Call ``pattern.finditer(string)``, but remove any matches beginning on an odd byte (i.e., matches where + match.start() is not a multiple of 2). + + This should be used to avoid false positive matches where a bytecode pair's argument is mistaken for an opcode. + """ + assert isinstance(string, bytes) + string = _cleanup_bytecode_string(string) + matches = pattern.finditer(string) + while True: + for match in matches: + if match.start() % 2 == 0: + # All is good. This match starts on an OPCODE. + yield match + else: + # This match has started on an odd byte, meaning that it is a false positive and should be skipped. + # There is a very slim chance that a genuine match overlaps this one and, because re.finditer() does not + # allow overlapping matches, it would be lost. To avoid that, restart the regex scan, starting at the + # next even byte. + matches = pattern.finditer(string, match.start() + 1) + break + else: + break + + +# Opcodes involved in function calls with constant arguments. The differences between python versions are handled by +# variables below, which are then used to construct the _call_function_bytecode regex. +# NOTE1: the _OPCODES_* entries are typically used in (non-capturing) groups that match the opcode plus an arbitrary +# argument. But because the entries themselves may contain more than on opcode (with OR operator between them), they +# themselves need to be enclosed in another (non-capturing) group. E.g., "(?:(?:_OPCODES_FUNCTION_GLOBAL).)". +# NOTE2: _OPCODES_EXTENDED_ARG2 is an exception, as it is used as a list of opcodes to exclude, i.e., +# "[^_OPCODES_EXTENDED_ARG2]". Therefore, multiple opcodes are not separated by the OR operator. +if not compat.is_py37: + _OPCODES_EXTENDED_ARG = rb"`EXTENDED_ARG`" + _OPCODES_EXTENDED_ARG2 = _OPCODES_EXTENDED_ARG + _OPCODES_FUNCTION_GLOBAL = rb"`LOAD_NAME`|`LOAD_GLOBAL`|`LOAD_FAST`" + _OPCODES_FUNCTION_LOAD = rb"`LOAD_ATTR`" + _OPCODES_FUNCTION_ARGS = rb"`LOAD_CONST`" + _OPCODES_FUNCTION_CALL = rb"`CALL_FUNCTION`|`CALL_FUNCTION_EX`" + + def _cleanup_bytecode_string(bytecode): + return bytecode # Nothing to do here +elif not compat.is_py311: + # Python 3.7 introduced two new function-related opcodes, LOAD_METHOD and CALL_METHOD + _OPCODES_EXTENDED_ARG = rb"`EXTENDED_ARG`" + _OPCODES_EXTENDED_ARG2 = _OPCODES_EXTENDED_ARG + _OPCODES_FUNCTION_GLOBAL = rb"`LOAD_NAME`|`LOAD_GLOBAL`|`LOAD_FAST`" + _OPCODES_FUNCTION_LOAD = rb"`LOAD_ATTR`|`LOAD_METHOD`" + _OPCODES_FUNCTION_ARGS = rb"`LOAD_CONST`" + _OPCODES_FUNCTION_CALL = rb"`CALL_FUNCTION`|`CALL_METHOD`|`CALL_FUNCTION_EX`" + + def _cleanup_bytecode_string(bytecode): + return bytecode # Nothing to do here +elif not compat.is_py312: + # Python 3.11 removed CALL_FUNCTION and CALL_METHOD, and replaced them with PRECALL + CALL instruction sequence. + # As both PRECALL and CALL have the same parameter (the argument count), we need to match only up to the PRECALL. + # The CALL_FUNCTION_EX is still present. + # From Python 3.11b1 on, there is an EXTENDED_ARG_QUICK specialization opcode present. + _OPCODES_EXTENDED_ARG = rb"`EXTENDED_ARG`|`EXTENDED_ARG_QUICK`" + _OPCODES_EXTENDED_ARG2 = rb"`EXTENDED_ARG``EXTENDED_ARG_QUICK`" # Special case; see note above the if/else block! + _OPCODES_FUNCTION_GLOBAL = rb"`LOAD_NAME`|`LOAD_GLOBAL`|`LOAD_FAST`" + _OPCODES_FUNCTION_LOAD = rb"`LOAD_ATTR`|`LOAD_METHOD`" + _OPCODES_FUNCTION_ARGS = rb"`LOAD_CONST`" + _OPCODES_FUNCTION_CALL = rb"`PRECALL`|`CALL_FUNCTION_EX`" + + # Starting with python 3.11, the bytecode is peppered with CACHE instructions (which dis module conveniently hides + # unless show_caches=True is used). Dealing with these CACHE instructions in regex rules is going to render them + # unreadable, so instead we pre-process the bytecode and filter the offending opcodes out. + _cache_instruction_filter = bytecode_regex(rb"(`CACHE`.)|(..)") + + def _cleanup_bytecode_string(bytecode): + return _cache_instruction_filter.sub(rb"\2", bytecode) + +else: + # Python 3.12 merged EXTENDED_ARG_QUICK back in to EXTENDED_ARG, and LOAD_METHOD in to LOAD_ATTR + # PRECALL is no longer a valid key + _OPCODES_EXTENDED_ARG = rb"`EXTENDED_ARG`" + _OPCODES_EXTENDED_ARG2 = _OPCODES_EXTENDED_ARG + _OPCODES_FUNCTION_GLOBAL = rb"`LOAD_NAME`|`LOAD_GLOBAL`|`LOAD_FAST`" + _OPCODES_FUNCTION_LOAD = rb"`LOAD_ATTR`" + _OPCODES_FUNCTION_ARGS = rb"`LOAD_CONST`" + _OPCODES_FUNCTION_CALL = rb"`CALL`|`CALL_FUNCTION_EX`" + + _cache_instruction_filter = bytecode_regex(rb"(`CACHE`.)|(..)") + + def _cleanup_bytecode_string(bytecode): + return _cache_instruction_filter.sub(rb"\2", bytecode) + + +# language=PythonVerboseRegExp +_call_function_bytecode = bytecode_regex( + rb""" + # Matches `global_function('some', 'constant', 'arguments')`. + + # Load the global function. In code with >256 of names, this may require extended name references. + ( + (?:(?:""" + _OPCODES_EXTENDED_ARG + rb""").)* + (?:(?:""" + _OPCODES_FUNCTION_GLOBAL + rb""").) + ) + + # For foo.bar.whizz(), the above is the 'foo', below is the 'bar.whizz' (one opcode per name component, each + # possibly preceded by name reference extension). + ( + (?: + (?:(?:""" + _OPCODES_EXTENDED_ARG + rb""").)* + (?:""" + _OPCODES_FUNCTION_LOAD + rb"""). + )* + ) + + # Load however many arguments it takes. These (for now) must all be constants. + # Again, code with >256 constants may need extended enumeration. + ( + (?: + (?:(?:""" + _OPCODES_EXTENDED_ARG + rb""").)* + (?:""" + _OPCODES_FUNCTION_ARGS + rb"""). + )* + ) + + # Call the function. If opcode is CALL_FUNCTION_EX, the parameter are flags. For other opcodes, the parameter + # is the argument count (which may be > 256). + ( + (?:(?:""" + _OPCODES_EXTENDED_ARG + rb""").)* + (?:""" + _OPCODES_FUNCTION_CALL + rb"""). + ) +""" +) + +# language=PythonVerboseRegExp +_extended_arg_bytecode = bytecode_regex( + rb"""( + # Arbitrary number of EXTENDED_ARG pairs. + (?:(?:""" + _OPCODES_EXTENDED_ARG + rb""").)* + + # Followed by some other instruction (usually a LOAD). + [^""" + _OPCODES_EXTENDED_ARG2 + rb"""]. +)""" +) + + +def extended_arguments(extended_args: bytes): + """ + Unpack the (extended) integer used to reference names or constants. + + The input should be a bytecode snippet of the following form:: + + EXTENDED_ARG ? # Repeated 0-4 times. + LOAD_xxx ? # Any of LOAD_NAME/LOAD_CONST/LOAD_METHOD/... + + Each ? byte combined together gives the number we want. + """ + return int.from_bytes(extended_args[1::2], "big") + + +def load(raw: bytes, code: CodeType) -> str: + """ + Parse an (extended) LOAD_xxx instruction. + """ + # Get the enumeration. + index = extended_arguments(raw) + + # Work out what that enumeration was for (constant/local var/global var). + + # If the last instruction byte is a LOAD_FAST: + if raw[-2] == opmap["LOAD_FAST"]: + # Then this is a local variable. + return code.co_varnames[index] + # Or if it is a LOAD_CONST: + if raw[-2] == opmap["LOAD_CONST"]: + # Then this is a literal. + return code.co_consts[index] + # Otherwise, it is a global name. + if compat.is_py311 and raw[-2] == opmap["LOAD_GLOBAL"]: + # In python 3.11, namei>>1 is pushed on stack... + return code.co_names[index >> 1] + if compat.is_py312 and raw[-2] == opmap["LOAD_ATTR"]: + # In python 3.12, namei>>1 is pushed on stack... + return code.co_names[index >> 1] + + return code.co_names[index] + + +def loads(raw: bytes, code: CodeType) -> list: + """ + Parse multiple consecutive LOAD_xxx instructions. Or load() in a for loop. + + May be used to unpack a function's parameters or nested attributes ``(foo.bar.pop.whack)``. + """ + return [load(i, code) for i in _extended_arg_bytecode.findall(raw)] + + +def function_calls(code: CodeType) -> list: + """ + Scan a code object for all function calls on constant arguments. + """ + match: re.Match + out = [] + + for match in finditer(_call_function_bytecode, code.co_code): + function_root, methods, args, function_call = match.groups() + + # For foo(): + # `function_root` contains 'foo' and `methods` is empty. + # For foo.bar.whizz(): + # `function_root` contains 'foo' and `methods` contains the rest. + function_root = load(function_root, code) + methods = loads(methods, code) + function = ".".join([function_root] + methods) + + args = loads(args, code) + if function_call[0] == opmap['CALL_FUNCTION_EX']: + flags = extended_arguments(function_call) + if flags != 0: + # Keyword arguments present. Unhandled at the moment. + continue + # In calls with const arguments, args contains a single + # tuple with all values. + if len(args) != 1 or not isinstance(args[0], tuple): + continue + args = list(args[0]) + else: + arg_count = extended_arguments(function_call) + + if arg_count != len(args): + # This happens if there are variable or keyword arguments. Bail out in either case. + continue + + out.append((function, args)) + + return out + + +def search_recursively(search: callable, code: CodeType, _memo=None) -> dict: + """ + Apply a search function to a code object, recursing into child code objects (function definitions). + """ + if _memo is None: + _memo = {} + if code not in _memo: + _memo[code] = search(code) + for const in code.co_consts: + if isinstance(const, CodeType): + search_recursively(search, const, _memo) + return _memo + + +def recursive_function_calls(code: CodeType) -> dict: + """ + Scan a code object for function calls on constant arguments, recursing into function definitions and bodies of + comprehension loops. + """ + return search_recursively(function_calls, code) + + +def any_alias(full_name: str): + """List possible aliases of a fully qualified Python name. + + >>> list(any_alias("foo.bar.wizz")) + ['foo.bar.wizz', 'bar.wizz', 'wizz'] + + This crudely allows us to capture uses of wizz() under any of + :: + import foo + foo.bar.wizz() + :: + from foo import bar + bar.wizz() + :: + from foo.bar import wizz + wizz() + + However, it will fail for any form of aliases and quite likely find false matches. + """ + parts = full_name.split('.') + while parts: + yield ".".join(parts) + parts = parts[1:] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/dylib.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/dylib.py new file mode 100755 index 000000000..235186431 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/dylib.py @@ -0,0 +1,385 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Manipulating with dynamic libraries. +""" + +import os.path + +from PyInstaller.utils.win32 import winutils + +__all__ = ['exclude_list', 'include_list', 'include_library'] + +import os +import re + +import PyInstaller.log as logging +from PyInstaller import compat + +logger = logging.getLogger(__name__) + +# Ignoring some system libraries speeds up packaging process +_excludes = { + # Ignore annoying warnings with Windows system DLLs. + # + # 'W: library kernel32.dll required via ctypes not found' + # 'W: library coredll.dll required via ctypes not found' + # + # These these dlls has to be ignored for all operating systems because they might be resolved when scanning code for + # ctypes dependencies. + r'advapi32\.dll', + r'ws2_32\.dll', + r'gdi32\.dll', + r'oleaut32\.dll', + r'shell32\.dll', + r'ole32\.dll', + r'coredll\.dll', + r'crypt32\.dll', + r'kernel32', + r'kernel32\.dll', + r'msvcrt\.dll', + r'rpcrt4\.dll', + r'user32\.dll', + # Some modules tries to import the Python library. e.g. pyreadline.console.console + r'python\%s\%s', +} + +# Regex includes - overrides excludes. Include list is used only to override specific libraries from exclude list. +_includes = set() + +_win_includes = { + # We need to allow collection of Visual Studio C++ (VC) runtime DLLs from system directories in order to avoid + # missing DLL errors when the frozen application is run on a system that does not have the corresponding VC + # runtime installed. The VC runtime DLLs may be dependencies of python shared library itself or of extension + # modules provided by 3rd party packages. + + # Visual Studio 2010 (VC10) runtime + # http://msdn.microsoft.com/en-us/library/8kche8ah(v=vs.100).aspx + r'atl100\.dll', + r'msvcr100\.dll', + r'msvcp100\.dll', + r'mfc100\.dll', + r'mfc100u\.dll', + r'mfcmifc80\.dll', + r'mfcm100\.dll', + r'mfcm100u\.dll', + + # Visual Studio 2012 (VC11) runtime + # https://docs.microsoft.com/en-us/visualstudio/releases/2013/2012-redistribution-vs + # + # VC110.ATL + r'atl110\.dll', + # VC110.CRT + r'msvcp110\.dll', + r'msvcr110\.dll', + r'vccorlib110\.dll', + # VC110.CXXAMP + r'vcamp110\.dll', + # VC110.MFC + r'mfc110\.dll', + r'mfc110u\.dll', + r'mfcm110\.dll', + r'mfcm110u\.dll', + # VC110.MFCLOC + r'mfc110chs\.dll', + r'mfc110cht\.dll', + r'mfc110enu\.dll', + r'mfc110esn\.dll', + r'mfc110deu\.dll', + r'mfc110fra\.dll', + r'mfc110ita\.dll', + r'mfc110jpn\.dll', + r'mfc110kor\.dll', + r'mfc110rus\.dll', + # VC110.OpenMP + r'vcomp110\.dll', + # DIA SDK + r'msdia110\.dll', + + # Visual Studio 2013 (VC12) runtime + # https://docs.microsoft.com/en-us/visualstudio/releases/2013/2013-redistribution-vs + # + # VC120.CRT + r'msvcp120\.dll', + r'msvcr120\.dll', + r'vccorlib120\.dll', + # VC120.CXXAMP + r'vcamp120\.dll', + # VC120.MFC + r'mfc120\.dll', + r'mfc120u\.dll', + r'mfcm120\.dll', + r'mfcm120u\.dll', + # VC120.MFCLOC + r'mfc120chs\.dll', + r'mfc120cht\.dll', + r'mfc120deu\.dll', + r'mfc120enu\.dll', + r'mfc120esn\.dll', + r'mfc120fra\.dll', + r'mfc120ita\.dll', + r'mfc120jpn\.dll', + r'mfc120kor\.dll', + r'mfc120rus\.dll', + # VC120.OPENMP + r'vcomp120\.dll', + # DIA SDK + r'msdia120\.dll', + # Cpp REST Windows SDK + r'casablanca120.winrt\.dll', + # Mobile Services Cpp Client + r'zumosdk120.winrt\.dll', + # Cpp REST SDK + r'casablanca120\.dll', + + # Universal C Runtime Library (since Visual Studio 2015) + # + # NOTE: these should be put under a switch, as they need not to be bundled if deployment target is Windows 10 + # and later, as "UCRT is now a system component in Windows 10 and later, managed by Windows Update". + # (https://docs.microsoft.com/en-us/cpp/windows/determining-which-dlls-to-redistribute?view=msvc-170) + # And as discovered in #6326, Windows prefers system-installed version over the bundled one, anyway + # (see https://docs.microsoft.com/en-us/cpp/windows/universal-crt-deployment?view=msvc-170#local-deployment). + r'api-ms-win-core.*', + r'api-ms-win-crt.*', + r'ucrtbase\.dll', + + # Visual Studio 2015/2017/2019/2022 (VC14) runtime + # https://docs.microsoft.com/en-us/visualstudio/releases/2022/redistribution + # + # VC141.CRT/VC142.CRT/VC143.CRT + r'concrt140\.dll', + r'msvcp140\.dll', + r'msvcp140_1\.dll', + r'msvcp140_2\.dll', + r'msvcp140_atomic_wait\.dll', + r'msvcp140_codecvt_ids\.dll', + r'vccorlib140\.dll', + r'vcruntime140\.dll', + r'vcruntime140_1\.dll', + # VC141.CXXAMP/VC142.CXXAMP/VC143.CXXAMP + r'vcamp140\.dll', + # VC141.OpenMP/VC142.OpenMP/VC143.OpenMP + r'vcomp140\.dll', + # DIA SDK + r'msdia140\.dll', + + # Allow pythonNN.dll, pythoncomNN.dll, pywintypesNN.dll + r'py(?:thon(?:com(?:loader)?)?|wintypes)\d+\.dll', +} + +_win_excludes = { + # On Windows, only .dll files can be loaded. + r'.*\.so', + r'.*\.dylib', + + # MS assembly excludes + r'Microsoft\.Windows\.Common-Controls', +} + +_unix_excludes = { + r'libc\.so(\..*)?', + r'libdl\.so(\..*)?', + r'libm\.so(\..*)?', + r'libpthread\.so(\..*)?', + r'librt\.so(\..*)?', + r'libthread_db\.so(\..*)?', + # glibc regex excludes. + r'ld-linux\.so(\..*)?', + r'libBrokenLocale\.so(\..*)?', + r'libanl\.so(\..*)?', + r'libcidn\.so(\..*)?', + r'libcrypt\.so(\..*)?', + r'libnsl\.so(\..*)?', + r'libnss_compat.*\.so(\..*)?', + r'libnss_dns.*\.so(\..*)?', + r'libnss_files.*\.so(\..*)?', + r'libnss_hesiod.*\.so(\..*)?', + r'libnss_nis.*\.so(\..*)?', + r'libnss_nisplus.*\.so(\..*)?', + r'libresolv\.so(\..*)?', + r'libutil\.so(\..*)?', + # graphical interface libraries come with graphical stack (see libglvnd) + r'libE?(Open)?GLX?(ESv1_CM|ESv2)?(dispatch)?\.so(\..*)?', + r'libdrm\.so(\..*)?', + # a subset of libraries included as part of the Nvidia Linux Graphics Driver as of 520.56.06: + # https://download.nvidia.com/XFree86/Linux-x86_64/520.56.06/README/installedcomponents.html + r'nvidia_drv\.so', + r'libglxserver_nvidia\.so(\..*)?', + r'libnvidia-egl-(gbm|wayland)\.so(\..*)?', + r'libnvidia-(cfg|compiler|e?glcore|glsi|glvkspirv|rtcore|allocator|tls|ml)\.so(\..*)?', + r'lib(EGL|GLX)_nvidia\.so(\..*)?', + # libxcb-dri changes ABI frequently (e.g.: between Ubuntu LTS releases) and is usually installed as dependency of + # the graphics stack anyway. No need to bundle it. + r'libxcb\.so(\..*)?', + r'libxcb-dri.*\.so(\..*)?', +} + +_aix_excludes = { + r'libbz2\.a', + r'libc\.a', + r'libC\.a', + r'libcrypt\.a', + r'libdl\.a', + r'libintl\.a', + r'libpthreads\.a', + r'librt\\.a', + r'librtl\.a', + r'libz\.a', +} + +if compat.is_win: + _includes |= _win_includes + _excludes |= _win_excludes +elif compat.is_aix: + # The exclude list for AIX differs from other *nix platforms. + _excludes |= _aix_excludes +elif compat.is_unix: + # Common excludes for *nix platforms -- except AIX. + _excludes |= _unix_excludes + + +class ExcludeList: + def __init__(self): + self.regex = re.compile('|'.join(_excludes), re.I) + + def search(self, libname): + # Running re.search() on '' regex never returns None. + if _excludes: + return self.regex.match(os.path.basename(libname)) + else: + return False + + +class IncludeList: + def __init__(self): + self.regex = re.compile('|'.join(_includes), re.I) + + def search(self, libname): + # Running re.search() on '' regex never returns None. + if _includes: + return self.regex.match(os.path.basename(libname)) + else: + return False + + +exclude_list = ExcludeList() +include_list = IncludeList() + +if compat.is_darwin: + # On Mac use macholib to decide if a binary is a system one. + from macholib import util + + class MacExcludeList: + def __init__(self, global_exclude_list): + # Wraps the global 'exclude_list' before it is overridden by this class. + self._exclude_list = global_exclude_list + + def search(self, libname): + # First try global exclude list. If it matches, return its result; otherwise continue with other check. + result = self._exclude_list.search(libname) + if result: + return result + else: + return util.in_system_path(libname) + + exclude_list = MacExcludeList(exclude_list) + +elif compat.is_win: + + class WinExcludeList: + def __init__(self, global_exclude_list): + self._exclude_list = global_exclude_list + # use normpath because msys2 uses / instead of \ + self._windows_dir = os.path.normpath(winutils.get_windows_dir().lower()) + + def search(self, libname): + libname = libname.lower() + result = self._exclude_list.search(libname) + if result: + return result + else: + # Exclude everything from the Windows directory by default. + # .. sometimes realpath changes the case of libname, lower it + # .. use normpath because msys2 uses / instead of \ + fn = os.path.normpath(os.path.realpath(libname).lower()) + return fn.startswith(self._windows_dir) + + exclude_list = WinExcludeList(exclude_list) + +_seen_wine_dlls = set() # Used for warning tracking in include_library() + + +def include_library(libname): + """ + Check if the dynamic library should be included with application or not. + """ + if exclude_list: + if exclude_list.search(libname) and not include_list.search(libname): + # Library is excluded and is not overridden by include list. It should be excluded. + return False + + # If we are running under Wine and the library is a Wine built-in DLL, ensure that it is always excluded. Typically, + # excluding a DLL leads to an incomplete bundle and run-time errors when the said DLL is not installed on the target + # system. However, having Wine built-in DLLs collected is even more detrimental, as they usually provide Wine's + # implementation of low-level functionality, and therefore cannot be used on actual Windows (i.e., system libraries + # from the C:\Windows\system32 directory that might end up collected due to ``_win_includes`` list; a prominent + # example are VC runtime DLLs, for which Wine provides their own implementation, unless user explicitly installs + # Microsoft's VC redistributable package in their Wine environment). Therefore, excluding the Wine built-in DLLs + # actually improves the chances of the bundle running on Windows, or at least makes the issue easier to debug by + # turning it into the "standard" missing DLL problem. Exclusion should not affect the bundle's ability to run under + # Wine itself, as the excluded DLLs are available there. + if compat.is_win_wine and compat.is_wine_dll(libname): + if libname not in _seen_wine_dlls: + logger.warning("Excluding Wine built-in DLL: %s", libname) # displayed only if DLL would have been included + _seen_wine_dlls.add(libname) # display only once for each DLL + return False + + return True + + +# Patterns for suppressing warnings about missing dynamically linked libraries +_warning_suppressions = [ + # We fail to discover shiboken2 (PySide2) and shiboken6 (PySide6) shared libraries due to the way the packages set + # up the search path to the library, which is located in a separate package. Suppress the harmless warnings to avoid + # confusion. + r'(lib)?shiboken.*', +] + +# On some systems (e.g., openwrt), libc.so might point to ldd. Suppress warnings about it. +if compat.is_linux: + _warning_suppressions.append(r'ldd') + +# Suppress false warnings on win 10 and UCRT (see issue #1566). +if compat.is_win_10: + _warning_suppressions.append(r'api-ms-win-crt.*') + _warning_suppressions.append(r'api-ms-win-core.*') + + +class MissingLibWarningSuppressionList: + def __init__(self): + self.regex = re.compile('|'.join(_warning_suppressions), re.I) + + def search(self, libname): + # Running re.search() on '' regex never returns None. + if _warning_suppressions: + return self.regex.match(os.path.basename(libname)) + else: + return False + + +missing_lib_warning_suppression_list = MissingLibWarningSuppressionList() + + +def warn_missing_lib(libname): + """ + Check if a missing-library warning should be displayed for the given library name (or full path). + """ + return not missing_lib_warning_suppression_list.search(libname) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/imphook.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/imphook.py new file mode 100755 index 000000000..1dd63c226 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/imphook.py @@ -0,0 +1,542 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Code related to processing of import hooks. +""" + +import glob +import os.path +import sys +import weakref + +from PyInstaller import log as logging +from PyInstaller.building.utils import format_binaries_and_datas +from PyInstaller.compat import expand_path, importlib_load_source +from PyInstaller.depend.imphookapi import PostGraphAPI +from PyInstaller.exceptions import ImportErrorWhenRunningHook + +logger = logging.getLogger(__name__) + +# Safety check: Hook module names need to be unique. Duplicate names might occur if the cached PyuModuleGraph has an +# issue. +HOOKS_MODULE_NAMES = set() + + +class ModuleHookCache(dict): + """ + Cache of lazily loadable hook script objects. + + This cache is implemented as a `dict` subclass mapping from the fully-qualified names of all modules with at + least one hook script to lists of `ModuleHook` instances encapsulating these scripts. As a `dict` subclass, + all cached module names and hook scripts are accessible via standard dictionary operations. + + Attributes + ---------- + module_graph : ModuleGraph + Current module graph. + _hook_module_name_prefix : str + String prefixing the names of all in-memory modules lazily loaded from cached hook scripts. See also the + `hook_module_name_prefix` parameter passed to the `ModuleHook.__init__()` method. + """ + + _cache_id_next = 0 + """ + 0-based identifier unique to the next `ModuleHookCache` to be instantiated. + + This identifier is incremented on each instantiation of a new `ModuleHookCache` to isolate in-memory modules of + lazily loaded hook scripts in that cache to the same cache-specific namespace, preventing edge-case collisions + with existing in-memory modules in other caches. + + """ + def __init__(self, module_graph, hook_dirs): + """ + Cache all hook scripts in the passed directories. + + **Order of caching is significant** with respect to hooks for the same module, as the values of this + dictionary are lists. Hooks for the same module will be run in the order in which they are cached. Previously + cached hooks are always preserved rather than overridden. + + By default, official hooks are cached _before_ user-defined hooks. For modules with both official and + user-defined hooks, this implies that the former take priority over and hence will be loaded _before_ the + latter. + + Parameters + ---------- + module_graph : ModuleGraph + Current module graph. + hook_dirs : list + List of the absolute or relative paths of all directories containing **hook scripts** (i.e., + Python scripts with filenames matching `hook-{module_name}.py`, where `{module_name}` is the module + hooked by that script) to be cached. + """ + super().__init__() + + # To avoid circular references and hence increased memory consumption, a weak rather than strong reference is + # stored to the passed graph. Since this graph is guaranteed to live longer than this cache, + # this is guaranteed to be safe. + self.module_graph = weakref.proxy(module_graph) + + # String unique to this cache prefixing the names of all in-memory modules lazily loaded from cached hook + # scripts, privatized for safety. + self._hook_module_name_prefix = '__PyInstaller_hooks_{}_'.format(ModuleHookCache._cache_id_next) + ModuleHookCache._cache_id_next += 1 + + # Cache all hook scripts in the passed directories. + self._cache_hook_dirs(hook_dirs) + + def _cache_hook_dirs(self, hook_dirs): + """ + Cache all hook scripts in the passed directories. + + Parameters + ---------- + hook_dirs : list + List of the absolute or relative paths of all directories containing hook scripts to be cached. + """ + + for hook_dir in hook_dirs: + # Canonicalize this directory's path and validate its existence. + hook_dir = os.path.abspath(expand_path(hook_dir)) + if not os.path.isdir(hook_dir): + raise FileNotFoundError('Hook directory "{}" not found.'.format(hook_dir)) + + # For each hook script in this directory... + hook_filenames = glob.glob(os.path.join(hook_dir, 'hook-*.py')) + for hook_filename in hook_filenames: + # Fully-qualified name of this hook's corresponding module, constructed by removing the "hook-" prefix + # and ".py" suffix. + module_name = os.path.basename(hook_filename)[5:-3] + + # Lazily loadable hook object. + module_hook = ModuleHook( + module_graph=self.module_graph, + module_name=module_name, + hook_filename=hook_filename, + hook_module_name_prefix=self._hook_module_name_prefix, + ) + + # Add this hook to this module's list of hooks. + module_hooks = self.setdefault(module_name, []) + module_hooks.append(module_hook) + + def remove_modules(self, *module_names): + """ + Remove the passed modules and all hook scripts cached for these modules from this cache. + + Parameters + ---------- + module_names : list + List of all fully-qualified module names to be removed. + """ + + for module_name in module_names: + # Unload this module's hook script modules from memory. Since these are top-level pure-Python modules cached + # only in the "sys.modules" dictionary, popping these modules from this dictionary suffices to garbage + # collect these modules. + module_hooks = self.get(module_name, []) + for module_hook in module_hooks: + sys.modules.pop(module_hook.hook_module_name, None) + + # Remove this module and its hook script objects from this cache. + self.pop(module_name, None) + + +def _module_collection_mode_sanitizer(value): + if isinstance(value, dict): + # Hook set a dictionary; use it as-is + return value + elif isinstance(value, str): + # Hook set a mode string; convert to a dictionary and assign the string to `None` (= the hooked module). + return {None: value} + + raise ValueError(f"Invalid module collection mode setting value: {value!r}") + + +# Dictionary mapping the names of magic attributes required by the "ModuleHook" class to 2-tuples "(default_type, +# sanitizer_func)", where: +# +# * "default_type" is the type to which that attribute will be initialized when that hook is lazily loaded. +# * "sanitizer_func" is the callable sanitizing the original value of that attribute defined by that hook into a +# safer value consumable by "ModuleHook" callers if any or "None" if the original value requires no sanitization. +# +# To avoid subtleties in the ModuleHook.__getattr__() method, this dictionary is declared as a module rather than a +# class attribute. If declared as a class attribute and then undefined (...for whatever reason), attempting to access +# this attribute from that method would produce infinite recursion. +_MAGIC_MODULE_HOOK_ATTRS = { + # Collections in which order is insignificant. This includes: + # + # * "datas", sanitized from hook-style 2-tuple lists defined by hooks into TOC-style 2-tuple sets consumable by + # "ModuleHook" callers. + # * "binaries", sanitized in the same way. + 'datas': (set, format_binaries_and_datas), + 'binaries': (set, format_binaries_and_datas), + 'excludedimports': (set, None), + + # Collections in which order is significant. This includes: + # + # * "hiddenimports", as order of importation is significant. On module importation, hook scripts are loaded and hook + # functions declared by these scripts are called. As these scripts and functions can have side effects dependent + # on module importation order, module importation itself can have side effects dependent on this order! + 'hiddenimports': (list, None), + + # Flags + 'warn_on_missing_hiddenimports': (lambda: True, bool), + + # Package/module collection mode dictionary. + 'module_collection_mode': (dict, _module_collection_mode_sanitizer), +} + + +class ModuleHook: + """ + Cached object encapsulating a lazy loadable hook script. + + This object exposes public attributes (e.g., `datas`) of the underlying hook script as attributes of the same + name of this object. On the first access of any such attribute, this hook script is lazily loaded into an + in-memory private module reused on subsequent accesses. These dynamic attributes are referred to as "magic." All + other static attributes of this object (e.g., `hook_module_name`) are referred to as "non-magic." + + Attributes (Magic) + ---------- + datas : set + Set of `TOC`-style 2-tuples `(target_file, source_file)` for all external non-executable files required by + the module being hooked, converted from the `datas` list of hook-style 2-tuples `(source_dir_or_glob, + target_dir)` defined by this hook script. + binaries : set + Set of `TOC`-style 2-tuples `(target_file, source_file)` for all external executable files required by the + module being hooked, converted from the `binaries` list of hook-style 2-tuples `(source_dir_or_glob, + target_dir)` defined by this hook script. + excludedimports : set + Set of the fully-qualified names of all modules imported by the module being hooked to be ignored rather than + imported from that module, converted from the `excludedimports` list defined by this hook script. These + modules will only be "locally" rather than "globally" ignored. These modules will remain importable from all + modules other than the module being hooked. + hiddenimports : set + Set of the fully-qualified names of all modules imported by the module being hooked that are _not_ + automatically detectable by PyInstaller (usually due to being dynamically imported in that module), + converted from the `hiddenimports` list defined by this hook script. + warn_on_missing_hiddenimports : bool + Boolean flag indicating whether missing hidden imports from the hook should generate warnings or not. This + behavior is enabled by default, but individual hooks can opt out of it. + module_collection_mode : dict + A dictionary of package/module names and their corresponding collection mode strings ('pyz', 'pyc', 'py', + 'pyz+py', 'py+pyz'). + + Attributes (Non-magic) + ---------- + module_graph : ModuleGraph + Current module graph. + module_name : str + Name of the module hooked by this hook script. + hook_filename : str + Absolute or relative path of this hook script. + hook_module_name : str + Name of the in-memory module of this hook script's interpreted contents. + _hook_module : module + In-memory module of this hook script's interpreted contents, lazily loaded on the first call to the + `_load_hook_module()` method _or_ `None` if this method has yet to be accessed. + """ + + #-- Magic -- + + def __init__(self, module_graph, module_name, hook_filename, hook_module_name_prefix): + """ + Initialize this metadata. + + Parameters + ---------- + module_graph : ModuleGraph + Current module graph. + module_name : str + Name of the module hooked by this hook script. + hook_filename : str + Absolute or relative path of this hook script. + hook_module_name_prefix : str + String prefixing the name of the in-memory module for this hook script. To avoid namespace clashes with + similar modules created by other `ModuleHook` objects in other `ModuleHookCache` containers, this string + _must_ be unique to the `ModuleHookCache` container containing this `ModuleHook` object. If this string + is non-unique, an existing in-memory module will be erroneously reused when lazily loading this hook + script, thus erroneously resanitizing previously sanitized hook script attributes (e.g., `datas`) with + the `format_binaries_and_datas()` helper. + + """ + # Note that the passed module graph is already a weak reference, avoiding circular reference issues. See + # ModuleHookCache.__init__(). TODO: Add a failure message + assert isinstance(module_graph, weakref.ProxyTypes) + self.module_graph = module_graph + self.module_name = module_name + self.hook_filename = hook_filename + + # Name of the in-memory module fabricated to refer to this hook script. + self.hook_module_name = hook_module_name_prefix + self.module_name.replace('.', '_') + + # Safety check, see above + global HOOKS_MODULE_NAMES + if self.hook_module_name in HOOKS_MODULE_NAMES: + # When self._shallow is true, this class never loads the hook and sets the attributes to empty values + self._shallow = True + else: + self._shallow = False + HOOKS_MODULE_NAMES.add(self.hook_module_name) + + # Attributes subsequently defined by the _load_hook_module() method. + self._loaded = False + self._has_hook_function = False + self._hook_module = None + + def __getattr__(self, attr_name): + """ + Get the magic attribute with the passed name (e.g., `datas`) from this lazily loaded hook script if any _or_ + raise `AttributeError` otherwise. + + This special method is called only for attributes _not_ already defined by this object. This includes + undefined attributes and the first attempt to access magic attributes. + + This special method is _not_ called for subsequent attempts to access magic attributes. The first attempt to + access magic attributes defines corresponding instance variables accessible via the `self.__dict__` instance + dictionary (e.g., as `self.datas`) without calling this method. This approach also allows magic attributes to + be deleted from this object _without_ defining the `__delattr__()` special method. + + See Also + ---------- + Class docstring for supported magic attributes. + """ + + # If this is a magic attribute, initialize this attribute by lazy loading this hook script and then return + # this attribute. + if attr_name in _MAGIC_MODULE_HOOK_ATTRS and not self._loaded: + self._load_hook_module() + return getattr(self, attr_name) + # Else, this is an undefined attribute. Raise an exception. + else: + raise AttributeError(attr_name) + + def __setattr__(self, attr_name, attr_value): + """ + Set the attribute with the passed name to the passed value. + + If this is a magic attribute, this hook script will be lazily loaded before setting this attribute. Unlike + `__getattr__()`, this special method is called to set _any_ attribute -- including magic, non-magic, + and undefined attributes. + + See Also + ---------- + Class docstring for supported magic attributes. + """ + + # If this is a magic attribute, initialize this attribute by lazy loading this hook script before overwriting + # this attribute. + if attr_name in _MAGIC_MODULE_HOOK_ATTRS: + self._load_hook_module() + + # Set this attribute to the passed value. To avoid recursion, the superclass method rather than setattr() is + # called. + return super().__setattr__(attr_name, attr_value) + + #-- Loading -- + + def _load_hook_module(self, keep_module_ref=False): + """ + Lazily load this hook script into an in-memory private module. + + This method (and, indeed, this class) preserves all attributes and functions defined by this hook script as + is, ensuring sane behaviour in hook functions _not_ expecting unplanned external modification. Instead, + this method copies public attributes defined by this hook script (e.g., `binaries`) into private attributes + of this object, which the special `__getattr__()` and `__setattr__()` methods safely expose to external + callers. For public attributes _not_ defined by this hook script, the corresponding private attributes will + be assigned sane defaults. For some public attributes defined by this hook script, the corresponding private + attributes will be transformed into objects more readily and safely consumed elsewhere by external callers. + + See Also + ---------- + Class docstring for supported attributes. + """ + + # If this hook script module has already been loaded, or we are _shallow, noop. + if (self._loaded and (self._hook_module is not None or not keep_module_ref)) or self._shallow: + if self._shallow: + self._loaded = True + self._hook_module = True # Not None + # Inform the user + logger.debug( + 'Skipping module hook %r from %r because a hook for %s has already been loaded.', + *os.path.split(self.hook_filename)[::-1], self.module_name + ) + # Set the default attributes to empty instances of the type. + for attr_name, (attr_type, _) in _MAGIC_MODULE_HOOK_ATTRS.items(): + super().__setattr__(attr_name, attr_type()) + return + + # Load and execute the hook script. Even if mechanisms from the import machinery are used, this does not import + # the hook as the module. + head, tail = os.path.split(self.hook_filename) + logger.info('Loading module hook %r from %r...', tail, head) + try: + self._hook_module = importlib_load_source(self.hook_module_name, self.hook_filename) + except ImportError: + logger.debug("Hook failed with:", exc_info=True) + raise ImportErrorWhenRunningHook(self.hook_module_name, self.hook_filename) + + # Mark as loaded + self._loaded = True + + # Check if module has hook() function. + self._has_hook_function = hasattr(self._hook_module, 'hook') + + # Copy hook script attributes into magic attributes exposed as instance variables of the current "ModuleHook" + # instance. + for attr_name, (default_type, sanitizer_func) in _MAGIC_MODULE_HOOK_ATTRS.items(): + # Unsanitized value of this attribute. + attr_value = getattr(self._hook_module, attr_name, None) + + # If this attribute is undefined, expose a sane default instead. + if attr_value is None: + attr_value = default_type() + # Else if this attribute requires sanitization, do so. + elif sanitizer_func is not None: + attr_value = sanitizer_func(attr_value) + # Else, expose the unsanitized value of this attribute. + + # Expose this attribute as an instance variable of the same name. + setattr(self, attr_name, attr_value) + + # If module_collection_mode has an entry with None key, reassign it to the hooked module's name. + setattr( + self, 'module_collection_mode', { + key if key is not None else self.module_name: value + for key, value in getattr(self, 'module_collection_mode').items() + } + ) + + # Release the module if we do not need the reference. This is the case when hook is loaded during the analysis + # rather as part of the post-graph operations. + if not keep_module_ref: + self._hook_module = None + + #-- Hooks -- + + def post_graph(self, analysis): + """ + Call the **post-graph hook** (i.e., `hook()` function) defined by this hook script, if any. + + Parameters + ---------- + analysis: build_main.Analysis + Analysis that calls the hook + + This method is intended to be called _after_ the module graph for this application is constructed. + """ + + # Lazily load this hook script into an in-memory module. + # The script might have been loaded before during modulegraph analysis; in that case, it needs to be reloaded + # only if it provides a hook() function. + if not self._loaded or self._has_hook_function: + # Keep module reference when loading the hook, so we can call its hook function! + self._load_hook_module(keep_module_ref=True) + + # Call this hook script's hook() function, which modifies attributes accessed by subsequent methods and + # hence must be called first. + self._process_hook_func(analysis) + + # Order is insignificant here. + self._process_hidden_imports() + + def _process_hook_func(self, analysis): + """ + Call this hook's `hook()` function if defined. + + Parameters + ---------- + analysis: build_main.Analysis + Analysis that calls the hook + """ + + # If this hook script defines no hook() function, noop. + if not hasattr(self._hook_module, 'hook'): + return + + # Call this hook() function. + hook_api = PostGraphAPI(module_name=self.module_name, module_graph=self.module_graph, analysis=analysis) + try: + self._hook_module.hook(hook_api) + except ImportError: + logger.debug("Hook failed with:", exc_info=True) + raise ImportErrorWhenRunningHook(self.hook_module_name, self.hook_filename) + + # Update all magic attributes modified by the prior call. + self.datas.update(set(hook_api._added_datas)) + self.binaries.update(set(hook_api._added_binaries)) + self.hiddenimports.extend(hook_api._added_imports) + self.module_collection_mode.update(hook_api._module_collection_mode) + + # FIXME: `hook_api._deleted_imports` should be appended to `self.excludedimports` and used to suppress module + # import during the modulegraph construction rather than handled here. However, for that to work, the `hook()` + # function needs to be ran during modulegraph construction instead of in post-processing (and this in turn + # requires additional code refactoring in order to be able to pass `analysis` to `PostGraphAPI` object at + # that point). So once the modulegraph rewrite is complete, remove the code block below. + for deleted_module_name in hook_api._deleted_imports: + # Remove the graph link between the hooked module and item. This removes the 'item' node from the graph if + # no other links go to it (no other modules import it) + self.module_graph.removeReference(hook_api.node, deleted_module_name) + + def _process_hidden_imports(self): + """ + Add all imports listed in this hook script's `hiddenimports` attribute to the module graph as if directly + imported by this hooked module. + + These imports are typically _not_ implicitly detectable by PyInstaller and hence must be explicitly defined + by hook scripts. + """ + + # For each hidden import required by the module being hooked... + for import_module_name in self.hiddenimports: + try: + # Graph node for this module. Do not implicitly create namespace packages for non-existent packages. + caller = self.module_graph.find_node(self.module_name, create_nspkg=False) + + # Manually import this hidden import from this module. + self.module_graph.import_hook(import_module_name, caller) + # If this hidden import is unimportable, print a non-fatal warning. Hidden imports often become + # desynchronized from upstream packages and hence are only "soft" recommendations. + except ImportError: + if self.warn_on_missing_hiddenimports: + logger.warning('Hidden import "%s" not found!', import_module_name) + + +class AdditionalFilesCache: + """ + Cache for storing what binaries and datas were pushed by what modules when import hooks were processed. + """ + def __init__(self): + self._binaries = {} + self._datas = {} + + def add(self, modname, binaries, datas): + + self._binaries.setdefault(modname, []) + self._binaries[modname].extend(binaries or []) + self._datas.setdefault(modname, []) + self._datas[modname].extend(datas or []) + + def __contains__(self, name): + return name in self._binaries or name in self._datas + + def binaries(self, modname): + """ + Return list of binaries for given module name. + """ + return self._binaries[modname] + + def datas(self, modname): + """ + Return list of datas for given module name. + """ + return self._datas[modname] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/imphookapi.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/imphookapi.py new file mode 100755 index 000000000..38a35efba --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/imphookapi.py @@ -0,0 +1,475 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Classes facilitating communication between PyInstaller and import hooks. + +PyInstaller passes instances of classes defined by this module to corresponding functions defined by external import +hooks, which commonly modify the contents of these instances before returning. PyInstaller then detects and converts +these modifications into appropriate operations on the current `PyiModuleGraph` instance, thus modifying which +modules will be frozen into the executable. +""" + +from PyInstaller.building.utils import format_binaries_and_datas +from PyInstaller.lib.modulegraph.modulegraph import (RuntimeModule, RuntimePackage) + + +class PreSafeImportModuleAPI: + """ + Metadata communicating changes made by the current **pre-safe import module hook** (i.e., hook run immediately + _before_ a call to `ModuleGraph._safe_import_module()` recursively adding the hooked module, package, + or C extension and all transitive imports thereof to the module graph) back to PyInstaller. + + Pre-safe import module hooks _must_ define a `pre_safe_import_module()` function accepting an instance of this + class, whose attributes describe the subsequent `ModuleGraph._safe_import_module()` call creating the hooked + module's graph node. + + Each pre-safe import module hook is run _only_ on the first attempt to create the hooked module's graph node and + then subsequently ignored. If this hook successfully creates that graph node, the subsequent + `ModuleGraph._safe_import_module()` call will observe this fact and silently return without attempting to + recreate that graph node. + + Pre-safe import module hooks are typically used to create graph nodes for **runtime modules** (i.e., + modules dynamically defined at runtime). Most modules are physically defined in external `.py`-suffixed scripts. + Some modules, however, are dynamically defined at runtime (e.g., `six.moves`, dynamically defined by the + physically defined `six.py` module). However, `ModuleGraph` only parses `import` statements residing in external + scripts. `ModuleGraph` is _not_ a full-fledged, Turing-complete Python interpreter and hence has no means of + parsing `import` statements performed by runtime modules existing only in-memory. + + 'With great power comes great responsibility.' + + + Attributes (Immutable) + ---------------------------- + The following attributes are **immutable** (i.e., read-only). For safety, any attempts to change these attributes + _will_ result in a raised exception: + + module_graph : PyiModuleGraph + Current module graph. + parent_package : Package + Graph node for the package providing this module _or_ `None` if this module is a top-level module. + + Attributes (Mutable) + ----------------------------- + The following attributes are editable. + + module_basename : str + Unqualified name of the module to be imported (e.g., `text`). + module_name : str + Fully-qualified name of this module (e.g., `email.mime.text`). + """ + def __init__(self, module_graph, module_basename, module_name, parent_package): + self._module_graph = module_graph + self.module_basename = module_basename + self.module_name = module_name + self._parent_package = parent_package + + # Immutable properties. No corresponding setters are defined. + @property + def module_graph(self): + """ + Current module graph. + """ + return self._module_graph + + @property + def parent_package(self): + """ + Parent Package of this node. + """ + return self._parent_package + + def add_runtime_module(self, module_name): + """ + Add a graph node representing a non-package Python module with the passed name dynamically defined at runtime. + + Most modules are statically defined on-disk as standard Python files. Some modules, however, are dynamically + defined in-memory at runtime (e.g., `gi.repository.Gst`, dynamically defined by the statically defined + `gi.repository.__init__` module). + + This method adds a graph node representing such a runtime module. Since this module is _not_ a package, + all attempts to import submodules from this module in `from`-style import statements (e.g., the `queue` + submodule in `from six.moves import queue`) will be silently ignored. To circumvent this, simply call + `add_runtime_package()` instead. + + Parameters + ---------- + module_name : str + Fully-qualified name of this module (e.g., `gi.repository.Gst`). + + Examples + ---------- + This method is typically called by `pre_safe_import_module()` hooks, e.g.: + + def pre_safe_import_module(api): + api.add_runtime_module(api.module_name) + """ + + self._module_graph.add_module(RuntimeModule(module_name)) + + def add_runtime_package(self, package_name): + """ + Add a graph node representing a non-namespace Python package with the passed name dynamically defined at + runtime. + + Most packages are statically defined on-disk as standard subdirectories containing `__init__.py` files. Some + packages, however, are dynamically defined in-memory at runtime (e.g., `six.moves`, dynamically defined by + the statically defined `six` module). + + This method adds a graph node representing such a runtime package. All attributes imported from this package + in `from`-style import statements that are submodules of this package (e.g., the `queue` submodule in `from + six.moves import queue`) will be imported rather than ignored. + + Parameters + ---------- + package_name : str + Fully-qualified name of this package (e.g., `six.moves`). + + Examples + ---------- + This method is typically called by `pre_safe_import_module()` hooks, e.g.: + + def pre_safe_import_module(api): + api.add_runtime_package(api.module_name) + """ + + self._module_graph.add_module(RuntimePackage(package_name)) + + def add_alias_module(self, real_module_name, alias_module_name): + """ + Alias the source module to the target module with the passed names. + + This method ensures that the next call to findNode() given the target module name will resolve this alias. + This includes importing and adding a graph node for the source module if needed as well as adding a reference + from the target to the source module. + + Parameters + ---------- + real_module_name : str + Fully-qualified name of the **existing module** (i.e., the module being aliased). + alias_module_name : str + Fully-qualified name of the **non-existent module** (i.e., the alias to be created). + """ + + self._module_graph.alias_module(real_module_name, alias_module_name) + + def append_package_path(self, directory): + """ + Modulegraph does a good job at simulating Python's, but it cannot handle packagepath `__path__` modifications + packages make at runtime. + + Therefore there is a mechanism whereby you can register extra paths in this map for a package, and it will be + honored. + + Parameters + ---------- + directory : str + Absolute or relative path of the directory to be appended to this package's `__path__` attribute. + """ + + self._module_graph.append_package_path(self.module_name, directory) + + +class PreFindModulePathAPI: + """ + Metadata communicating changes made by the current **pre-find module path hook** (i.e., hook run immediately + _before_ a call to `ModuleGraph._find_module_path()` finding the hooked module's absolute path) back to PyInstaller. + + Pre-find module path hooks _must_ define a `pre_find_module_path()` function accepting an instance of this class, + whose attributes describe the subsequent `ModuleGraph._find_module_path()` call to be performed. + + Pre-find module path hooks are typically used to change the absolute path from which a module will be + subsequently imported and thus frozen into the executable. To do so, hooks may overwrite the default + `search_dirs` list of the absolute paths of all directories to be searched for that module: e.g., + + def pre_find_module_path(api): + api.search_dirs = ['/the/one/true/package/providing/this/module'] + + Each pre-find module path hook is run _only_ on the first call to `ModuleGraph._find_module_path()` for the + corresponding module. + + Attributes + ---------- + The following attributes are **mutable** (i.e., modifiable). All changes to these attributes will be immediately + respected by PyInstaller: + + search_dirs : list + List of the absolute paths of all directories to be searched for this module (in order). Searching will halt + at the first directory containing this module. + + Attributes (Immutable) + ---------- + The following attributes are **immutable** (i.e., read-only). For safety, any attempts to change these attributes + _will_ result in a raised exception: + + module_name : str + Fully-qualified name of this module. + module_graph : PyiModuleGraph + Current module graph. For efficiency, this attribute is technically mutable. To preserve graph integrity, + this attribute should nonetheless _never_ be modified. While read-only `PyiModuleGraph` methods (e.g., + `findNode()`) are safely callable from within pre-find module path hooks, methods modifying the graph are + _not_. If graph modifications are required, consider an alternative type of hook (e.g., pre-import module + hooks). + """ + def __init__( + self, + module_graph, + module_name, + search_dirs, + ): + # Mutable attributes. + self.search_dirs = search_dirs + + # Immutable attributes. + self._module_graph = module_graph + self._module_name = module_name + + # Immutable properties. No corresponding setters are defined. + @property + def module_graph(self): + """ + Current module graph. + """ + return self._module_graph + + @property + def module_name(self): + """ + Fully-qualified name of this module. + """ + return self._module_name + + +class PostGraphAPI: + """ + Metadata communicating changes made by the current **post-graph hook** (i.e., hook run for a specific module + transitively imported by the current application _after_ the module graph of all `import` statements performed by + this application has been constructed) back to PyInstaller. + + Post-graph hooks may optionally define a `post_graph()` function accepting an instance of this class, + whose attributes describe the current state of the module graph and the hooked module's graph node. + + Attributes (Mutable) + ---------- + The following attributes are **mutable** (i.e., modifiable). All changes to these attributes will be immediately + respected by PyInstaller: + + module_graph : PyiModuleGraph + Current module graph. + module : Node + Graph node for the currently hooked module. + + 'With great power comes great responsibility.' + + Attributes (Immutable) + ---------- + The following attributes are **immutable** (i.e., read-only). For safety, any attempts to change these attributes + _will_ result in a raised exception: + + __name__ : str + Fully-qualified name of this module (e.g., `six.moves.tkinter`). + __file__ : str + Absolute path of this module. If this module is: + * A standard (rather than namespace) package, this is the absolute path of this package's directory. + * A namespace (rather than standard) package, this is the abstract placeholder `-`. (Don't ask. Don't tell.) + * A non-package module or C extension, this is the absolute path of the corresponding file. + __path__ : list + List of the absolute paths of all directories comprising this package if this module is a package _or_ `None` + otherwise. If this module is a standard (rather than namespace) package, this list contains only the absolute + path of this package's directory. + co : code + Code object compiled from the contents of `__file__` (e.g., via the `compile()` builtin). + analysis: build_main.Analysis + The Analysis that load the hook. + + Attributes (Private) + ---------- + The following attributes are technically mutable but private, and hence should _never_ be externally accessed or + modified by hooks. Call the corresponding public methods instead: + + _added_datas : list + List of the `(name, path)` 2-tuples or TOC objects of all external data files required by the current hook, + defaulting to the empty list. This is equivalent to the global `datas` hook attribute. + _added_imports : list + List of the fully-qualified names of all modules imported by the current hook, defaulting to the empty list. + This is equivalent to the global `hiddenimports` hook attribute. + _added_binaries : list + List of the `(name, path)` 2-tuples or TOC objects of all external C extensions imported by the current hook, + defaulting to the empty list. This is equivalent to the global `binaries` hook attribute. + _module_collection_mode : dict + Dictionary of package/module names and their corresponding collection mode strings. This is equivalent to the + global `module_collection_mode` hook attribute. + """ + def __init__(self, module_name, module_graph, analysis): + # Mutable attributes. + self.module_graph = module_graph + self.module = module_graph.find_node(module_name) + assert self.module is not None # should not occur + + # Immutable attributes. + self.___name__ = module_name + self.___file__ = self.module.filename + self._co = self.module.code + self._analysis = analysis + + # To enforce immutability, convert this module's package path if any into an immutable tuple. + self.___path__ = tuple(self.module.packagepath) \ + if self.module.packagepath is not None else None + + #FIXME: Refactor "_added_datas", "_added_binaries", and "_deleted_imports" into sets. Since order of + #import is important, "_added_imports" must remain a list. + + # Private attributes. + self._added_binaries = [] + self._added_datas = [] + self._added_imports = [] + self._deleted_imports = [] + self._module_collection_mode = {} + + # Immutable properties. No corresponding setters are defined. + @property + def __file__(self): + """ + Absolute path of this module's file. + """ + return self.___file__ + + @property + def __path__(self): + """ + List of the absolute paths of all directories comprising this package if this module is a package _or_ `None` + otherwise. If this module is a standard (rather than namespace) package, this list contains only the absolute + path of this package's directory. + """ + return self.___path__ + + @property + def __name__(self): + """ + Fully-qualified name of this module (e.g., `six.moves.tkinter`). + """ + return self.___name__ + + @property + def co(self): + """ + Code object compiled from the contents of `__file__` (e.g., via the `compile()` builtin). + """ + return self._co + + @property + def analysis(self): + """ + build_main.Analysis that calls the hook. + """ + return self._analysis + + # Obsolete immutable properties provided to preserve backward compatibility. + @property + def name(self): + """ + Fully-qualified name of this module (e.g., `six.moves.tkinter`). + + **This property has been deprecated by the `__name__` property.** + """ + return self.___name__ + + @property + def graph(self): + """ + Current module graph. + + **This property has been deprecated by the `module_graph` property.** + """ + return self.module_graph + + @property + def node(self): + """ + Graph node for the currently hooked module. + + **This property has been deprecated by the `module` property.** + """ + return self.module + + # TODO: This incorrectly returns the list of the graph nodes of all modules *TRANSITIVELY* (rather than directly) + # imported by this module. Unfortunately, this implies that most uses of this property are currently broken + # (e.g., "hook-PIL.SpiderImagePlugin.py"). We only require this for the aforementioned hook, so contemplate + # alternative approaches. + @property + def imports(self): + """ + List of the graph nodes of all modules directly imported by this module. + """ + return self.module_graph.iter_graph(start=self.module) + + def add_imports(self, *module_names): + """ + Add all Python modules whose fully-qualified names are in the passed list as "hidden imports" upon which the + current module depends. + + This is equivalent to appending such names to the hook-specific `hiddenimports` attribute. + """ + # Append such names to the current list of all such names. + self._added_imports.extend(module_names) + + def del_imports(self, *module_names): + """ + Remove the named fully-qualified modules from the set of imports (either hidden or visible) upon which the + current module depends. + + This is equivalent to appending such names to the hook-specific `excludedimports` attribute. + """ + self._deleted_imports.extend(module_names) + + def add_binaries(self, binaries): + """ + Add all external dynamic libraries in the passed list of `(src_name, dest_name)` 2-tuples as dependencies of the + current module. This is equivalent to adding to the global `binaries` hook attribute. + + For convenience, the `binaries` may also be a list of TOC-style 3-tuples `(dest_name, src_name, typecode)`. + """ + + # Detect TOC 3-tuple list by checking the length of the first entry + if binaries and len(binaries[0]) == 3: + self._added_binaries.extend(entry[:2] for entry in binaries) + else: + # NOTE: `format_binaries_and_datas` changes tuples from input format `(src_name, dest_name)` to output + # format `(dest_name, src_name)`. + self._added_binaries.extend(format_binaries_and_datas(binaries)) + + def add_datas(self, datas): + """ + Add all external data files in the passed list of `(src_name, dest_name)` 2-tuples as dependencies of the + current module. This is equivalent to adding to the global `datas` hook attribute. + + For convenience, the `datas` may also be a list of TOC-style 3-tuples `(dest_name, src_name, typecode)`. + """ + + # Detect TOC 3-tuple list by checking the length of the first entry + if datas and len(datas[0]) == 3: + self._added_datas.extend(entry[:2] for entry in datas) + else: + # NOTE: `format_binaries_and_datas` changes tuples from input format `(src_name, dest_name)` to output + # format `(dest_name, src_name)`. + self._added_datas.extend(format_binaries_and_datas(datas)) + + def set_module_collection_mode(self, name, mode): + """" + Set the package/module collection mode for the specified module name. If `name` is `None`, the hooked + module/package name is used. `mode` can be one of valid mode strings (`'pyz'`, `'pyc'`, ˙'py'˙, `'pyz+py'`, + ˙'py+pyz'`) or `None`, which clears the setting for the module/package - but only within this hook's context! + """ + if name is None: + name = self.__name__ + if mode is None: + self._module_collection_mode.pop(name) + else: + self._module_collection_mode[name] = mode diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/utils.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/utils.py new file mode 100755 index 000000000..84f43adbe --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/depend/utils.py @@ -0,0 +1,420 @@ +# -*- coding: utf-8 -*- +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Utility functions related to analyzing/bundling dependencies. +""" + +import ctypes.util +import io +import os +import re +import struct +import zipfile +from types import CodeType + +import marshal + +from PyInstaller import compat +from PyInstaller import log as logging +from PyInstaller.depend import bytecode +from PyInstaller.depend.dylib import include_library +from PyInstaller.exceptions import ExecCommandFailed +from PyInstaller.lib.modulegraph import modulegraph + +logger = logging.getLogger(__name__) + + +# TODO find out if modules from base_library.zip could be somehow bundled into the .exe file. +def create_py3_base_library(libzip_filename, graph): + """ + Package basic Python modules into .zip file. The .zip file with basic modules is necessary to have on PYTHONPATH + for initializing libpython3 in order to run the frozen executable with Python 3. + """ + # Import strip_paths_in_code locally to avoid cyclic import between building.utils and depend.utils (this module); + # building.utils imports depend.bindepend, which in turn imports depend.utils. + from PyInstaller.building.utils import strip_paths_in_code + + # Construct regular expression for matching modules that should be bundled into base_library.zip. Excluded are plain + # 'modules' or 'submodules.ANY_NAME'. The match has to be exact - start and end of string not substring. + regex_modules = '|'.join([rf'(^{x}$)' for x in compat.PY3_BASE_MODULES]) + regex_submod = '|'.join([rf'(^{x}\..*$)' for x in compat.PY3_BASE_MODULES]) + regex_str = regex_modules + '|' + regex_submod + module_filter = re.compile(regex_str) + + try: + # Remove .zip from previous run. + if os.path.exists(libzip_filename): + os.remove(libzip_filename) + logger.debug('Adding python files to base_library.zip') + # Class zipfile.PyZipFile is not suitable for PyInstaller needs. + with zipfile.ZipFile(libzip_filename, mode='w') as zf: + zf.debug = 3 + # Sort the graph nodes by identifier to ensure repeatable builds + graph_nodes = list(graph.iter_graph()) + graph_nodes.sort(key=lambda item: item.identifier) + for mod in graph_nodes: + if type(mod) in (modulegraph.SourceModule, modulegraph.Package, modulegraph.CompiledModule): + # Bundling just required modules. + if module_filter.match(mod.identifier): + # Name inside the archive. The ZIP format specification requires forward slashes as directory + # separator. + if type(mod) is modulegraph.Package: + new_name = mod.identifier.replace('.', '/') + '/__init__.pyc' + else: + new_name = mod.identifier.replace('.', '/') + '.pyc' + + # Write code to a file. This code is similar to py_compile.compile(). + with io.BytesIO() as fc: + fc.write(compat.BYTECODE_MAGIC) + fc.write(struct.pack('>> _resolveCtypesImports(['libgs.so']) + [(libgs.so', ''/usr/lib/libgs.so', 'BINARY')] + """ + from ctypes.util import find_library + + from PyInstaller.config import CONF + + if compat.is_unix: + envvar = "LD_LIBRARY_PATH" + elif compat.is_darwin: + envvar = "DYLD_LIBRARY_PATH" + else: + envvar = "PATH" + + def _setPaths(): + path = os.pathsep.join(CONF['pathex']) + old = compat.getenv(envvar) + if old is not None: + path = os.pathsep.join((path, old)) + compat.setenv(envvar, path) + return old + + def _restorePaths(old): + if old is None: + compat.unsetenv(envvar) + else: + compat.setenv(envvar, old) + + ret = [] + + # Try to locate the shared library on the disk. This is done by calling ctypes.util.find_library with + # ImportTracker's local paths temporarily prepended to the library search paths (and restored after the call). + old = _setPaths() + for cbin in cbinaries: + try: + # There is an issue with find_library() where it can run into errors trying to locate the library. See + # #5734. + cpath = find_library(os.path.splitext(cbin)[0]) + except FileNotFoundError: + # In these cases, find_library() should return None. + cpath = None + if compat.is_unix: + # CAVEAT: find_library() is not the correct function. ctype's documentation says that it is meant to resolve + # only the filename (as a *compiler* does) not the full path. Anyway, it works well enough on Windows and + # Mac OS. On Linux, we need to implement more code to find out the full path. + if cpath is None: + cpath = cbin + # "man ld.so" says that we should first search LD_LIBRARY_PATH and then the ldcache. + for d in compat.getenv(envvar, '').split(os.pathsep): + if os.path.isfile(os.path.join(d, cpath)): + cpath = os.path.join(d, cpath) + break + else: + if LDCONFIG_CACHE is None: + load_ldconfig_cache() + if cpath in LDCONFIG_CACHE: + cpath = LDCONFIG_CACHE[cpath] + assert os.path.isfile(cpath) + else: + cpath = None + if cpath is None: + # Skip warning message if cbin (basename of library) is ignored. This prevents messages like: + # 'W: library kernel32.dll required via ctypes not found' + if not include_library(cbin): + continue + logger.warning("Library %s required via ctypes not found", cbin) + else: + if not include_library(cpath): + continue + ret.append((cbin, cpath, "BINARY")) + _restorePaths(old) + return ret + + +LDCONFIG_CACHE = None # cache the output of `/sbin/ldconfig -p` + + +def load_ldconfig_cache(): + """ + Create a cache of the `ldconfig`-output to call it only once. + It contains thousands of libraries and running it on every dylib is expensive. + """ + global LDCONFIG_CACHE + + if LDCONFIG_CACHE is not None: + return + + if compat.is_musl: + # Musl deliberately doesn't use ldconfig. The ldconfig executable either doesn't exist or it's a functionless + # executable which, on calling with any arguments, simply tells you that those arguments are invalid. + LDCONFIG_CACHE = {} + return + + from distutils.spawn import find_executable + ldconfig = find_executable('ldconfig') + if ldconfig is None: + # If `ldconfig` is not found in $PATH, search for it in some fixed directories. Simply use a second call instead + # of fiddling around with checks for empty env-vars and string-concat. + ldconfig = find_executable('ldconfig', '/usr/sbin:/sbin:/usr/bin:/usr/sbin') + + # If we still could not find the 'ldconfig' command... + if ldconfig is None: + LDCONFIG_CACHE = {} + return + + if compat.is_freebsd or compat.is_openbsd: + # This has a quite different format than other Unixes: + # [vagrant@freebsd-10 ~]$ ldconfig -r + # /var/run/ld-elf.so.hints: + # search directories: /lib:/usr/lib:/usr/lib/compat:... + # 0:-lgeom.5 => /lib/libgeom.so.5 + # 184:-lpython2.7.1 => /usr/local/lib/libpython2.7.so.1 + ldconfig_arg = '-r' + splitlines_count = 2 + pattern = re.compile(r'^\s+\d+:-l(\S+)(\s.*)? => (\S+)') + else: + # Skip first line of the library list because it is just an informative line and might contain localized + # characters. Example of first line with locale set to cs_CZ.UTF-8: + #$ /sbin/ldconfig -p + #V keši „/etc/ld.so.cache“ nalezeno knihoven: 2799 + # libzvbi.so.0 (libc6,x86-64) => /lib64/libzvbi.so.0 + # libzvbi-chains.so.0 (libc6,x86-64) => /lib64/libzvbi-chains.so.0 + ldconfig_arg = '-p' + splitlines_count = 1 + pattern = re.compile(r'^\s+(\S+)(\s.*)? => (\S+)') + + try: + text = compat.exec_command(ldconfig, ldconfig_arg) + except ExecCommandFailed: + logger.warning("Failed to execute ldconfig. Disabling LD cache.") + LDCONFIG_CACHE = {} + return + + text = text.strip().splitlines()[splitlines_count:] + + LDCONFIG_CACHE = {} + for line in text: + # :fixme: this assumes library names do not contain whitespace + m = pattern.match(line) + + # Sanitize away any abnormal lines of output. + if m is None: + # Warn about it then skip the rest of this iteration. + if re.search("Cache generated by:", line): + # See #5540. This particular line is harmless. + pass + else: + logger.warning("Unrecognised line of output %r from ldconfig", line) + continue + + path = m.groups()[-1] + if compat.is_freebsd or compat.is_openbsd: + # Insert `.so` at the end of the lib's basename. soname and filename may have (different) trailing versions. + # We assume the `.so` in the filename to mark the end of the lib's basename. + bname = os.path.basename(path).split('.so', 1)[0] + name = 'lib' + m.group(1) + assert name.startswith(bname) + name = bname + '.so' + name[len(bname):] + else: + name = m.group(1) + # ldconfig may know about several versions of the same lib, e.g., different arch, different libc, etc. + # Use the first entry. + if name not in LDCONFIG_CACHE: + LDCONFIG_CACHE[name] = path + + +def get_path_to_egg(path): + """ + Return the path to the python egg file, if the given path points to a file inside (or directly to) an egg. + Return `None` otherwise. + """ + # This assumes that eggs are not nested. + # TODO: add support for unpacked eggs and for new .whl packages. + lastpath = None # marker to stop recursion + while path and path != lastpath: + if os.path.splitext(path)[1].lower() == ".egg": + if os.path.isfile(path) or os.path.isdir(path): + return path + lastpath = path + path = os.path.dirname(path) + return None + + +def is_path_to_egg(path): + """ + Check if the given path points to a file inside (or directly to) a python egg file. + """ + return get_path_to_egg(path) is not None diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/exceptions.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/exceptions.py new file mode 100755 index 000000000..f3d4387cb --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/exceptions.py @@ -0,0 +1,30 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +class ExecCommandFailed(SystemExit): + pass + + +class HookError(Exception): + """ + Base class for hook related errors. + """ + pass + + +class ImportErrorWhenRunningHook(HookError): + def __str__(self): + return ( + "Failed to import module {0} required by hook for module {1}. Please check whether module {0} actually " + "exists and whether the hook is compatible with your version of {1}: You might want to read more about " + "hooks in the manual and provide a pull-request to improve PyInstaller.".format(self.args[0], self.args[1]) + ) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/fake-modules/_pyi_rth_utils/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/fake-modules/_pyi_rth_utils/__init__.py new file mode 100755 index 000000000..7db4d4bc1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/fake-modules/_pyi_rth_utils/__init__.py @@ -0,0 +1,57 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +# ----------------------------------------------------------------------------- + +import os +import sys +import errno +import tempfile + +# Helper for creating temporary directories with access restricted to the user running the process. +# On POSIX systems, this is already achieved by `tempfile.mkdtemp`, which uses 0o700 permissions mask. +# On Windows, however, the POSIX permissions semantics have no effect, and we need to provide our own implementation +# that restricts the access by passing appropriate security attributes to the `CreateDirectory` function. + +if os.name == 'nt': + from . import _win32 + + def secure_mkdtemp(suffix=None, prefix=None, dir=None): + """ + Windows-specific replacement for `tempfile.mkdtemp` that restricts access to the user running the process. + Based on `mkdtemp` implementation from python 3.11 stdlib. + """ + + prefix, suffix, dir, output_type = tempfile._sanitize_params(prefix, suffix, dir) + + names = tempfile._get_candidate_names() + if output_type is bytes: + names = map(os.fsencode, names) + + for seq in range(tempfile.TMP_MAX): + name = next(names) + file = os.path.join(dir, prefix + name + suffix) + if sys.version_info >= (3, 8): + sys.audit("tempfile.mkdtemp", file) + try: + _win32.secure_mkdir(file) + except FileExistsError: + continue # try again + except PermissionError: + # This exception is thrown when a directory with the chosen name already exists on windows. + if (os.name == 'nt' and os.path.isdir(dir) and os.access(dir, os.W_OK)): + continue + else: + raise + return file + + raise FileExistsError(errno.EEXIST, "No usable temporary directory name found") + +else: + secure_mkdtemp = tempfile.mkdtemp diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/fake-modules/_pyi_rth_utils/_win32.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/fake-modules/_pyi_rth_utils/_win32.py new file mode 100755 index 000000000..41237fb97 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/fake-modules/_pyi_rth_utils/_win32.py @@ -0,0 +1,262 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +# ----------------------------------------------------------------------------- + +import ctypes +import ctypes.wintypes + +# Constants from win32 headers +TOKEN_QUERY = 0x0008 + +TokenUser = 1 # from TOKEN_INFORMATION_CLASS enum + +ERROR_INSUFFICIENT_BUFFER = 122 + +INVALID_HANDLE = -1 + +FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100 +FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000 + +SDDL_REVISION1 = 1 + +# Structures for ConvertSidToStringSidW +PSID = ctypes.wintypes.LPVOID + + +class SID_AND_ATTRIBUTES(ctypes.Structure): + _fields_ = [ + ("Sid", PSID), + ("Attributes", ctypes.wintypes.DWORD), + ] + + +class TOKEN_USER(ctypes.Structure): + _fields_ = [ + ("User", SID_AND_ATTRIBUTES), + ] + + +PTOKEN_USER = ctypes.POINTER(TOKEN_USER) + +# SECURITY_ATTRIBUTES structure for CreateDirectoryW +PSECURITY_DESCRIPTOR = ctypes.wintypes.LPVOID + + +class SECURITY_ATTRIBUTES(ctypes.Structure): + _fields_ = [ + ("nLength", ctypes.wintypes.DWORD), + ("lpSecurityDescriptor", PSECURITY_DESCRIPTOR), + ("bInheritHandle", ctypes.wintypes.BOOL), + ] + + +# win32 API functions, bound via ctypes. +# NOTE: we do not use ctypes.windll. to avoid modifying its (global) function prototypes, which might affect +# user's code. +kernel32 = ctypes.WinDLL("kernel32") +advapi32 = ctypes.WinDLL("advapi32") + +kernel32.CloseHandle.restype = ctypes.wintypes.BOOL +kernel32.CloseHandle.argtypes = (ctypes.wintypes.HANDLE,) + +kernel32.LocalFree.restype = ctypes.wintypes.BOOL +kernel32.LocalFree.argtypes = (ctypes.wintypes.HLOCAL,) + +kernel32.GetCurrentProcess.restype = ctypes.wintypes.HANDLE + +kernel32.OpenProcessToken.restype = ctypes.wintypes.BOOL +kernel32.OpenProcessToken.argtypes = ( + ctypes.wintypes.HANDLE, + ctypes.wintypes.DWORD, + ctypes.wintypes.PHANDLE, +) + +advapi32.ConvertSidToStringSidW.restype = ctypes.wintypes.BOOL +advapi32.ConvertSidToStringSidW.argtypes = ( + PSID, + ctypes.POINTER(ctypes.wintypes.LPWSTR), +) + +advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW.restype = ctypes.wintypes.BOOL +advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW.argtypes = ( + ctypes.wintypes.LPCWSTR, + ctypes.wintypes.DWORD, + ctypes.POINTER(PSECURITY_DESCRIPTOR), + ctypes.wintypes.PULONG, +) + + +def _win_error_to_message(error_code): + """ + Convert win32 error code to message. + """ + message_wstr = ctypes.wintypes.LPWSTR(None) + ret = kernel32.FormatMessageW( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + None, # lpSource + error_code, # dwMessageId + 0x400, # dwLanguageId = MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT) + ctypes.byref(message_wstr), # pointer to LPWSTR due to FORMAT_MESSAGE_ALLOCATE_BUFFER + 64, # due to FORMAT_MESSAGE_ALLOCATE_BUFFER, this is minimum number of characters to allocate + ) + if ret == 0: + return None + + message = message_wstr.value + kernel32.LocalFree(message_wstr) + + # Strip trailing CR/LF. + if message: + message = message.strip() + return message + + +def _get_user_sid(): + """ + Obtain the SID for the current user. + """ + process_token = ctypes.wintypes.HANDLE(INVALID_HANDLE) + + try: + # Get access token for the current process + ret = kernel32.OpenProcessToken( + kernel32.GetCurrentProcess(), + TOKEN_QUERY, + ctypes.pointer(process_token), + ) + if ret == 0: + error_code = kernel32.GetLastError() + raise RuntimeError(f"Failed to open process token! Error code: 0x{error_code:X}") + + # Query buffer size for user info structure + user_info_size = ctypes.wintypes.DWORD(0) + + ret = advapi32.GetTokenInformation( + process_token, + TokenUser, + None, + 0, + ctypes.byref(user_info_size), + ) + + # We expect this call to fail with ERROR_INSUFFICIENT_BUFFER + if ret == 0: + error_code = kernel32.GetLastError() + if error_code != ERROR_INSUFFICIENT_BUFFER: + raise RuntimeError(f"Failed to query token information buffer size! Error code: 0x{error_code:X}") + else: + raise RuntimeError("Unexpected return value from GetTokenInformation!") + + # Allocate buffer + user_info = ctypes.create_string_buffer(user_info_size.value) + ret = advapi32.GetTokenInformation( + process_token, + TokenUser, + user_info, + user_info_size, + ctypes.byref(user_info_size), + ) + if ret == 0: + error_code = kernel32.GetLastError() + raise RuntimeError(f"Failed to query token information! Error code: 0x{error_code:X}") + + # Convert SID to string + # Technically, we need to pass user_info->User.Sid, but as they are at the beginning of the + # buffer, just pass the buffer instead... + sid_wstr = ctypes.wintypes.LPWSTR(None) + ret = advapi32.ConvertSidToStringSidW( + ctypes.cast(user_info, PTOKEN_USER).contents.User.Sid, + ctypes.pointer(sid_wstr), + ) + if ret == 0: + error_code = kernel32.GetLastError() + raise RuntimeError(f"Failed to convert SID to string! Error code: 0x{error_code:X}") + sid = sid_wstr.value + kernel32.LocalFree(sid_wstr) + except Exception: + sid = None + finally: + # Close the process token + if process_token.value != INVALID_HANDLE: + kernel32.CloseHandle(process_token) + + return sid + + +# Get and cache current user's SID +_user_sid = _get_user_sid() + + +def secure_mkdir(dir_name): + """ + Replacement for mkdir that limits the access to created directory to current user. + """ + + # Create security descriptor + # Prefer actual user SID over SID S-1-3-4 (current owner), because at the time of writing, Wine does not properly + # support the latter. + sid = _user_sid or "S-1-3-4" + + # DACL descriptor (D): + # ace_type;ace_flags;rights;object_guid;inherit_object_guid;account_sid;(resource_attribute) + # - ace_type = SDDL_ACCESS_ALLOWED (A) + # - rights = SDDL_FILE_ALL (FA) + # - account_sid = current user (queried SID) + security_desc_str = f"D:(A;;FA;;;{sid})" + security_desc = ctypes.wintypes.LPVOID(None) + + ret = advapi32.ConvertStringSecurityDescriptorToSecurityDescriptorW( + security_desc_str, + SDDL_REVISION1, + ctypes.byref(security_desc), + None, + ) + if ret == 0: + error_code = kernel32.GetLastError() + raise RuntimeError( + f"Failed to create security descriptor! Error code: 0x{error_code:X}, " + f"message: {_win_error_to_message(error_code)}" + ) + + security_attr = SECURITY_ATTRIBUTES() + security_attr.nLength = ctypes.sizeof(SECURITY_ATTRIBUTES) + security_attr.lpSecurityDescriptor = security_desc + security_attr.bInheritHandle = False + + # Create directory + ret = kernel32.CreateDirectoryW( + dir_name, + security_attr, + ) + if ret == 0: + # Call failed; store error code immediately, to avoid it being overwritten in cleanup below. + error_code = kernel32.GetLastError() + + # Free security descriptor + kernel32.LocalFree(security_desc) + + # Exit on succeess + if ret != 0: + return + + # Construct OSError from win error code + error_message = _win_error_to_message(error_code) + + # Strip trailing dot to match error message from os.mkdir(). + if error_message and error_message[-1] == '.': + error_message = error_message[:-1] + + raise OSError( + None, # errno + error_message, # strerror + dir_name, # filename + error_code, # winerror + None, # filename2 + ) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/fake-modules/pyi_splash.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/fake-modules/pyi_splash.py new file mode 100755 index 000000000..6c7ef6384 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/fake-modules/pyi_splash.py @@ -0,0 +1,223 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +# ----------------------------------------------------------------------------- + +# This module is not a "fake module" in the classical sense, but a real module that can be imported. It acts as an RPC +# interface for the functions of the bootloader. +""" +This module connects to the bootloader to send messages to the splash screen. + +It is intended to act as a RPC interface for the functions provided by the bootloader, such as displaying text or +closing. This makes the users python program independent of how the communication with the bootloader is implemented, +since a consistent API is provided. + +To connect to the bootloader, it connects to a local tcp socket whose port is passed through the environment variable +'_PYIBoot_SPLASH'. The bootloader creates a server socket and accepts every connection request. Since the os-module, +which is needed to request the environment variable, is not available at boot time, the module does not establish the +connection until initialization. + +The protocol by which the Python interpreter communicates with the bootloader is implemented in this module. + +This module does not support reloads while the splash screen is displayed, i.e. it cannot be reloaded (such as by +importlib.reload), because the splash screen closes automatically when the connection to this instance of the module +is lost. +""" + +import atexit +import os + +# Import the _socket module instead of the socket module. All used functions to connect to the ipc system are +# provided by the C module and the users program does not necessarily need to include the socket module and all +# required modules it uses. +import _socket + +__all__ = ["CLOSE_CONNECTION", "FLUSH_CHARACTER", "is_alive", "close", "update_text"] + +try: + # The user might have excluded logging from imports. + import logging as _logging +except ImportError: + _logging = None + +try: + # The user might have excluded functools from imports. + from functools import update_wrapper +except ImportError: + update_wrapper = None + + +# Utility +def _log(level, msg, *args, **kwargs): + """ + Conditional wrapper around logging module. If the user excluded logging from the imports or it was not imported, + this function should handle it and avoid using the logger. + """ + if _logging: + logger = _logging.getLogger(__name__) + logger.log(level, msg, *args, **kwargs) + + +# These constants define single characters which are needed to send commands to the bootloader. Those constants are +# also set in the tcl script. +CLOSE_CONNECTION = b'\x04' # ASCII End-of-Transmission character +FLUSH_CHARACTER = b'\x0D' # ASCII Carriage Return character + +# Module internal variables +_initialized = False +# Keep these variables always synchronized +_ipc_socket_closed = True +_ipc_socket = _socket.socket(_socket.AF_INET, _socket.SOCK_STREAM) + + +def _initialize(): + """ + Initialize this module + + :return: + """ + global _initialized, _ipc_socket, _ipc_socket_closed + try: + _ipc_socket.connect(("localhost", _ipc_port)) + _ipc_socket_closed = False + + _initialized = True + _log(20, "A connection to the splash screen was successfully established.") # log-level: info + except OSError as err: + raise ConnectionError("Unable to connect to the tcp server socket on port %d" % _ipc_port) from err + + +# We expect a splash screen from the bootloader, but if _PYIBoot_SPLASH is not set, the module cannot connect to it. +try: + _ipc_port = int(os.environ['_PYIBoot_SPLASH']) + del os.environ['_PYIBoot_SPLASH'] + # Initialize the connection upon importing this module. This will establish a connection to the bootloader's TCP + # server socket. + _initialize() +except (KeyError, ValueError) as _err: + # log-level: warning + _log( + 30, "The environment does not allow connecting to the splash screen. Are the splash resources attached to the " + "bootloader or did an error occur?", + exc_info=_err + ) +except ConnectionError as _err: + # log-level: error + _log(40, "Cannot connect to the bootloaders ipc server socket", exc_info=_err) + + +def _check_connection(func): + """ + Utility decorator for checking whether the function should be executed. + + The wrapped function may raise a ConnectionError if the module was not initialized correctly. + """ + def wrapper(*args, **kwargs): + """ + Executes the wrapped function if the environment allows it. + + That is, if the connection to to bootloader has not been closed and the module is initialized. + + :raises RuntimeError: if the module was not initialized correctly. + """ + if _initialized and _ipc_socket_closed: + _log( + 20, "The module has been disabled, so the use of the splash screen is no longer supported." + ) # log-level: info + return + elif not _initialized: + raise RuntimeError("This module is not initialized; did it fail to load?") + + return func(*args, **kwargs) + + if update_wrapper: + # For runtime introspection + update_wrapper(wrapper, func) + + return wrapper + + +@_check_connection +def _send_command(cmd, args=None): + """ + Send the command followed by args to the splash screen. + + :param str cmd: The command to send. All command have to be defined as procedures in the tcl splash screen script. + :param list[str] args: All arguments to send to the receiving function + """ + if args is None: + args = [] + + full_cmd = "%s(%s)" % (cmd, " ".join(args)) + try: + _ipc_socket.sendall(full_cmd.encode("utf-8") + FLUSH_CHARACTER) + except OSError as err: + raise ConnectionError("Unable to send '%s' to the bootloader" % full_cmd) from err + + +def is_alive(): + """ + Indicates whether the module can be used. + + Returns False if the module is either not initialized or was disabled by closing the splash screen. Otherwise, + the module should be usable. + """ + return _initialized and not _ipc_socket_closed + + +@_check_connection +def update_text(msg: str): + """ + Updates the text on the splash screen window. + + :param str msg: the text to be displayed + :raises ConnectionError: If the OS fails to write to the socket. + :raises RuntimeError: If the module is not initialized. + """ + _send_command("update_text", [msg]) + + +def close(): + """ + Close the connection to the ipc tcp server socket. + + This will close the splash screen and renders this module unusable. After this function is called, no connection + can be opened to the splash screen again and all functions in this module become unusable. + """ + global _ipc_socket_closed + if _initialized and not _ipc_socket_closed: + _ipc_socket.sendall(CLOSE_CONNECTION) + _ipc_socket.close() + _ipc_socket_closed = True + + +@atexit.register +def _exit(): + close() + + +# Discarded idea: +# Problem: +# There was a race condition between the tcl (splash screen) and python interpreter. Initially the tcl was started as a +# separate thread next to the bootloader thread, which starts python. Tcl sets the environment variable +# '_PYIBoot_SPLASH' with a port to connect to. If the python interpreter is faster initialized than the tcl interpreter +# (sometimes the case in onedir mode) the environment variable does not yet exist. Since python caches the environment +# variables at startup, updating the environ from tcl does not update the python environ. +# +# Considered Solution: +# Dont rely on python itself to look up the environment variables. We could implement via ctypes functions to look up +# the latest environ. See https://stackoverflow.com/a/33642551/5869139 for a possible implementation. +# +# Discarded because: +# This module would need to implement for every supported OS a dll hook to link to the environ variable, technically +# reimplementing the C function 'convertenviron' from posixmodule.c_ in python. The implemented solution now waits for +# the tcl interpreter to finish before starting python. +# +# .. _posixmodule.c: +# https://github.com/python/cpython/blob/3.7/Modules/posixmodule.c#L1315-L1393 diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/__init__.py new file mode 100755 index 000000000..792d60054 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/__init__.py @@ -0,0 +1 @@ +# diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PIL.Image.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PIL.Image.py new file mode 100755 index 000000000..1d9e0297f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PIL.Image.py @@ -0,0 +1,17 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# This hook was tested with Pillow 2.9.0 (Maintained fork of PIL): https://pypi.python.org/pypi/Pillow + +from PyInstaller.utils.hooks import collect_submodules + +# Include all PIL image plugins - module names containing 'ImagePlugin'. e.g. PIL.JpegImagePlugin +hiddenimports = collect_submodules('PIL', lambda name: 'ImagePlugin' in name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PIL.ImageFilter.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PIL.ImageFilter.py new file mode 100755 index 000000000..528694b40 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PIL.ImageFilter.py @@ -0,0 +1,13 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# Only used if installed, not mean to pull in numpy. +excludedimports = ["numpy"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PIL.SpiderImagePlugin.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PIL.SpiderImagePlugin.py new file mode 100755 index 000000000..1b6466ffd --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PIL.SpiderImagePlugin.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# PIL's SpiderImagePlugin features a tkPhotoImage() method, which imports ImageTk (and thus brings in the whole Tcl/Tk +# library). Assume that if people are really using tkinter in their application, they will also import it directly. +excludedimports = ['tkinter'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PIL.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PIL.py new file mode 100755 index 000000000..b7a684916 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PIL.py @@ -0,0 +1,21 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# This hook was tested with Pillow 2.9.0 (Maintained fork of PIL): +# https://pypi.python.org/pypi/Pillow + +# Ignore tkinter to prevent inclusion of Tcl/Tk library and other GUI libraries. Assume that if people are really using +# tkinter in their application, they will also import it directly and thus PyInstaller bundles the right GUI library. +excludedimports = ['tkinter', 'PyQt5', 'PySide2', 'PyQt6', 'PySide6'] + +# Similarly, prevent inclusion of IPython, which in turn ends up pulling in whole matplotlib, along with its optional +# GUI library dependencies. +excludedimports += ['IPython'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QAxContainer.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QAxContainer.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QAxContainer.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qsci.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qsci.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qsci.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt.py new file mode 100755 index 000000000..3520f3cf8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt.py @@ -0,0 +1,29 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# When PyQt5.Qt is imported it implies the import of all PyQt5 modules. See +# http://pyqt.sourceforge.net/Docs/PyQt5/Qt.html. +import os + +from PyInstaller.utils.hooks import get_module_file_attribute + +# Only do this if PyQt5 is found. +mfi = get_module_file_attribute('PyQt5') +if mfi: + # Determine the name of all these modules by looking in the PyQt5 directory. + hiddenimports = [] + for f in os.listdir(os.path.dirname(mfi)): + root, ext = os.path.splitext(os.path.basename(f)) + if root.startswith('Qt') and root != 'Qt': + # On Linux and OS X, PyQt 5.14.1 has a ``.abi3`` suffix on all library names. Remove it. + if root.endswith('.abi3'): + root = root[:-5] + hiddenimports.append('PyQt5.' + root) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt3DAnimation.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt3DAnimation.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt3DAnimation.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt3DCore.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt3DCore.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt3DCore.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt3DExtras.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt3DExtras.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt3DExtras.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt3DInput.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt3DInput.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt3DInput.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt3DLogic.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt3DLogic.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt3DLogic.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt3DRender.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt3DRender.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.Qt3DRender.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtBluetooth.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtBluetooth.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtBluetooth.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtChart.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtChart.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtChart.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtCore.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtCore.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtCore.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtDBus.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtDBus.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtDBus.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtDataVisualization.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtDataVisualization.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtDataVisualization.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtDesigner.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtDesigner.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtDesigner.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtGui.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtGui.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtGui.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtHelp.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtHelp.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtHelp.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtLocation.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtLocation.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtLocation.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtMacExtras.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtMacExtras.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtMacExtras.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtMultimedia.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtMultimedia.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtMultimedia.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtMultimediaWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtMultimediaWidgets.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtMultimediaWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtNetwork.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtNetwork.py new file mode 100755 index 000000000..1c8cc679b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtNetwork.py @@ -0,0 +1,15 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies, pyqt5_library_info + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) +binaries += pyqt5_library_info.collect_qtnetwork_files() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtNetworkAuth.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtNetworkAuth.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtNetworkAuth.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtNfc.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtNfc.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtNfc.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtOpenGL.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtOpenGL.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtOpenGL.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtPositioning.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtPositioning.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtPositioning.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtPrintSupport.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtPrintSupport.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtPrintSupport.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtPurchasing.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtPurchasing.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtPurchasing.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtQml.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtQml.py new file mode 100755 index 000000000..718d323a9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtQml.py @@ -0,0 +1,17 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies, pyqt5_library_info + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) +qml_binaries, qml_datas = pyqt5_library_info.collect_qtqml_files() +binaries += qml_binaries +datas += qml_datas diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtQuick.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtQuick.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtQuick.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtQuick3D.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtQuick3D.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtQuick3D.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtQuickWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtQuickWidgets.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtQuickWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtRemoteObjects.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtRemoteObjects.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtRemoteObjects.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtScript.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtScript.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtScript.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtSensors.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtSensors.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtSensors.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtSerialPort.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtSerialPort.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtSerialPort.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtSql.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtSql.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtSql.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtSvg.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtSvg.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtSvg.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtTest.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtTest.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtTest.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtTextToSpeech.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtTextToSpeech.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtTextToSpeech.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebChannel.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebChannel.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebChannel.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebEngine.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebEngine.py new file mode 100755 index 000000000..7b67e1b7f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebEngine.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebEngineCore.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebEngineCore.py new file mode 100755 index 000000000..f575e0de4 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebEngineCore.py @@ -0,0 +1,22 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import \ + add_qt5_dependencies, pyqt5_library_info + +# Ensure PyQt5 is importable before adding info depending on it. +if pyqt5_library_info.version is not None: + hiddenimports, binaries, datas = add_qt5_dependencies(__file__) + + # Include helper process executable, translations, and resources. + webengine_binaries, webengine_datas = pyqt5_library_info.collect_qtwebengine_files() + binaries += webengine_binaries + datas += webengine_datas diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebEngineWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebEngineWidgets.py new file mode 100755 index 000000000..7b67e1b7f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebEngineWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebKit.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebKit.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebKit.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebKitWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebKitWidgets.py new file mode 100755 index 000000000..7b67e1b7f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebKitWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebSockets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebSockets.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWebSockets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWidgets.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWinExtras.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWinExtras.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtWinExtras.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtX11Extras.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtX11Extras.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtX11Extras.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtXml.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtXml.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtXml.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtXmlPatterns.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtXmlPatterns.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.QtXmlPatterns.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.py new file mode 100755 index 000000000..1b05def29 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.py @@ -0,0 +1,26 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import pyqt5_library_info + +# Only proceed if PyQt5 can be imported. +if pyqt5_library_info.version is not None: + hiddenimports = [ + # PyQt5.10 and earlier uses sip in an separate package; + 'sip', + # PyQt5.11 and later provides SIP in a private package. Support both. + 'PyQt5.sip', + # Imported via __import__ in PyQt5/__init__.py + 'pkgutil', + ] + + # Collect required Qt binaries. + binaries = pyqt5_library_info.collect_extra_binaries() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.uic.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.uic.py new file mode 100755 index 000000000..e4474ddae --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt5.uic.py @@ -0,0 +1,17 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_data_files + +# We need to include modules in PyQt5.uic.widget-plugins, so they can be dynamically loaded by uic. They should be +# included as separate (data-like) files, so they can be found by os.listdir and friends. However, as this directory +# is not a package, refer to it using the package (PyQt5.uic) followed by the subdirectory name (``widget-plugins/``). +datas = collect_data_files('PyQt5.uic', True, 'widget-plugins') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QAxContainer.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QAxContainer.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QAxContainer.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qsci.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qsci.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qsci.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qt3DAnimation.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qt3DAnimation.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qt3DAnimation.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qt3DCore.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qt3DCore.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qt3DCore.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qt3DExtras.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qt3DExtras.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qt3DExtras.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qt3DInput.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qt3DInput.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qt3DInput.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qt3DLogic.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qt3DLogic.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qt3DLogic.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qt3DRender.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qt3DRender.py new file mode 100755 index 000000000..58ac06d80 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.Qt3DRender.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) + +hiddenimports += ["PyQt6.QtOpenGL"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtBluetooth.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtBluetooth.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtBluetooth.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtCharts.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtCharts.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtCharts.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtCore.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtCore.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtCore.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtDBus.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtDBus.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtDBus.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtDataVisualization.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtDataVisualization.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtDataVisualization.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtDesigner.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtDesigner.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtDesigner.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtGui.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtGui.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtGui.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtHelp.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtHelp.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtHelp.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtMultimedia.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtMultimedia.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtMultimedia.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtMultimediaWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtMultimediaWidgets.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtMultimediaWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtNetwork.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtNetwork.py new file mode 100755 index 000000000..c780c7cf1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtNetwork.py @@ -0,0 +1,15 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies, pyqt6_library_info + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) +binaries += pyqt6_library_info.collect_qtnetwork_files() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtNetworkAuth.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtNetworkAuth.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtNetworkAuth.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtNfc.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtNfc.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtNfc.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtOpenGL.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtOpenGL.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtOpenGL.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtOpenGLWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtOpenGLWidgets.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtOpenGLWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtPdf.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtPdf.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtPdf.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtPdfWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtPdfWidgets.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtPdfWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtPositioning.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtPositioning.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtPositioning.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtPrintSupport.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtPrintSupport.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtPrintSupport.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtQml.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtQml.py new file mode 100755 index 000000000..024696af4 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtQml.py @@ -0,0 +1,17 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies, pyqt6_library_info + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) +qml_binaries, qml_datas = pyqt6_library_info.collect_qtqml_files() +binaries += qml_binaries +datas += qml_datas diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtQuick.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtQuick.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtQuick.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtQuick3D.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtQuick3D.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtQuick3D.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtQuickWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtQuickWidgets.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtQuickWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtRemoteObjects.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtRemoteObjects.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtRemoteObjects.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtSensors.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtSensors.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtSensors.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtSerialPort.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtSerialPort.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtSerialPort.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtSpatialAudio.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtSpatialAudio.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtSpatialAudio.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtSql.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtSql.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtSql.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtSvg.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtSvg.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtSvg.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtSvgWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtSvgWidgets.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtSvgWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtTest.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtTest.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtTest.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtTextToSpeech.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtTextToSpeech.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtTextToSpeech.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtWebChannel.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtWebChannel.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtWebChannel.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtWebEngineCore.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtWebEngineCore.py new file mode 100755 index 000000000..a749a7c7c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtWebEngineCore.py @@ -0,0 +1,27 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import \ + add_qt6_dependencies, pyqt6_library_info + +# Ensure PyQt6 is importable before adding info depending on it. +if pyqt6_library_info.version is not None: + # Qt6 prior to 6.2.2 contains a bug that makes it incompatible with the way PyInstaller collects + # QtWebEngine shared libraries and resources. So exit here and now instead of producing a defunct build. + if pyqt6_library_info.version < [6, 2, 2]: + raise SystemExit("Error: PyInstaller's QtWebEngine support requires Qt6 6.2.2 or later!") + + hiddenimports, binaries, datas = add_qt6_dependencies(__file__) + + # Include helper process executable, translations, and resources. + webengine_binaries, webengine_datas = pyqt6_library_info.collect_qtwebengine_files() + binaries += webengine_binaries + datas += webengine_datas diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtWebEngineQuick.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtWebEngineQuick.py new file mode 100755 index 000000000..19083debe --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtWebEngineQuick.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtWebEngineWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtWebEngineWidgets.py new file mode 100755 index 000000000..19083debe --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtWebEngineWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtWebSockets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtWebSockets.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtWebSockets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtWidgets.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtXml.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtXml.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.QtXml.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.py new file mode 100755 index 000000000..b8cf59ab5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.py @@ -0,0 +1,23 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import pyqt6_library_info + +# Only proceed if PyQt6 can be imported. +if pyqt6_library_info.version is not None: + hiddenimports = [ + 'PyQt6.sip', + # Imported via __import__ in PyQt6/__init__.py + 'pkgutil', + ] + + # Collect required Qt binaries. + binaries = pyqt6_library_info.collect_extra_binaries() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.uic.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.uic.py new file mode 100755 index 000000000..7744cbc0f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PyQt6.uic.py @@ -0,0 +1,17 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_data_files + +# We need to include modules in PyQt6.uic.widget-plugins, so they can be dynamically loaded by uic. They should be +# included as separate (data-like) files, so they can be found by os.listdir and friends. However, as this directory +# is not a package, refer to it using the package (PyQt6.uic) followed by the subdirectory name (``widget-plugins/``). +datas = collect_data_files('PyQt6.uic', True, 'widget-plugins') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qt3DAnimation.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qt3DAnimation.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qt3DAnimation.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qt3DCore.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qt3DCore.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qt3DCore.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qt3DExtras.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qt3DExtras.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qt3DExtras.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qt3DInput.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qt3DInput.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qt3DInput.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qt3DLogic.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qt3DLogic.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qt3DLogic.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qt3DRender.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qt3DRender.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qt3DRender.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtAxContainer.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtAxContainer.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtAxContainer.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtCharts.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtCharts.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtCharts.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtConcurrent.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtConcurrent.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtConcurrent.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtCore.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtCore.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtCore.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtDataVisualization.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtDataVisualization.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtDataVisualization.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtGui.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtGui.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtGui.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtHelp.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtHelp.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtHelp.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtLocation.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtLocation.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtLocation.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtMacExtras.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtMacExtras.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtMacExtras.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtMultimedia.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtMultimedia.py new file mode 100755 index 000000000..1f3f90802 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtMultimedia.py @@ -0,0 +1,19 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) + +# Using PySide2 true_properties ("from __feature__ import true_properties") causes a hidden dependency on +# QtMultimediaWidgets python module: +# https://github.com/qtproject/pyside-pyside-setup/blob/5.15.2/sources/shiboken2/shibokenmodule/files.dir/shibokensupport/signature/mapping.py#L577-L586 +hiddenimports += ['PySide2.QtMultimediaWidgets'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtMultimediaWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtMultimediaWidgets.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtMultimediaWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtNetwork.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtNetwork.py new file mode 100755 index 000000000..4e6209107 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtNetwork.py @@ -0,0 +1,15 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies, pyside2_library_info + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) +binaries += pyside2_library_info.collect_qtnetwork_files() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtOpenGL.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtOpenGL.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtOpenGL.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtOpenGLFunctions.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtOpenGLFunctions.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtOpenGLFunctions.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtPositioning.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtPositioning.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtPositioning.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtPrintSupport.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtPrintSupport.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtPrintSupport.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtQml.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtQml.py new file mode 100755 index 000000000..a9f7162f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtQml.py @@ -0,0 +1,19 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies, pyside2_library_info + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) +qml_binaries, qml_datas = pyside2_library_info.collect_qtqml_files() +binaries += qml_binaries +datas += qml_datas + +hiddenimports += ["PySide2.QtGui"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtQuick.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtQuick.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtQuick.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtQuickControls2.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtQuickControls2.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtQuickControls2.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtQuickWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtQuickWidgets.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtQuickWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtRemoteObjects.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtRemoteObjects.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtRemoteObjects.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtScript.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtScript.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtScript.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtScriptTools.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtScriptTools.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtScriptTools.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtScxml.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtScxml.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtScxml.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtSensors.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtSensors.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtSensors.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtSerialPort.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtSerialPort.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtSerialPort.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtSql.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtSql.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtSql.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtSvg.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtSvg.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtSvg.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtTest.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtTest.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtTest.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtTextToSpeech.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtTextToSpeech.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtTextToSpeech.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtUiTools.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtUiTools.py new file mode 100755 index 000000000..9f47776bb --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtUiTools.py @@ -0,0 +1,15 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) +hiddenimports += ['PySide2.QtXml'] # Not inferred from dynamic lib analysis diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebChannel.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebChannel.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebChannel.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebEngine.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebEngine.py new file mode 100755 index 000000000..7b67e1b7f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebEngine.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebEngineCore.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebEngineCore.py new file mode 100755 index 000000000..afb578ead --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebEngineCore.py @@ -0,0 +1,22 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import \ + add_qt5_dependencies, pyside2_library_info + +# Ensure PySide2 is importable before adding info depending on it. +if pyside2_library_info.version is not None: + hiddenimports, binaries, datas = add_qt5_dependencies(__file__) + + # Include helper process executable, translations, and resources. + webengine_binaries, webengine_datas = pyside2_library_info.collect_qtwebengine_files() + binaries += webengine_binaries + datas += webengine_datas diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebEngineWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebEngineWidgets.py new file mode 100755 index 000000000..7b67e1b7f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebEngineWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebKit.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebKit.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebKit.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebKitWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebKitWidgets.py new file mode 100755 index 000000000..7b67e1b7f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebKitWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebSockets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebSockets.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWebSockets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWidgets.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWinExtras.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWinExtras.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtWinExtras.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtX11Extras.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtX11Extras.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtX11Extras.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtXml.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtXml.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtXml.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtXmlPatterns.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtXmlPatterns.py new file mode 100755 index 000000000..51258b943 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.QtXmlPatterns.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt5_dependencies + +hiddenimports, binaries, datas = add_qt5_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qwt5.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qwt5.py new file mode 100755 index 000000000..57f3c2227 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.Qwt5.py @@ -0,0 +1,31 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller import isolated + +hiddenimports = ['PySide2.QtCore', 'PySide2.QtWidgets', 'PySide2.QtGui', 'PySide2.QtSvg'] + + +@isolated.decorate +def conditional_imports(): + from PySide2 import Qwt5 + + out = [] + if hasattr(Qwt5, "toNumpy"): + out.append("numpy") + if hasattr(Qwt5, "toNumeric"): + out.append("numeric") + if hasattr(Qwt5, "toNumarray"): + out.append("numarray") + return out + + +hiddenimports += conditional_imports() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.py new file mode 100755 index 000000000..cb851ed0a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide2.py @@ -0,0 +1,22 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import pyside2_library_info + +# Only proceed if PySide2 can be imported. +if pyside2_library_info.version is not None: + hiddenimports = ['shiboken2', 'inspect'] + if pyside2_library_info.version < [5, 15]: + # The shiboken2 bootstrap in earlier releases requires __future__ in addition to inspect + hiddenimports += ['__future__'] + + # Collect required Qt binaries. + binaries = pyside2_library_info.collect_extra_binaries() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.Qt3DAnimation.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.Qt3DAnimation.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.Qt3DAnimation.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.Qt3DCore.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.Qt3DCore.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.Qt3DCore.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.Qt3DExtras.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.Qt3DExtras.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.Qt3DExtras.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.Qt3DInput.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.Qt3DInput.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.Qt3DInput.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.Qt3DLogic.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.Qt3DLogic.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.Qt3DLogic.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.Qt3DRender.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.Qt3DRender.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.Qt3DRender.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtAxContainer.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtAxContainer.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtAxContainer.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtBluetooth.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtBluetooth.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtBluetooth.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtCharts.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtCharts.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtCharts.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtConcurrent.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtConcurrent.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtConcurrent.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtCore.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtCore.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtCore.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtDBus.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtDBus.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtDBus.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtDataVisualization.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtDataVisualization.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtDataVisualization.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtDesigner.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtDesigner.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtDesigner.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtGui.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtGui.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtGui.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtHelp.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtHelp.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtHelp.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtHttpServer.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtHttpServer.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtHttpServer.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtLocation.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtLocation.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtLocation.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtMultimedia.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtMultimedia.py new file mode 100755 index 000000000..0c2d31b79 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtMultimedia.py @@ -0,0 +1,19 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) + +# Using PySide6 true_properties ("from __feature__ import true_properties") causes a hidden dependency on +# QtMultimediaWidgets python module: +# https://github.com/qtproject/pyside-pyside-setup/blob/v6.2.2.1/sources/shiboken6/shibokenmodule/files.dir/shibokensupport/signature/mapping.py#L614-L627 +hiddenimports += ['PySide6.QtMultimediaWidgets'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtMultimediaWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtMultimediaWidgets.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtMultimediaWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtNetwork.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtNetwork.py new file mode 100755 index 000000000..a216ecd45 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtNetwork.py @@ -0,0 +1,15 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies, pyside6_library_info + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) +binaries += pyside6_library_info.collect_qtnetwork_files() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtNetworkAuth.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtNetworkAuth.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtNetworkAuth.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtNfc.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtNfc.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtNfc.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtOpenGL.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtOpenGL.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtOpenGL.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtOpenGLWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtOpenGLWidgets.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtOpenGLWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtPdf.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtPdf.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtPdf.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtPdfWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtPdfWidgets.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtPdfWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtPositioning.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtPositioning.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtPositioning.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtPrintSupport.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtPrintSupport.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtPrintSupport.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtQml.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtQml.py new file mode 100755 index 000000000..8b6837d5a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtQml.py @@ -0,0 +1,17 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies, pyside6_library_info + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) +qml_binaries, qml_datas = pyside6_library_info.collect_qtqml_files() +binaries += qml_binaries +datas += qml_datas diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtQuick.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtQuick.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtQuick.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtQuick3D.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtQuick3D.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtQuick3D.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtQuickControls2.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtQuickControls2.py new file mode 100755 index 000000000..b405fc64c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtQuickControls2.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) + +hiddenimports += ['PySide6.QtQuick'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtQuickWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtQuickWidgets.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtQuickWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtRemoteObjects.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtRemoteObjects.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtRemoteObjects.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtScxml.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtScxml.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtScxml.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSensors.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSensors.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSensors.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSerialBus.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSerialBus.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSerialBus.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSerialPort.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSerialPort.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSerialPort.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSpatialAudio.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSpatialAudio.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSpatialAudio.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSql.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSql.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSql.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtStateMachine.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtStateMachine.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtStateMachine.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSvg.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSvg.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSvg.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSvgWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSvgWidgets.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtSvgWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtTest.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtTest.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtTest.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtTextToSpeech.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtTextToSpeech.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtTextToSpeech.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtUiTools.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtUiTools.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtUiTools.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtWebChannel.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtWebChannel.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtWebChannel.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtWebEngineCore.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtWebEngineCore.py new file mode 100755 index 000000000..1889c0cf9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtWebEngineCore.py @@ -0,0 +1,29 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import \ + add_qt6_dependencies, pyside6_library_info + +# Ensure PySide6 is importable before adding info depending on it. +if pyside6_library_info.version is not None: + # Qt6 prior to 6.2.2 contains a bug that makes it incompatible with the way PyInstaller collects + # QtWebEngine shared libraries and resources. So exit here and now instead of producing a defunct build. + if pyside6_library_info.version < [6, 2, 2]: + raise SystemExit("Error: PyInstaller's QtWebEngine support requires Qt6 6.2.2 or later!") + + hiddenimports, binaries, datas = add_qt6_dependencies(__file__) + + # Include helper process executable, translations, and resources. + webengine_binaries, webengine_datas = pyside6_library_info.collect_qtwebengine_files() + binaries += webengine_binaries + datas += webengine_datas + + hiddenimports += ['PySide6.QtPrintSupport'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtWebEngineQuick.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtWebEngineQuick.py new file mode 100755 index 000000000..19083debe --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtWebEngineQuick.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtWebEngineWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtWebEngineWidgets.py new file mode 100755 index 000000000..19083debe --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtWebEngineWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtWebSockets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtWebSockets.py new file mode 100755 index 000000000..49d27d6f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtWebSockets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtWidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtWidgets.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtWidgets.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtXml.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtXml.py new file mode 100755 index 000000000..edd5cd1e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.QtXml.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.qt import add_qt6_dependencies + +hiddenimports, binaries, datas = add_qt6_dependencies(__file__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.py new file mode 100755 index 000000000..ad2a7ccf8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-PySide6.py @@ -0,0 +1,25 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import is_module_satisfies +from PyInstaller.utils.hooks.qt import pyside6_library_info + +# Only proceed if PySide6 can be imported. +if pyside6_library_info.version is not None: + hiddenimports = ['shiboken6', 'inspect'] + + # Starting with PySide6 6.4.0, we need to collect PySide6.support.deprecated for | and & operators to work with + # Qt key and key modifiers enums. See #7249. + if is_module_satisfies("PySide6 >= 6.4.0"): + hiddenimports += ['PySide6.support.deprecated'] + + # Collect required Qt binaries. + binaries = pyside6_library_info.collect_extra_binaries() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-_tkinter.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-_tkinter.py new file mode 100755 index 000000000..2b836be1e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-_tkinter.py @@ -0,0 +1,29 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +import sys + +from PyInstaller import compat +from PyInstaller.utils.hooks import logger +from PyInstaller.utils.hooks.tcl_tk import collect_tcl_tk_files + + +def hook(hook_api): + # Use a hook-function to get the module's attr:`__file__` easily. + """ + Freeze all external Tcl/Tk data files if this is a supported platform *or* log a non-fatal error otherwise. + """ + if compat.is_win or compat.is_darwin or compat.is_unix: + # collect_tcl_tk_files() returns a Tree, so we need to store it into `hook_api.datas` in order to prevent + # `building.imphook.format_binaries_and_datas` from crashing with "too many values to unpack". + hook_api.add_datas(collect_tcl_tk_files(hook_api.__file__)) + else: + logger.error("... skipping Tcl/Tk handling on unsupported platform %s", sys.platform) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-babel.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-babel.py new file mode 100755 index 000000000..2e5ce5aa4 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-babel.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_data_files + +hiddenimports = ["babel.dates"] + +datas = collect_data_files('babel') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-difflib.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-difflib.py new file mode 100755 index 000000000..2416758e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-difflib.py @@ -0,0 +1,13 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2015-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# only required when run as `__main__` +excludedimports = ["doctest"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-distutils.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-distutils.py new file mode 100755 index 000000000..2f1a647ba --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-distutils.py @@ -0,0 +1,33 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import is_module_satisfies + +hiddenimports = [] + +# From Python 3.6 and later ``distutils.sysconfig`` takes on the same behaviour as regular ``sysconfig`` of moving the +# config vars to a module (see hook-sysconfig.py). It doesn't use a nice `get module name` function like ``sysconfig`` +# does to help us locate it but the module is the same file that ``sysconfig`` uses so we can use the +# ``_get_sysconfigdata_name()`` from regular ``sysconfig``. +try: + import sysconfig + hiddenimports += [sysconfig._get_sysconfigdata_name()] +except AttributeError: + # Either sysconfig has no attribute _get_sysconfigdata_name (i.e., the function does not exist), or this is Windows + # and the _get_sysconfigdata_name() call failed due to missing sys.abiflags attribute. + pass + +# Starting with setuptools 60.0, the vendored distutils overrides the stdlib one (which will be removed in python 3.12 +# anyway), so check if we are using that version. While the distutils override behavior can be controleld via the +# ``SETUPTOOLS_USE_DISTUTILS`` environment variable, the latter may have a different value during the build and at the +# runtime, and so we need to ensure that both stdlib and setuptools variant of distutils are collected. +if is_module_satisfies("setuptools >= 60.0"): + hiddenimports += ['setuptools._distutils'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-distutils.util.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-distutils.util.py new file mode 100755 index 000000000..021d45995 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-distutils.util.py @@ -0,0 +1,13 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# distutils.util.run_2to3() imports lib2to3. Exclude it as chances are low that it is used by the frozen package. +excludedimports = ['lib2to3.refactor'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.contrib.sessions.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.contrib.sessions.py new file mode 100755 index 000000000..5d86e6c43 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.contrib.sessions.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules('django.contrib.sessions.backends') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.core.cache.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.core.cache.py new file mode 100755 index 000000000..eb319c79c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.core.cache.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules('django.core.cache.backends') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.core.mail.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.core.mail.py new file mode 100755 index 000000000..1cee61c56 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.core.mail.py @@ -0,0 +1,25 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +django.core.mail uses part of the email package. +The problem is: when using runserver with autoreload mode, the thread that checks for changed files triggers further +imports within the email package, because of the LazyImporter in email (used in 2.5 for backward compatibility). +We then need to name those modules as hidden imports, otherwise at runtime the autoreload thread will complain +with a traceback. +""" + +hiddenimports = [ + 'email.mime.message', + 'email.mime.image', + 'email.mime.text', + 'email.mime.multipart', + 'email.mime.audio', +] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.core.management.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.core.management.py new file mode 100755 index 000000000..a8566e084 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.core.management.py @@ -0,0 +1,19 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_submodules + +# Module django.core.management.commands.shell imports IPython, but it introduces many other dependencies that are not +# necessary for a simple django project; ignore the IPython module. +excludedimports = ['IPython', 'matplotlib', 'tkinter'] + +# Django requires management modules for the script 'manage.py'. +hiddenimports = collect_submodules('django.core.management.commands') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.db.backends.mysql.base.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.db.backends.mysql.base.py new file mode 100755 index 000000000..951899eee --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.db.backends.mysql.base.py @@ -0,0 +1,13 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# Compiler module (see class DatabaseOperations) +hiddenimports = ["django.db.backends.mysql.compiler"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.db.backends.oracle.base.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.db.backends.oracle.base.py new file mode 100755 index 000000000..d50eb977e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.db.backends.oracle.base.py @@ -0,0 +1,12 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +hiddenimports = ["django.db.backends.oracle.compiler"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.db.backends.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.db.backends.py new file mode 100755 index 000000000..e829fe7a7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.db.backends.py @@ -0,0 +1,25 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +import glob +import os + +from PyInstaller.utils.hooks import get_module_file_attribute + +# Compiler (see class BaseDatabaseOperations) +hiddenimports = ['django.db.models.sql.compiler'] + +# Include all available Django backends. +modpath = os.path.dirname(get_module_file_attribute('django.db.backends')) +for fn in glob.glob(os.path.join(modpath, '*')): + if os.path.isdir(fn): + fn = os.path.basename(fn) + hiddenimports.append('django.db.backends.' + fn + '.base') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.py new file mode 100755 index 000000000..4a8ee04b9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.py @@ -0,0 +1,92 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# Tested with django 2.2 + +import glob +import os + +from PyInstaller import log as logging +from PyInstaller.utils import hooks +from PyInstaller.utils.hooks import django + +logger = logging.getLogger(__name__) + +# Collect everything. Some submodules of django are not importable without considerable external setup. Ignore the +# errors they raise. +datas, binaries, hiddenimports = hooks.collect_all('django', on_error="ignore") + +root_dir = django.django_find_root_dir() +if root_dir: + logger.info('Django root directory %s', root_dir) + # Include imports from the mysite.settings.py module. + settings_py_imports = django.django_dottedstring_imports(root_dir) + # Include all submodules of all imports detected in mysite.settings.py. + for submod in settings_py_imports: + hiddenimports.append(submod) + hiddenimports += hooks.collect_submodules(submod) + # Include main django modules - settings.py, urls.py, wsgi.py. Without them the django server won't run. + package_name = os.path.basename(root_dir) + default_settings_module = f'{package_name}.settings' + settings_module = os.environ.get('DJANGO_SETTINGS_MODULE', default_settings_module) + hiddenimports += [ + # TODO: consider including 'mysite.settings.py' in source code as a data files, + # since users might need to edit this file. + settings_module, + package_name + '.urls', + package_name + '.wsgi', + ] + # Django hiddenimports from the standard Python library. + hiddenimports += [ + 'http.cookies', + 'html.parser', + ] + + # Bundle django DB schema migration scripts as data files. They are necessary for some commands. + logger.info('Collecting Django migration scripts.') + migration_modules = [ + 'django.conf.app_template.migrations', + 'django.contrib.admin.migrations', + 'django.contrib.auth.migrations', + 'django.contrib.contenttypes.migrations', + 'django.contrib.flatpages.migrations', + 'django.contrib.redirects.migrations', + 'django.contrib.sessions.migrations', + 'django.contrib.sites.migrations', + ] + # Include migration scripts of Django-based apps too. + installed_apps = hooks.get_module_attribute(settings_module, 'INSTALLED_APPS') + migration_modules.extend(set(app + '.migrations' for app in installed_apps)) + # Copy migration files. + for mod in migration_modules: + mod_name, bundle_name = mod.split('.', 1) + mod_dir = os.path.dirname(hooks.get_module_file_attribute(mod_name)) + bundle_dir = bundle_name.replace('.', os.sep) + pattern = os.path.join(mod_dir, bundle_dir, '*.py') + files = glob.glob(pattern) + for f in files: + datas.append((f, os.path.join(mod_name, bundle_dir))) + + # Include data files from your Django project found in your django root package. + datas += hooks.collect_data_files(package_name) + + # Include database file if using sqlite. The sqlite database is usually next to the manage.py script. + root_dir_parent = os.path.dirname(root_dir) + # TODO Add more patterns if necessary. + _patterns = ['*.db', 'db.*'] + for p in _patterns: + files = glob.glob(os.path.join(root_dir_parent, p)) + for f in files: + # Place those files next to the executable. + datas.append((f, '.')) + +else: + logger.warning('No django root directory could be found!') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.template.loaders.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.template.loaders.py new file mode 100755 index 000000000..18b1374cc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-django.template.loaders.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules('django.template.loaders') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-encodings.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-encodings.py new file mode 100755 index 000000000..a4082e198 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-encodings.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules('encodings') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gevent.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gevent.py new file mode 100755 index 000000000..40ad95342 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gevent.py @@ -0,0 +1,24 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2015-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_all, copy_metadata + +excludedimports = ["gevent.testing", "gevent.tests"] + +datas, binaries, hiddenimports = collect_all( + 'gevent', + filter_submodules=lambda name: ("gevent.testing" not in name or "gevent.tests" not in name), + include_py_files=False, + exclude_datas=["**/tests"] +) + +# Gevent uses ``pkg_resources.require("...")``, which means that all its dependencies must also have their metadata. +datas += copy_metadata('gevent', recursive=True) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.py new file mode 100755 index 000000000..f6b226154 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.py @@ -0,0 +1,12 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +hiddenimports = ['gi._error', 'gi._option'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Adw.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Adw.py new file mode 100755 index 000000000..3327e21b3 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Adw.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('Adw', '1') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Atk.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Atk.py new file mode 100755 index 000000000..b57ee3fac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Atk.py @@ -0,0 +1,29 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import get_hook_config +from PyInstaller.utils.hooks.gi import GiModuleInfo, collect_glib_translations + + +def hook(hook_api): + module_info = GiModuleInfo('Atk', '1.0') + if not module_info.available: + return + + binaries, datas, hiddenimports = module_info.collect_typelib_data() + + # Collect translations + lang_list = get_hook_config(hook_api, "gi", "languages") + datas += collect_glib_translations('atk10', lang_list) + + hook_api.add_datas(datas) + hook_api.add_binaries(binaries) + hook_api.add_imports(*hiddenimports) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Champlain.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Champlain.py new file mode 100755 index 000000000..d48def3a0 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Champlain.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('Champlain', '0.12') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Clutter.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Clutter.py new file mode 100755 index 000000000..9ad56a61a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Clutter.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('Clutter', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GIRepository.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GIRepository.py new file mode 100755 index 000000000..5c6961a23 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GIRepository.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GIRepository', '2.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GLib.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GLib.py new file mode 100755 index 000000000..6aa236c56 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GLib.py @@ -0,0 +1,42 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +import glob +import os + +from PyInstaller.compat import is_win +from PyInstaller.utils.hooks import get_hook_config +from PyInstaller.utils.hooks.gi import GiModuleInfo, collect_glib_share_files, collect_glib_translations + + +def hook(hook_api): + module_info = GiModuleInfo('GLib', '2.0') + if not module_info.available: + return + + binaries, datas, hiddenimports = module_info.collect_typelib_data() + + # Collect translations + lang_list = get_hook_config(hook_api, "gi", "languages") + datas += collect_glib_translations('glib20', lang_list) + + # Collect schemas + datas += collect_glib_share_files('glib-2.0', 'schemas') + + # On Windows, glib needs a spawn helper for g_spawn* API + if is_win: + pattern = os.path.join(module_info.get_libdir(), 'gspawn-*-helper*.exe') + for f in glob.glob(pattern): + binaries.append((f, '.')) + + hook_api.add_datas(datas) + hook_api.add_binaries(binaries) + hook_api.add_imports(*hiddenimports) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GModule.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GModule.py new file mode 100755 index 000000000..0ccaaaff6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GModule.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GModule', '2.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GObject.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GObject.py new file mode 100755 index 000000000..1952226fa --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GObject.py @@ -0,0 +1,19 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +from PyInstaller.utils.hooks import is_module_satisfies +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GObject', '2.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() + # gi._gobject removed from PyGObject in version 3.25.1 + if is_module_satisfies('PyGObject < 3.25.1'): + hiddenimports += ['gi._gobject'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Gdk.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Gdk.py new file mode 100755 index 000000000..99fbd08d7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Gdk.py @@ -0,0 +1,36 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo +from PyInstaller.utils.hooks import get_hook_config + + +def hook(hook_api): + # Use the Gdk version from hook config, if available. If not, try using Gtk version from hook config, so that we + # collect Gdk and Gtk of the same version. + module_versions = get_hook_config(hook_api, 'gi', 'module-versions') + if module_versions: + version = module_versions.get('Gdk') + if not version: + version = module_versions.get('Gtk', '3.0') + else: + version = '3.0' + + module_info = GiModuleInfo('Gdk', version) + if not module_info.available: + return + + binaries, datas, hiddenimports = module_info.collect_typelib_data() + hiddenimports += ['gi._gi_cairo', 'gi.repository.cairo'] + + hook_api.add_datas(datas) + hook_api.add_binaries(binaries) + hook_api.add_imports(*hiddenimports) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GdkPixbuf.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GdkPixbuf.py new file mode 100755 index 000000000..fb0c3402d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GdkPixbuf.py @@ -0,0 +1,146 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +import glob +import os +import shutil + +from PyInstaller import compat +from PyInstaller.config import CONF # workpath +from PyInstaller.utils.hooks import get_hook_config, logger +from PyInstaller.utils.hooks.gi import GiModuleInfo, collect_glib_translations + +LOADERS_PATH = os.path.join('gdk-pixbuf-2.0', '2.10.0', 'loaders') +LOADER_MODULE_DEST_PATH = "lib/gdk-pixbuf/loaders" +LOADER_CACHE_DEST_PATH = "lib/gdk-pixbuf" # NOTE: some search & replace code depends on / being used on all platforms. + + +def _find_gdk_pixbuf_query_loaders_executable(libdir): + # Distributions either package gdk-pixbuf-query-loaders in the GI libs directory (not on the path), or on the path + # with or without a -x64 suffix, depending on the architecture. + cmds = [ + os.path.join(libdir, 'gdk-pixbuf-2.0', 'gdk-pixbuf-query-loaders'), + 'gdk-pixbuf-query-loaders-64', + 'gdk-pixbuf-query-loaders', + ] + + for cmd in cmds: + cmd_fullpath = shutil.which(cmd) + if cmd_fullpath is not None: + return cmd_fullpath + + return None + + +def _collect_loaders(libdir): + # Assume loader plugins have .so library suffix on all non-Windows platforms + lib_ext = "*.dll" if compat.is_win else "*.so" + + # Find all loaders + loader_libs = [] + pattern = os.path.join(libdir, LOADERS_PATH, lib_ext) + for f in glob.glob(pattern): + loader_libs.append(f) + + # Sometimes the loaders are stored in a different directory from the library (msys2) + if not loader_libs: + pattern = os.path.abspath(os.path.join(libdir, '..', 'lib', LOADERS_PATH, lib_ext)) + for f in glob.glob(pattern): + loader_libs.append(f) + + return loader_libs + + +def _generate_loader_cache(gdk_pixbuf_query_loaders, libdir, loader_libs): + # Run the "gdk-pixbuf-query-loaders" command and capture its standard output providing an updated loader + # cache; then write this output to the loader cache bundled with this frozen application. On all platforms, + # we also move the package structure to point to lib/gdk-pixbuf instead of lib/gdk-pixbuf-2.0/2.10.0 in + # order to make compatible for OSX application signing. + # + # On Mac OS we use @executable_path to specify a path relative to the generated bundle. However, on + # non-Windows, we need to rewrite the loader cache because it is not relocatable by default. See + # https://bugzilla.gnome.org/show_bug.cgi?id=737523 + # + # To make it easier to rewrite, we just always write @executable_path, since its significantly easier to + # find/replace at runtime. :) + # + # To permit string munging, decode the encoded bytes output by this command (i.e., enable the + # "universal_newlines" option). + # + # On Fedora, the default loaders cache is /usr/lib64, but the libdir is actually /lib64. To get around this, + # we pass the path to the loader command, and it will create a cache with the right path. + # + # On Windows, the loaders lib directory is relative, starts with 'lib', and uses \\ as path separators + # (escaped \). + cachedata = compat.exec_command_stdout(gdk_pixbuf_query_loaders, *loader_libs) + + output_lines = [] + prefix = '"' + os.path.join(libdir, 'gdk-pixbuf-2.0', '2.10.0') + plen = len(prefix) + + win_prefix = '"' + '\\\\'.join(['lib', 'gdk-pixbuf-2.0', '2.10.0']) + win_plen = len(win_prefix) + + msys2_prefix = '"' + os.path.abspath(os.path.join(libdir, '..', 'lib', 'gdk-pixbuf-2.0', '2.10.0')) + msys2_plen = len(msys2_prefix) + + # For each line in the updated loader cache... + for line in cachedata.splitlines(): + if line.startswith('#'): + continue + if line.startswith(prefix): + line = '"@executable_path/' + LOADER_CACHE_DEST_PATH + line[plen:] + elif line.startswith(win_prefix): + line = '"' + LOADER_CACHE_DEST_PATH.replace('/', '\\\\') + line[win_plen:] + elif line.startswith(msys2_prefix): + line = ('"' + LOADER_CACHE_DEST_PATH + line[msys2_plen:]).replace('/', '\\\\') + output_lines.append(line) + + return '\n'.join(output_lines) + + +def hook(hook_api): + module_info = GiModuleInfo('GdkPixbuf', '2.0') + if not module_info.available: + return + + binaries, datas, hiddenimports = module_info.collect_typelib_data() + + libdir = module_info.get_libdir() + + # Collect GdkPixbuf loaders and generate loader cache file + gdk_pixbuf_query_loaders = _find_gdk_pixbuf_query_loaders_executable(libdir) + logger.debug("gdk-pixbuf-query-loaders executable: %s", gdk_pixbuf_query_loaders) + if not gdk_pixbuf_query_loaders: + logger.warning("gdk-pixbuf-query-loaders executable not found in GI library directory or in PATH!") + else: + # Find all GdkPixbuf loader modules + loader_libs = _collect_loaders(libdir) + + # Collect discovered loaders + for lib in loader_libs: + binaries.append((lib, LOADER_MODULE_DEST_PATH)) + + # Generate loader cache; we need to store it to CONF['workpath'] so we can collect it as a data file. + cachedata = _generate_loader_cache(gdk_pixbuf_query_loaders, libdir, loader_libs) + cachefile = os.path.join(CONF['workpath'], 'loaders.cache') + with open(cachefile, 'w') as fp: + fp.write(cachedata) + datas.append((cachefile, LOADER_CACHE_DEST_PATH)) + + # Collect translations + lang_list = get_hook_config(hook_api, "gi", "languages") + if gdk_pixbuf_query_loaders: + datas += collect_glib_translations('gdk-pixbuf', lang_list) + + hook_api.add_datas(datas) + hook_api.add_binaries(binaries) + hook_api.add_imports(*hiddenimports) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Gio.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Gio.py new file mode 100755 index 000000000..46a4351af --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Gio.py @@ -0,0 +1,63 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +import glob +import os + +from PyInstaller import compat +import PyInstaller.log as logging +from PyInstaller.utils.hooks.gi import GiModuleInfo + +logger = logging.getLogger(__name__) + +module_info = GiModuleInfo('Gio', '2.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() + + # Find Gio modules + libdir = module_info.get_libdir() + modules_pattern = None + + if compat.is_win: + modules_pattern = os.path.join(libdir, 'gio', 'modules', '*.dll') + else: + gio_libdir = os.path.join(libdir, 'gio', 'modules') + if not os.path.exists(gio_libdir): + # homebrew installs the files elsewhere... + gio_libdir = os.path.join(os.path.commonprefix([compat.base_prefix, gio_libdir]), 'lib', 'gio', 'modules') + + if os.path.exists(gio_libdir): + modules_pattern = os.path.join(gio_libdir, '*.so') + else: + logger.warning('Could not determine Gio modules path!') + + if modules_pattern: + for f in glob.glob(modules_pattern): + binaries.append((f, 'gio_modules')) + else: + # To add a new platform add a new elif above with the proper is_ and proper pattern for finding the + # Gio modules on your platform. + logger.warning('Bundling Gio modules is not supported on your platform.') + + # Bundle the mime cache -- might not be needed on Windows + # -> this is used for content type detection (also used by GdkPixbuf) + # -> gio/xdgmime/xdgmime.c looks for mime/mime.cache in the users home directory, followed by XDG_DATA_DIRS if + # specified in the environment, otherwise it searches /usr/local/share/ and /usr/share/ + if not compat.is_win: + _mime_searchdirs = ['/usr/local/share', '/usr/share'] + if 'XDG_DATA_DIRS' in os.environ: + _mime_searchdirs.insert(0, os.environ['XDG_DATA_DIRS']) + + for sd in _mime_searchdirs: + spath = os.path.join(sd, 'mime', 'mime.cache') + if os.path.exists(spath): + datas.append((spath, 'share/mime')) + break diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Graphene.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Graphene.py new file mode 100755 index 000000000..bfa4d30fe --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Graphene.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('Graphene', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Gsk.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Gsk.py new file mode 100755 index 000000000..922925287 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Gsk.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('Gsk', '4.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Gst.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Gst.py new file mode 100755 index 000000000..939a37b5e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Gst.py @@ -0,0 +1,93 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# GStreamer contains a lot of plugins. We need to collect them and bundle them with the exe file. We also need to +# resolve binary dependencies of these GStreamer plugins. + +import pathlib + +from PyInstaller.utils.hooks import get_hook_config, include_or_exclude_file +import PyInstaller.log as logging +from PyInstaller import isolated +from PyInstaller.utils.hooks.gi import GiModuleInfo, collect_glib_share_files, collect_glib_translations + +logger = logging.getLogger(__name__) + + +@isolated.decorate +def _get_gst_plugin_path(): + import os + import gi + gi.require_version('Gst', '1.0') + from gi.repository import Gst + Gst.init(None) + reg = Gst.Registry.get() + plug = reg.find_plugin('coreelements') + path = plug.get_filename() + return os.path.dirname(path) + + +def _format_plugin_pattern(plugin_name): + return f"**/*gst{plugin_name}.*" + + +def hook(hook_api): + module_info = GiModuleInfo('Gst', '1.0') + if not module_info.available: + return + + binaries, datas, hiddenimports = module_info.collect_typelib_data() + hiddenimports += ["gi.repository.Gio"] + + # Collect data files + datas += collect_glib_share_files('gstreamer-1.0') + + # Translations + lang_list = get_hook_config(hook_api, "gi", "languages") + for prog in [ + 'gst-plugins-bad-1.0', + 'gst-plugins-base-1.0', + 'gst-plugins-good-1.0', + 'gst-plugins-ugly-1.0', + 'gstreamer-1.0', + ]: + datas += collect_glib_translations(prog, lang_list) + + # Plugins + try: + plugin_path = _get_gst_plugin_path() + except Exception as e: + logger.warning("Failed to determine gstreamer plugin path: %s", e) + plugin_path = None + + if plugin_path: + plugin_path = pathlib.Path(plugin_path) + + # Obtain optional include/exclude list from hook config + include_list = get_hook_config(hook_api, "gstreamer", "include_plugins") + exclude_list = get_hook_config(hook_api, "gstreamer", "exclude_plugins") + + # Format plugin basenames into filename patterns for matching + if include_list is not None: + include_list = [_format_plugin_pattern(name) for name in include_list] + if exclude_list is not None: + exclude_list = [_format_plugin_pattern(name) for name in exclude_list] + + # The names of GStreamer plugins typically start with libgst (or just gst, depending on the toolchain). We also + # need to account for different extensions that might be used on a particular OS (for example, on macOS, the + # extension may be either .so or .dylib). + for lib_pattern in ['*gst*.dll', '*gst*.dylib', '*gst*.so']: + binaries += [(str(filename), 'gst_plugins') for filename in plugin_path.glob(lib_pattern) + if include_or_exclude_file(filename, include_list, exclude_list)] + + hook_api.add_datas(datas) + hook_api.add_binaries(binaries) + hook_api.add_imports(*hiddenimports) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstAllocators.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstAllocators.py new file mode 100755 index 000000000..119401a1c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstAllocators.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstAllocators', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstApp.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstApp.py new file mode 100755 index 000000000..7c25a4455 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstApp.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstApp', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstAudio.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstAudio.py new file mode 100755 index 000000000..cf18078ee --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstAudio.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstAudio', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstBadAudio.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstBadAudio.py new file mode 100755 index 000000000..0f345b957 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstBadAudio.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstBadAudio', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstBase.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstBase.py new file mode 100755 index 000000000..ea6187b04 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstBase.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstBase', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstCheck.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstCheck.py new file mode 100755 index 000000000..e631995bc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstCheck.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstCheck', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstCodecs.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstCodecs.py new file mode 100755 index 000000000..ffa643e76 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstCodecs.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstCodecs', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstController.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstController.py new file mode 100755 index 000000000..c928843bd --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstController.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstController', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstGL.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstGL.py new file mode 100755 index 000000000..0075eb049 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstGL.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstGL', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstGLEGL.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstGLEGL.py new file mode 100755 index 000000000..a3f557df9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstGLEGL.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstGLEGL', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstGLWayland.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstGLWayland.py new file mode 100755 index 000000000..6ef146d84 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstGLWayland.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstGLWayland', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstGLX11.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstGLX11.py new file mode 100755 index 000000000..dd68570f1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstGLX11.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstGLX11', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstInsertBin.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstInsertBin.py new file mode 100755 index 000000000..c7980bccb --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstInsertBin.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstInsertBin', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstMpegts.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstMpegts.py new file mode 100755 index 000000000..b6901925f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstMpegts.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstMpegts', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstNet.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstNet.py new file mode 100755 index 000000000..0c268af1b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstNet.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstNet', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstPbutils.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstPbutils.py new file mode 100755 index 000000000..173b695f0 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstPbutils.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstPbutils', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstPlay.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstPlay.py new file mode 100755 index 000000000..edb602082 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstPlay.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstPlay', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstPlayer.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstPlayer.py new file mode 100755 index 000000000..80cb93ff8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstPlayer.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstPlayer', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstRtp.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstRtp.py new file mode 100755 index 000000000..d18e58d6d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstRtp.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstRtp', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstRtsp.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstRtsp.py new file mode 100755 index 000000000..09382dd20 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstRtsp.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstRtsp', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstRtspServer.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstRtspServer.py new file mode 100755 index 000000000..d023c3fa1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstRtspServer.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstRtspServer', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstSdp.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstSdp.py new file mode 100755 index 000000000..2a78e2bd9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstSdp.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstSdp', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstTag.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstTag.py new file mode 100755 index 000000000..dbac75668 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstTag.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstTag', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstTranscoder.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstTranscoder.py new file mode 100755 index 000000000..3cc1dcf8a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstTranscoder.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstTranscoder', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstVideo.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstVideo.py new file mode 100755 index 000000000..398b50329 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstVideo.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstVideo', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstVulkan.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstVulkan.py new file mode 100755 index 000000000..588c0734c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstVulkan.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstVulkan', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstVulkanWayland.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstVulkanWayland.py new file mode 100755 index 000000000..aaef939f1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstVulkanWayland.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstVulkanWayland', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstVulkanXCB.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstVulkanXCB.py new file mode 100755 index 000000000..2351a1301 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstVulkanXCB.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstVulkanXCB', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstWebRTC.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstWebRTC.py new file mode 100755 index 000000000..9fcac0608 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GstWebRTC.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GstWebRTC', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Gtk.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Gtk.py new file mode 100755 index 000000000..2495b1d22 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Gtk.py @@ -0,0 +1,59 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +import os +import os.path + +from PyInstaller.compat import is_win +from PyInstaller.utils.hooks import get_hook_config +from PyInstaller.utils.hooks.gi import GiModuleInfo, collect_glib_etc_files, collect_glib_share_files, \ + collect_glib_translations + + +def hook(hook_api): + module_info = GiModuleInfo('Gtk', '3.0', hook_api=hook_api) # Pass hook_api to read version from hook config + if not module_info.available: + return + + binaries, datas, hiddenimports = module_info.collect_typelib_data() + + # Collect fontconfig data + datas += collect_glib_share_files('fontconfig') + + # Icons, themes, translations + icon_list = get_hook_config(hook_api, "gi", "icons") + if icon_list is not None: + for icon in icon_list: + datas += collect_glib_share_files(os.path.join('icons', icon)) + else: + datas += collect_glib_share_files('icons') + + # Themes + theme_list = get_hook_config(hook_api, "gi", "themes") + if theme_list is not None: + for theme in theme_list: + datas += collect_glib_share_files(os.path.join('themes', theme)) + else: + datas += collect_glib_share_files('themes') + + # Translations + lang_list = get_hook_config(hook_api, "gi", "languages") + datas += collect_glib_translations(f'gtk{module_info.version[0]}0', lang_list) + + # These only seem to be required on Windows + if is_win: + datas += collect_glib_etc_files('fonts') + datas += collect_glib_etc_files('pango') + datas += collect_glib_share_files('fonts') + + hook_api.add_datas(datas) + hook_api.add_binaries(binaries) + hook_api.add_imports(*hiddenimports) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GtkChamplain.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GtkChamplain.py new file mode 100755 index 000000000..777b620bb --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GtkChamplain.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GtkChamplain', '0.12') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GtkClutter.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GtkClutter.py new file mode 100755 index 000000000..cc4fcd7ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GtkClutter.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('GtkClutter', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GtkSource.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GtkSource.py new file mode 100755 index 000000000..5e7efa79b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GtkSource.py @@ -0,0 +1,31 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo, collect_glib_share_files + + +def hook(hook_api): + module_info = GiModuleInfo('GtkSource', '3.0', hook_api=hook_api) # Pass hook_api to read version from hook config + if not module_info.available: + return + + binaries, datas, hiddenimports = module_info.collect_typelib_data() + + # Collect data files + # The data directory name contains verbatim version, e.g.: + # * GtkSourceView-3.0 -> /usr/share/gtksourceview-3.0 + # * GtkSourceView-4 -> /usr/share/gtksourceview-4 + # * GtkSourceView-5 -> /usr/share/gtksourceview-5 + datas += collect_glib_share_files(f'gtksourceview-{module_info.version}') + + hook_api.add_datas(datas) + hook_api.add_binaries(binaries) + hook_api.add_imports(*hiddenimports) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GtkosxApplication.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GtkosxApplication.py new file mode 100755 index 000000000..3437edf2a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.GtkosxApplication.py @@ -0,0 +1,18 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.compat import is_darwin +from PyInstaller.utils.hooks.gi import GiModuleInfo + +if is_darwin: + module_info = GiModuleInfo('GtkosxApplication', '1.0') + if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.HarfBuzz.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.HarfBuzz.py new file mode 100755 index 000000000..41cef143c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.HarfBuzz.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('HarfBuzz', '0.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Pango.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Pango.py new file mode 100755 index 000000000..3d8b86522 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.Pango.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('Pango', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.PangoCairo.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.PangoCairo.py new file mode 100755 index 000000000..7c058fd14 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.PangoCairo.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('PangoCairo', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.cairo.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.cairo.py new file mode 100755 index 000000000..71fed303c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.cairo.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('cairo', '1.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.freetype2.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.freetype2.py new file mode 100755 index 000000000..ffea7a1a5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.freetype2.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('freetype2', '2.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.xlib.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.xlib.py new file mode 100755 index 000000000..1c2bde327 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-gi.repository.xlib.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks.gi import GiModuleInfo + +module_info = GiModuleInfo('xlib', '2.0') +if module_info.available: + binaries, datas, hiddenimports = module_info.collect_typelib_data() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-heapq.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-heapq.py new file mode 100755 index 000000000..373025ff8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-heapq.py @@ -0,0 +1,13 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2015-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# Only required when run as `__main__`. +excludedimports = ["doctest"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-idlelib.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-idlelib.py new file mode 100755 index 000000000..505378d5e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-idlelib.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('idlelib') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-importlib_metadata.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-importlib_metadata.py new file mode 100755 index 000000000..7abf511ca --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-importlib_metadata.py @@ -0,0 +1,24 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2019-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +importlib_metadata is a library to access the metadata for a Python package. This functionality intends to replace most +uses of pkg_resources entry point API and metadata API. +""" + +from PyInstaller.utils.hooks import copy_metadata + +# Normally, we should never need to use copy_metadata() in a hook since metadata requirements detection is now +# automatic. However, that detection first uses `PyiModuleGraph.get_code_using("importlib_metadata")` to find +# files which `import importlib_metadata` and `get_code_using()` intentionally excludes internal imports. This +# means that importlib_metadata is not scanned for usages of importlib_metadata and therefore when +# importlib_metadata uses its own API to get its version, this goes undetected. Therefore, we must collect its +# metadata manually. +datas = copy_metadata('importlib_metadata') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-importlib_resources.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-importlib_resources.py new file mode 100755 index 000000000..29727985e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-importlib_resources.py @@ -0,0 +1,22 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2019-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +`importlib_resources` is a backport of the 3.9+ module `importlib.resources` +""" + +from PyInstaller.utils.hooks import is_module_satisfies, collect_data_files + +# Prior to v1.2.0, a `version.txt` file is used to set __version__. Later versions use `importlib.metadata`. +if is_module_satisfies("importlib_resources < 1.2.0"): + datas = collect_data_files("importlib_resources", includes=["version.txt"]) + +if is_module_satisfies("importlib_resources >= 1.3.1"): + hiddenimports = ['importlib_resources.trees'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-keyring.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-keyring.py new file mode 100755 index 000000000..acbd5ff44 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-keyring.py @@ -0,0 +1,19 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_submodules, copy_metadata + +# Collect backends +hiddenimports = collect_submodules('keyring.backends') + +# Keyring performs backend plugin discovery using setuptools entry points, which are listed in the metadata. Therefore, +# we need to copy the metadata, otherwise no backends will be found at run-time. +datas = copy_metadata('keyring') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-kivy.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-kivy.py new file mode 100755 index 000000000..f264a6702 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-kivy.py @@ -0,0 +1,25 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2015-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller import log as logging +from PyInstaller.utils.hooks import is_module_satisfies + +if is_module_satisfies('kivy >= 1.9.1'): + from kivy.tools.packaging.pyinstaller_hooks import (add_dep_paths, get_deps_all, get_factory_modules, kivy_modules) + from kivy.tools.packaging.pyinstaller_hooks import excludedimports, datas # noqa: F401 + + add_dep_paths() + + hiddenimports = get_deps_all()['hiddenimports'] + hiddenimports = list(set(get_factory_modules() + kivy_modules + hiddenimports)) +else: + logger = logging.getLogger(__name__) + logger.warning('Hook disabled because of Kivy version < 1.9.1') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-lib2to3.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-lib2to3.py new file mode 100755 index 000000000..83b0f085d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-lib2to3.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# This is needed to bundle lib2to3 Grammars files + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('lib2to3') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-matplotlib.backends.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-matplotlib.backends.py new file mode 100755 index 000000000..6b9550ddf --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-matplotlib.backends.py @@ -0,0 +1,218 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.compat import is_darwin +from PyInstaller.utils.hooks import logger, get_hook_config +from PyInstaller import isolated + + +@isolated.decorate +def _get_configured_default_backend(): + """ + Return the configured default matplotlib backend name, if available as matplotlib.rcParams['backend'] (or overridden + by MPLBACKEND environment variable. If the value of matplotlib.rcParams['backend'] corresponds to the auto-sentinel + object, returns None + """ + import matplotlib + # matplotlib.rcParams overrides the __getitem__ implementation and attempts to determine and load the default + # backend using pyplot.switch_backend(). Therefore, use dict.__getitem__(). + val = dict.__getitem__(matplotlib.rcParams, 'backend') + if isinstance(val, str): + return val + return None + + +@isolated.decorate +def _list_available_mpl_backends(): + """ + Returns the names of all available matplotlib backends. + """ + import matplotlib + return matplotlib.rcsetup.all_backends + + +@isolated.decorate +def _check_mpl_backend_importable(module_name): + """ + Attempts to import the given module name (matplotlib backend module). + + Exceptions are propagated to caller. + """ + __import__(module_name) + + +# Bytecode scanning +def _recursive_scan_code_objects_for_mpl_use(co): + """ + Recursively scan the bytecode for occurrences of matplotlib.use() or mpl.use() calls with const arguments, and + collect those arguments into list of used matplotlib backend names. + """ + + from PyInstaller.depend.bytecode import any_alias, recursive_function_calls + + mpl_use_names = { + *any_alias("matplotlib.use"), + *any_alias("mpl.use"), # matplotlib is commonly aliased as mpl + } + + backends = [] + for calls in recursive_function_calls(co).values(): + for name, args in calls: + # matplotlib.use(backend) or matplotlib.use(backend, force) + # We support only literal arguments. Similarly, kwargs are + # not supported. + if len(args) not in {1, 2} or not isinstance(args[0], str): + continue + if name in mpl_use_names: + backends.append(args[0]) + + return backends + + +def _backend_module_name(name): + """ + Converts matplotlib backend name to its corresponding module name. + + Equivalent to matplotlib.cbook._backend_module_name(). + """ + if name.startswith("module://"): + return name[9:] + return f"matplotlib.backends.backend_{name.lower()}" + + +def _autodetect_used_backends(hook_api): + """ + Returns a list of automatically-discovered matplotlib backends in use, or the name of the default matplotlib + backend. Implements the 'auto' backend selection method. + """ + # Scan the code for matplotlib.use() + modulegraph = hook_api.analysis.graph + mpl_code_objs = modulegraph.get_code_using("matplotlib") + used_backends = [] + for name, co in mpl_code_objs.items(): + co_backends = _recursive_scan_code_objects_for_mpl_use(co) + if co_backends: + logger.info( + "Discovered Matplotlib backend(s) via `matplotlib.use()` call in module %r: %r", name, co_backends + ) + used_backends += co_backends + + if used_backends: + HOOK_CONFIG_DOCS = 'https://pyinstaller.org/en/stable/hooks-config.html#matplotlib-hooks' + logger.info( + "The following Matplotlib backends were discovered by scanning for `matplotlib.use()` calls: %r. If your " + "backend of choice is not in this list, either add a `matplotlib.use()` call to your code, or configure " + "the backend collection via hook options (see: %s).", used_backends, HOOK_CONFIG_DOCS + ) + return used_backends + + # Determine the default matplotlib backend. + # + # Ideally, this would be done by calling ``matplotlib.get_backend()``. However, that function tries to switch to the + # default backend (calling ``matplotlib.pyplot.switch_backend()``), which seems to occasionally fail on our linux CI + # with an error and, on other occasions, returns the headless Agg backend instead of the GUI one (even with display + # server running). Furthermore, using ``matplotlib.get_backend()`` returns headless 'Agg' when display server is + # unavailable, which is not ideal for automated builds. + # + # Therefore, we try to emulate ``matplotlib.get_backend()`` ourselves. First, we try to obtain the configured + # default backend from settings (rcparams and/or MPLBACKEND environment variable). If that is unavailable, we try to + # find the first importable GUI-based backend, using the same list as matplotlib.pyplot.switch_backend() uses for + # automatic backend selection. The difference is that we only test whether the backend module is importable, without + # trying to switch to it. + default_backend = _get_configured_default_backend() # isolated sub-process + if default_backend: + logger.info("Found configured default matplotlib backend: %s", default_backend) + return [default_backend] + + candidates = ["Qt5Agg", "Gtk3Agg", "TkAgg", "WxAgg"] + if is_darwin: + candidates = ["MacOSX"] + candidates + logger.info("Trying determine the default backend as first importable candidate from the list: %r", candidates) + + for candidate in candidates: + try: + module_name = _backend_module_name(candidate) + _check_mpl_backend_importable(module_name) # NOTE: uses an isolated sub-process. + except Exception: + continue + return [candidate] + + # Fall back to headless Agg backend + logger.info("None of the backend candidates could be imported; falling back to headless Agg!") + return ['Agg'] + + +def _collect_all_importable_backends(hook_api): + """ + Returns a list of all importable matplotlib backends. Implements the 'all' backend selection method. + """ + # List of the human-readable names of all available backends. + backend_names = _list_available_mpl_backends() # NOTE: retrieved in an isolated sub-process. + logger.info("All available matplotlib backends: %r", backend_names) + + # Try to import the module(s). + importable_backends = [] + + # List of backends to exclude; Qt4 is not supported by PyInstaller anymore. + exclude_backends = {'Qt4Agg', 'Qt4Cairo'} + + # Ignore "CocoaAgg" on OSes other than Mac OS; attempting to import it on other OSes halts the current + # (sub)process without printing output or raising exceptions, preventing reliable detection. Apply the + # same logic for the (newer) "MacOSX" backend. + if not is_darwin: + exclude_backends |= {'CocoaAgg', 'MacOSX'} + + # For safety, attempt to import each backend in an isolated sub-process. + for backend_name in backend_names: + if backend_name in exclude_backends: + logger.info(' Matplotlib backend %r: excluded', backend_name) + continue + + try: + module_name = _backend_module_name(backend_name) + _check_mpl_backend_importable(module_name) # NOTE: uses an isolated sub-process. + except Exception: + # Backend is not importable, for whatever reason. + logger.info(' Matplotlib backend %r: ignored due to import error', backend_name) + continue + + logger.info(' Matplotlib backend %r: added', backend_name) + importable_backends.append(backend_name) + + return importable_backends + + +def hook(hook_api): + # Backend collection setting + backends_method = get_hook_config(hook_api, 'matplotlib', 'backends') + if backends_method is None: + backends_method = 'auto' # default method + + # Select backend(s) + if backends_method == 'auto': + logger.info("Matplotlib backend selection method: automatic discovery of used backends") + backend_names = _autodetect_used_backends(hook_api) + elif backends_method == 'all': + logger.info("Matplotlib backend selection method: collection of all importable backends") + backend_names = _collect_all_importable_backends(hook_api) + else: + logger.info("Matplotlib backend selection method: user-provided name(s)") + if isinstance(backends_method, str): + backend_names = [backends_method] + else: + assert isinstance(backends_method, list), "User-provided backend name(s) must be either a string or a list!" + backend_names = backends_method + + logger.info("Selected matplotlib backends: %r", backend_names) + + # Set module names as hiddenimports + module_names = [_backend_module_name(backend) for backend in backend_names] # backend name -> module name + hook_api.add_imports(*module_names) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-matplotlib.numerix.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-matplotlib.numerix.py new file mode 100755 index 000000000..924b40039 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-matplotlib.numerix.py @@ -0,0 +1,21 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +The matplotlib.numerix package sneaks these imports in under the radar. +""" + +hiddenimports = [ + 'fft', + 'linear_algebra', + 'random_array', + 'ma', + 'mlab', +] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-matplotlib.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-matplotlib.py new file mode 100755 index 000000000..dddac4b24 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-matplotlib.py @@ -0,0 +1,38 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller import isolated +from PyInstaller import compat +from PyInstaller.utils import hooks as hookutils + + +@isolated.decorate +def mpl_data_dir(): + import matplotlib + return matplotlib.get_data_path() + + +datas = [ + (mpl_data_dir(), "matplotlib/mpl-data"), +] + +binaries = [] + +# Windows PyPI wheels for `matplotlib` >= 3.7.0 use `delvewheel`. +# In addition to DLLs from `matplotlib.libs` directory, which should be picked up automatically by dependency analysis +# in contemporary PyInstaller versions, we also need to collect the load-order file. This used to be required for +# python <= 3.7 (that lacked `os.add_dll_directory`), but is also needed for Anaconda python 3.8 and 3.9, where +# `delvewheel` falls back to load-order file codepath due to Anaconda breaking `os.add_dll_directory` implementation. +if compat.is_win and hookutils.is_module_satisfies('matplotlib >= 3.7.0'): + delvewheel_datas, delvewheel_binaries = hookutils.collect_delvewheel_libs_directory('matplotlib') + + datas += delvewheel_datas + binaries += delvewheel_binaries diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-multiprocessing.util.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-multiprocessing.util.py new file mode 100755 index 000000000..b9363bab1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-multiprocessing.util.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# In Python 3.8 mutliprocess.utils has _cleanup_tests() to cleanup multiprocessing resources when multiprocessing tests +# completed. This function import `tests` which is the complete Python test-suite, pulling in many more dependencies, +# e.g., tkinter. + +excludedimports = ['test'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-numpy.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-numpy.py new file mode 100755 index 000000000..3a0245ce1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-numpy.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python3 + +# --- Copyright Disclaimer --- +# +# In order to support PyInstaller with numpy<1.20.0 this file will be duplicated for a short period inside +# PyInstaller's repository [1]. However this file is the intellectual property of the NumPy team and is +# under the terms and conditions outlined their repository [2]. +# +# .. refs: +# +# [1] PyInstaller: https://github.com/pyinstaller/pyinstaller/ +# [2] NumPy's license: https://github.com/numpy/numpy/blob/master/LICENSE.txt +# +""" +This hook should collect all binary files and any hidden modules that numpy needs. + +Our (some-what inadequate) docs for writing PyInstaller hooks are kept here: +https://pyinstaller.readthedocs.io/en/stable/hooks.html + +PyInstaller has a lot of NumPy users so we consider maintaining this hook a high priority. +Feel free to @mention either bwoodsend or Legorooj on Github for help keeping it working. +""" + +from PyInstaller.compat import is_conda, is_pure_conda +from PyInstaller.utils.hooks import collect_dynamic_libs, is_module_satisfies + +# Collect all DLLs inside numpy's installation folder, dump them into built app's root. +binaries = collect_dynamic_libs("numpy", ".") + +# If using Conda without any non-conda virtual environment manager: +if is_pure_conda: + # Assume running the NumPy from Conda-forge and collect it's DLLs from the communal Conda bin directory. DLLs from + # NumPy's dependencies must also be collected to capture MKL, OpenBlas, OpenMP, etc. + from PyInstaller.utils.hooks import conda_support + datas = conda_support.collect_dynamic_libs("numpy", dependencies=True) + +# Submodules PyInstaller cannot detect (probably because they are only imported by extension modules, which PyInstaller +# cannot read). +hiddenimports = ['numpy.core._dtype_ctypes'] +if is_conda: + hiddenimports.append("six") + +# Remove testing and building code and packages that are referenced throughout NumPy but are not really dependencies. +excludedimports = [ + "scipy", + "pytest", + "nose", + "f2py", + "setuptools", + "numpy.f2py", +] + +# As of version 1.22, numpy.testing (imported for example by some scipy modules) requires numpy.distutils and distutils. +# So exclude them only for earlier versions. +if is_module_satisfies("numpy < 1.22"): + excludedimports += [ + "distutils", + "numpy.distutils", + ] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-packaging.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-packaging.py new file mode 100755 index 000000000..c742b4aaf --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-packaging.py @@ -0,0 +1,13 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# Duplicate hook-pkg_resources.py. +hiddenimports = ["pkg_resources"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pandas.io.formats.style.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pandas.io.formats.style.py new file mode 100755 index 000000000..2a5682831 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pandas.io.formats.style.py @@ -0,0 +1,18 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_data_files + +# This module indirectly imports jinja2 +hiddenimports = ['jinja2'] + +# It also requires template file stored in pandas/io/formats/templates +datas = collect_data_files('pandas.io.formats') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pandas.plotting.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pandas.plotting.py new file mode 100755 index 000000000..96adf89d4 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pandas.plotting.py @@ -0,0 +1,18 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import is_module_satisfies + +# Starting with pandas 1.3.0, pandas.plotting._matplotlib is imported via importlib.import_module() and needs to be +# added to hidden imports. But do this only if matplotlib is available in the first place (as it is soft dependency +# of pandas). +if is_module_satisfies('pandas >= 1.3.0') and is_module_satisfies('matplotlib'): + hiddenimports = ['pandas.plotting._matplotlib'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pandas.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pandas.py new file mode 100755 index 000000000..df6d07507 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pandas.py @@ -0,0 +1,20 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2017-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_submodules, is_module_satisfies + +# Pandas keeps Python extensions loaded with dynamic imports here. +hiddenimports = collect_submodules('pandas._libs') + +# Pandas 1.2.0 and later require cmath hidden import on linux and macOS. On Windows, this is not strictly required, but +# we add it anyway to keep things simple (and future-proof). +if is_module_satisfies('pandas >= 1.2.0'): + hiddenimports += ['cmath'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pickle.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pickle.py new file mode 100755 index 000000000..8d023bbe2 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pickle.py @@ -0,0 +1,13 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2015-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# Only required when run as `__main__` +excludedimports = ["argparse", "doctest"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pkg_resources.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pkg_resources.py new file mode 100755 index 000000000..3fc9dd1fd --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pkg_resources.py @@ -0,0 +1,57 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_submodules, is_module_satisfies, can_import_module + +# pkg_resources keeps vendored modules in its _vendor subpackage, and does sys.meta_path based import magic to expose +# them as pkg_resources.extern.* + +# The `railroad` package is an optional requirement for `pyparsing`. `pyparsing.diagrams` depends on `railroad`, so +# filter it out when `railroad` is not available. +if can_import_module('railroad'): + hiddenimports = collect_submodules('pkg_resources._vendor') +else: + hiddenimports = collect_submodules( + 'pkg_resources._vendor', filter=lambda name: 'pkg_resources._vendor.pyparsing.diagram' not in name + ) + +# pkg_resources v45.0 dropped support for Python 2 and added this module printing a warning. We could save some bytes if +# we would replace this by a fake module. +if is_module_satisfies('setuptools >= 45.0.0, < 49.1.1'): + hiddenimports.append('pkg_resources.py2_warn') + +excludedimports = ['__main__'] + +# Some more hidden imports. See: +# https://github.com/pyinstaller/pyinstaller-hooks-contrib/issues/15#issuecomment-663699288 `packaging` can either be +# its own package, or embedded in `pkg_resources._vendor.packaging`, or both. +hiddenimports += collect_submodules('packaging') + +# As of v60.7, setuptools vendored jaraco and has pkg_resources use it. Currently, the pkg_resources._vendor.jaraco +# namespace package cannot be automatically scanned due to limited support for pure namespace packages in our hook +# utilities. +# +# In setuptools 60.7.0, the vendored jaraco.text package included "Lorem Ipsum.txt" data file, which also has to be +# collected. However, the presence of the data file (and the resulting directory hierarchy) confuses the importer's +# redirection logic; instead of trying to work-around that, tell user to upgrade or downgrade their setuptools. +if is_module_satisfies("setuptools == 60.7.0"): + raise SystemExit( + "ERROR: Setuptools 60.7.0 is incompatible with PyInstaller. " + "Downgrade to an earlier version or upgrade to a later version." + ) +# In setuptools 60.7.1, the "Lorem Ipsum.txt" data file was dropped from the vendored jaraco.text package, so we can +# accommodate it with couple of hidden imports. +elif is_module_satisfies("setuptools >= 60.7.1"): + hiddenimports += [ + 'pkg_resources._vendor.jaraco.functools', + 'pkg_resources._vendor.jaraco.context', + 'pkg_resources._vendor.jaraco.text', + ] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-platform.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-platform.py new file mode 100755 index 000000000..d1d8e1d1f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-platform.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +import sys + +# see https://github.com/python/cpython/blob/3.9/Lib/platform.py#L411 +# This will exclude `plistlib` for sys.platform != 'darwin' +if sys.platform != 'darwin': + excludedimports = ["plistlib"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pygments.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pygments.py new file mode 100755 index 000000000..529d82b04 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pygments.py @@ -0,0 +1,29 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +PyInstaller hook file for Pygments. Tested with version 2.0.2. +""" + +from PyInstaller.utils.hooks import collect_submodules + +# The following applies to pygments version 2.0.2, as reported by ``pip show pygments``. +# +# From pygments.formatters, line 37:: +# +# def _load_formatters(module_name): +# """Load a formatter (and all others in the module too).""" +# mod = __import__(module_name, None, None, ['__all__']) +# +# Therefore, we need all the modules in ``pygments.formatters``. + +hiddenimports = collect_submodules('pygments.formatters') +hiddenimports.extend(collect_submodules('pygments.lexers')) +hiddenimports.extend(collect_submodules('pygments.styles')) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pytz.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pytz.py new file mode 100755 index 000000000..d6b6486a9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pytz.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_data_files + +# On Linux pytz installed from distribution repository uses zoneinfo from /usr/share/zoneinfo/ and no data files might +# be collected. +datas = collect_data_files('pytz') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pytzdata.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pytzdata.py new file mode 100755 index 000000000..e45626ca9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-pytzdata.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("pytzdata") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-qtawesome.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-qtawesome.py new file mode 100755 index 000000000..9829a0341 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-qtawesome.py @@ -0,0 +1,19 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2017-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Hook for QtAwesome (https://github.com/spyder-ide/qtawesome). +Font files and charmaps need to be included with module. +Tested with QtAwesome 0.4.4 and Python 3.6 on macOS 10.12.4. +""" + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('qtawesome') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scapy.layers.all.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scapy.layers.all.py new file mode 100755 index 000000000..fdcc77956 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scapy.layers.all.py @@ -0,0 +1,19 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_submodules + +# The layers to load can be configured using scapy's conf.load_layers. +# from scapy.config import conf; print(conf.load_layers) +# I decided not to use this, but to include all layer modules. The reason is: When building the package, load_layers may +# not include all the layer modules the program will use later. + +hiddenimports = collect_submodules('scapy.layers') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.io.matlab.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.io.matlab.py new file mode 100755 index 000000000..c69c7677d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.io.matlab.py @@ -0,0 +1,13 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# Module scipy.io.matlab allows to parse matlab files. The hidden import is necessary for SciPy 0.11+. +hiddenimports = ['scipy.io.matlab.streams'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.linalg.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.linalg.py new file mode 100755 index 000000000..b1a68b8f9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.linalg.py @@ -0,0 +1,13 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# The hidden import is necessary for SciPy 0.16+. +hiddenimports = ['scipy.linalg.cython_blas', 'scipy.linalg.cython_lapack'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.py new file mode 100755 index 000000000..7e0b9c07b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.py @@ -0,0 +1,35 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +# ----------------------------------------------------------------------------- + +import glob +import os + +from PyInstaller.compat import is_win +from PyInstaller.utils.hooks import get_module_file_attribute, is_module_satisfies, collect_delvewheel_libs_directory + +binaries = [] +datas = [] + +# Package the DLL bundle that official scipy wheels for Windows ship The DLL bundle will either be in extra-dll on +# windows proper and in .libs if installed on a virtualenv created from MinGW (Git-Bash for example) +if is_win: + extra_dll_locations = ['extra-dll', '.libs'] + for location in extra_dll_locations: + dll_glob = os.path.join(os.path.dirname(get_module_file_attribute('scipy')), location, "*.dll") + if glob.glob(dll_glob): + binaries.append((dll_glob, ".")) + +# Handle delvewheel-enabled win32 wheels, which have external scipy.libs directory (scipy >= 0.9.2) +if is_module_satisfies("scipy >= 1.9.2") and is_win: + datas, binaries = collect_delvewheel_libs_directory('scipy', datas=datas, binaries=binaries) + +# collect library-wide utility extension modules +hiddenimports = ['scipy._lib.%s' % m for m in ['messagestream', "_ccallback_c", "_fpumode"]] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.sparse.csgraph.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.sparse.csgraph.py new file mode 100755 index 000000000..9cabdbd67 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.sparse.csgraph.py @@ -0,0 +1,13 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# The hidden import is necessary for SciPy 0.11+. +hiddenimports = ['scipy.sparse.csgraph._validation'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.spatial.transform.rotation.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.spatial.transform.rotation.py new file mode 100755 index 000000000..d8589e3a0 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.spatial.transform.rotation.py @@ -0,0 +1,17 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import is_module_satisfies + +# As of scipy 1.6.0, scipy.spatial.transform.rotation is cython-compiled, so we fail to automatically pick up its +# imports. +if is_module_satisfies("scipy >= 1.6.0"): + hiddenimports = ['scipy.spatial.transform._rotation_groups'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.special._ellip_harm_2.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.special._ellip_harm_2.py new file mode 100755 index 000000000..5115b02c9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.special._ellip_harm_2.py @@ -0,0 +1,30 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Module hook for the `scipy.special._ellip_harm_2` C extension first introduced by SciPy >= 0.15.0. + +See Also +---------- +https://github.com/scipy/scipy/blob/master/scipy/special/_ellip_harm_2.pyx + This C extension's Cython-based implementation. +""" + +# In SciPy >= 0.15.0: +# +# 1. The "scipy.special.__init__" module imports... +# 2. The "scipy.special._ellip_harm" module imports... +# 3. The "scipy.special._ellip_harm_2" C extension imports... +# 4. The "scipy.integrate" package. +# +# The third import is undetectable by PyInstaller and hence explicitly listed. Since "_ellip_harm" and "_ellip_harm_2" +# were first introduced by SciPy 0.15.0, the following hidden import will only be applied for versions of SciPy +# guaranteed to provide these modules and C extensions. +hiddenimports = ['scipy.integrate'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.special._ufuncs.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.special._ufuncs.py new file mode 100755 index 000000000..2498d85a7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.special._ufuncs.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# Module scipy.io._ufunc on some other C/C++ extensions. The hidden import is necessary for SciPy 0.13+. +# Thanks to dyadkin; see issue #826. +hiddenimports = ['scipy.special._ufuncs_cxx'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.stats._stats.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.stats._stats.py new file mode 100755 index 000000000..e7147659a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scipy.stats._stats.py @@ -0,0 +1,15 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import is_module_satisfies + +if is_module_satisfies("scipy >= 1.5.0"): + hiddenimports = ['scipy.special.cython_special'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scrapy.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scrapy.py new file mode 100755 index 000000000..f110bb0f1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-scrapy.py @@ -0,0 +1,18 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# Hook for https://pypi.org/project/Scrapy/ +# https://stackoverflow.com/questions/49085970/no-such-file-or-directory-error-using-pyinstaller-and-scrapy + +from PyInstaller.utils.hooks import collect_data_files, collect_submodules + +datas = collect_data_files('scrapy') +hiddenimports = collect_submodules('scrapy') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-setuptools.msvc.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-setuptools.msvc.py new file mode 100755 index 000000000..9533f2ef2 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-setuptools.msvc.py @@ -0,0 +1,13 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2015-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# Only imported if numpy is installed; avoid pulling in numpy. +excludedimports = ["numpy"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-setuptools.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-setuptools.py new file mode 100755 index 000000000..a84977d7d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-setuptools.py @@ -0,0 +1,41 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.compat import is_darwin, is_unix +from PyInstaller.utils.hooks import collect_submodules, is_module_satisfies + +hiddenimports = [ + # Test case import/test_zipimport2 fails during importing pkg_resources or setuptools when module not present. + 'distutils.command.build_ext', + 'setuptools.msvc', +] + +# Necessary for setuptools on Mac/Unix +if is_unix or is_darwin: + hiddenimports.append('syslog') + +# setuptools >= 39.0.0 is "vendoring" its own direct dependencies from "_vendor" to "extern". This also requires +# 'pre_safe_import_module/hook-setuptools.extern.six.moves.py' to make the moves defined in 'setuptools._vendor.six' +# importable under 'setuptools.extern.six'. +_excluded_submodules = ( + # Prevent recursing into setuptools._vendor.pyparsing.diagram, which typically fails to be imported due to + # missing dependencies (railroad, pyparsing (?), jinja2) and generates a warning... As the module is usually + # unimportable, it is likely not to be used by setuptools. + 'setuptools._vendor.pyparsing.diagram', +) +hiddenimports.extend(collect_submodules('setuptools._vendor', filter=lambda name: name not in _excluded_submodules)) + +# As of setuptools >= 60.0, we need to collect the vendored version of distutils via hiddenimports. The corresponding +# pyi_rth_setuptools runtime hook ensures that the _distutils_hack is installed at the program startup, which allows +# setuptools to override the stdlib distutils with its vendored version, if necessary. +if is_module_satisfies("setuptools >= 60.0"): + hiddenimports += ["_distutils_hack"] + hiddenimports += collect_submodules("setuptools._distutils") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-shelve.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-shelve.py new file mode 100755 index 000000000..1df601a83 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-shelve.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# Tested on Windows 7 x64 With Python 3.5 + +hiddenimports = ["dbm.ndbm", "dbm.dumb", "dbm.gnu"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-sphinx.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-sphinx.py new file mode 100755 index 000000000..f5a13acc6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-sphinx.py @@ -0,0 +1,41 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_data_files, collect_submodules, eval_statement + +# Sphinx consists of several extensions that are lazily loaded. So collect all submodules to ensure we do not miss +# any of them. +hiddenimports = collect_submodules('sphinx') + +# For each extension in sphinx.application.builtin_extensions that does not come from the sphinx package, do a +# collect_submodules(). We need to do this explicitly because collect_submodules() does not seem to work with +# namespace packages, which precludes us from simply doing hiddenimports += collect_submodules('sphinxcontrib') +builtin_extensions = list( + eval_statement( + """ + from sphinx.application import builtin_extensions + print(builtin_extensions) + """ + ) +) +for extension in builtin_extensions: + if extension.startswith('sphinx.'): + continue # Already collected + hiddenimports += collect_submodules(extension) + +# This is inherited from an earlier version of the hook, and seems to have been required in Sphinx v.1.3.1 era due to +# https://github.com/sphinx-doc/sphinx/blob/b87ce32e7dc09773f9e71305e66e8d6aead53dd1/sphinx/cmdline.py#L173. +# It does not hurt to keep it around, just in case. +hiddenimports += ['locale'] + +# Collect all data files: *.html and *.conf files in ``sphinx.themes``, translation files in ``sphinx.locale``, etc. +# Also collect all data files for the alabaster theme. +datas = collect_data_files('sphinx') + collect_data_files('alabaster') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-sqlalchemy.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-sqlalchemy.py new file mode 100755 index 000000000..cd8409dc2 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-sqlalchemy.py @@ -0,0 +1,77 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +import re + +from PyInstaller import isolated +from PyInstaller.lib.modulegraph.modulegraph import SourceModule +from PyInstaller.lib.modulegraph.util import guess_encoding +from PyInstaller.utils.hooks import is_module_satisfies, logger + +# 'sqlalchemy.testing' causes bundling a lot of unnecessary modules. +excludedimports = ['sqlalchemy.testing'] + +# Include most common database bindings some database bindings are detected and include some are not. We should +# explicitly include database backends. +hiddenimports = ['pysqlite2', 'MySQLdb', 'psycopg2', 'sqlalchemy.ext.baked'] + +if is_module_satisfies('sqlalchemy >= 1.4'): + hiddenimports.append("sqlalchemy.sql.default_comparator") + + +@isolated.decorate +def _get_dialect_modules(module_name): + import importlib + module = importlib.import_module(module_name) + return [f"{module_name}.{submodule_name}" for submodule_name in module.__all__] + + +# In SQLAlchemy >= 0.6, the "sqlalchemy.dialects" package provides dialects. +# In SQLAlchemy <= 0.5, the "sqlalchemy.databases" package provides dialects. +if is_module_satisfies('sqlalchemy >= 0.6'): + hiddenimports += _get_dialect_modules("sqlalchemy.dialects") +else: + hiddenimports += _get_dialect_modules("sqlalchemy.databases") + + +def hook(hook_api): + """ + SQLAlchemy 0.9 introduced the decorator 'util.dependencies'. This decorator does imports. E.g.: + + @util.dependencies("sqlalchemy.sql.schema") + + This hook scans for included SQLAlchemy modules and then scans those modules for any util.dependencies and marks + those modules as hidden imports. + """ + + if not is_module_satisfies('sqlalchemy >= 0.9'): + return + + # this parser is very simplistic but seems to catch all cases as of V1.1 + depend_regex = re.compile(r'@util.dependencies\([\'"](.*?)[\'"]\)') + + hidden_imports_set = set() + known_imports = set() + for node in hook_api.module_graph.iter_graph(start=hook_api.module): + if isinstance(node, SourceModule) and node.identifier.startswith('sqlalchemy.'): + known_imports.add(node.identifier) + # Determine the encoding of the source file. + with open(node.filename, 'rb') as f: + encoding = guess_encoding(f) + # Use that to open the file. + with open(node.filename, 'r', encoding=encoding) as f: + for match in depend_regex.findall(f.read()): + hidden_imports_set.add(match) + + hidden_imports_set -= known_imports + if len(hidden_imports_set): + logger.info(" Found %d sqlalchemy hidden imports", len(hidden_imports_set)) + hook_api.add_imports(*list(hidden_imports_set)) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-sqlite3.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-sqlite3.py new file mode 100755 index 000000000..805bf8fa3 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-sqlite3.py @@ -0,0 +1,19 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = [] + +# On Windows in Python 3.4 'sqlite3' package might contain tests that are not required in frozen application. +for mod in collect_submodules('sqlite3'): + if not mod.startswith('sqlite3.test'): + hiddenimports.append(mod) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-sysconfig.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-sysconfig.py new file mode 100755 index 000000000..d4331cfb9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-sysconfig.py @@ -0,0 +1,29 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +import sys + +# see https://github.com/python/cpython/blob/3.9/Lib/sysconfig.py#L593 +# This will exclude `_osx_support`, `distutils`, `distutils.log` for sys.platform != 'darwin' +if sys.platform != 'darwin': + excludedimports = ["_osx_support"] + +# Python 3.6 uses additional modules like `_sysconfigdata_m_linux_x86_64-linux-gnu`, see +# https://github.com/python/cpython/blob/3.6/Lib/sysconfig.py#L417 +# Note: Some versions of Anaconda backport this feature to before 3.6. See issue #3105. +# Note: on Windows, python.org and Anaconda python provide _get_sysconfigdata_name, but calling it fails due to sys +# module lacking abiflags attribute. It does work on MSYS2/MINGW python, where we need to collect corresponding file. +try: + import sysconfig + hiddenimports = [sysconfig._get_sysconfigdata_name()] +except AttributeError: + # Either sysconfig has no attribute _get_sysconfigdata_name (i.e., the function does not exist), or this is Windows + # and the _get_sysconfigdata_name() call failed due to missing sys.abiflags attribute. + pass diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-wcwidth.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-wcwidth.py new file mode 100755 index 000000000..dc7c2dd47 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-wcwidth.py @@ -0,0 +1,14 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2017-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('wcwidth') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-win32ctypes.core.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-win32ctypes.core.py new file mode 100755 index 000000000..cfd310145 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-win32ctypes.core.py @@ -0,0 +1,21 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2020-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# TODO: remove this hook during PyInstaller 4.5 release cycle! + +from PyInstaller.utils.hooks import can_import_module, collect_submodules + +# We need to collect submodules from win32ctypes.core.cffi or win32ctypes.core.ctypes for win32ctypes.core to work. The +# use of the backend is determined by availability of cffi. +if can_import_module('cffi'): + hiddenimports = collect_submodules('win32ctypes.core.cffi') +else: + hiddenimports = collect_submodules('win32ctypes.core.ctypes') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-xml.dom.domreg.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-xml.dom.domreg.py new file mode 100755 index 000000000..eb7161aed --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-xml.dom.domreg.py @@ -0,0 +1,13 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# xml.dom.domreg line 54 +hiddenimports = ['xml.dom.minidom'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-xml.etree.cElementTree.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-xml.etree.cElementTree.py new file mode 100755 index 000000000..95dc702b6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-xml.etree.cElementTree.py @@ -0,0 +1,13 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# cElementTree has a hidden import (Python >=2.5 stdlib version) +hiddenimports = ['xml.etree.ElementTree'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-xml.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-xml.py new file mode 100755 index 000000000..d7776a0f9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-xml.py @@ -0,0 +1,12 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +hiddenimports = ['xml.sax.xmlreader', 'xml.sax.expatreader'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-zope.interface.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-zope.interface.py new file mode 100755 index 000000000..b43d0232d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/hook-zope.interface.py @@ -0,0 +1,12 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2015-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +excludedimports = ["unittest"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_find_module_path/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_find_module_path/__init__.py new file mode 100755 index 000000000..792d60054 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_find_module_path/__init__.py @@ -0,0 +1 @@ +# diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_find_module_path/hook-PyQt5.uic.port_v2.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_find_module_path/hook-PyQt5.uic.port_v2.py new file mode 100755 index 000000000..014c9e2b6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_find_module_path/hook-PyQt5.uic.port_v2.py @@ -0,0 +1,15 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_find_module_path(hook_api): + # Forbid imports in the port_v2 directory under Python 3 The code wouldn't import and would crash the build process. + hook_api.search_dirs = [] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_find_module_path/hook-_pyi_rth_utils.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_find_module_path/hook-_pyi_rth_utils.py new file mode 100755 index 000000000..d035df000 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_find_module_path/hook-_pyi_rth_utils.py @@ -0,0 +1,25 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +# ----------------------------------------------------------------------------- +""" +This hook allows discovery and collection of PyInstaller's internal _pyi_rth_utils module that provides utility +functions for run-time hooks. + +The module is implemented in 'PyInstaller/fake-modules/_pyi_rth_utils.py'. +""" + +import os + +from PyInstaller import PACKAGEPATH + + +def pre_find_module_path(api): + module_dir = os.path.join(PACKAGEPATH, 'fake-modules') + api.search_dirs = [module_dir] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_find_module_path/hook-distutils.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_find_module_path/hook-distutils.py new file mode 100755 index 000000000..0e7e64603 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_find_module_path/hook-distutils.py @@ -0,0 +1,46 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +# ----------------------------------------------------------------------------- +""" +`distutils`-specific pre-find module path hook. + +When run from within a virtual environment, this hook changes the `__path__` of the `distutils` package to +that of the system-wide rather than virtual-environment-specific `distutils` package. While the former is suitable for +freezing, the latter is intended for use _only_ from within virtual environments. + +NOTE: this behavior seems to be specific to virtual environments created by (an old?) version of `virtualenv`; it is not +applicable to virtual environments created by the `venv`. +""" + +import pathlib + +from PyInstaller.utils.hooks import logger, get_module_file_attribute + + +def pre_find_module_path(api): + # Absolute path of the system-wide "distutils" package when run from within a venv or None otherwise. + + # opcode is not a virtualenv module, so we can use it to find the stdlib. Technique taken from virtualenv's + # "distutils" package detection at + # https://github.com/pypa/virtualenv/blob/16.3.0/virtualenv_embedded/distutils-init.py#L5 + # As opcode is a module, stdlib path corresponds to the parent directory of its ``__file__`` attribute. + stdlib_path = pathlib.Path(get_module_file_attribute('opcode')).parent.resolve() + # As distutils is a package, we need to consider the grandparent directory of its ``__file__`` attribute. + distutils_path = pathlib.Path(get_module_file_attribute('distutils')).parent.parent.resolve() + + if distutils_path.name == 'setuptools': + logger.debug("distutils: provided by setuptools") + elif distutils_path == stdlib_path: + logger.debug("distutils: provided by stdlib") + else: + # Find this package in stdlib. + stdlib_path = str(stdlib_path) + logger.debug("distutils: virtualenv shim - retargeting to stdlib dir %r", stdlib_path) + api.search_dirs = [stdlib_path] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_find_module_path/hook-pyi_splash.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_find_module_path/hook-pyi_splash.py new file mode 100755 index 000000000..15f8009fb --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_find_module_path/hook-pyi_splash.py @@ -0,0 +1,36 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +# ----------------------------------------------------------------------------- +""" +This hook does not move a module that can be installed by a package manager, but points to a PyInstaller internal +module that can be imported into the users python instance. + +The module is implemented in 'PyInstaller/fake-modules/pyi_splash.py'. +""" + +import os + +from PyInstaller import PACKAGEPATH +from PyInstaller.utils.hooks import logger + + +def pre_find_module_path(api): + try: + # Test if a module named 'pyi_splash' is locally installed. This prevents that a potentially required dependency + # is not packed + import pyi_splash # noqa: F401 + except ImportError: + module_dir = os.path.join(PACKAGEPATH, 'fake-modules') + + api.search_dirs = [module_dir] + logger.info('Adding pyi_splash module to application dependencies.') + else: + logger.info('A local module named "pyi_splash" is installed. Use the installed one instead.') + return diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/__init__.py new file mode 100755 index 000000000..792d60054 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/__init__.py @@ -0,0 +1 @@ +# diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-distutils.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-distutils.py new file mode 100755 index 000000000..f9f831265 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-distutils.py @@ -0,0 +1,35 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller import compat +from PyInstaller.utils import hooks as hookutils + + +def pre_safe_import_module(api): + # `distutils` was removed from from stdlib in python 3.12; if it is available, it is provided by `setuptools`. + # Therefore, we need to mark it as a run-time package - this ensures that even though modulegraph cannot find the + # module, it will call the standard hook nevertheless, and the standard hook will trigger the collection of + # `setuptools`, which in turn will make `distutils` available at the run-time. + # + # Unfortunately, making the package a run-time package also means that we need to mark all its submodules and + # subpackages as run-time ones as well... + if compat.is_py312: + distutils_submodules = hookutils.collect_submodules('setuptools._distutils') + + # Known package names - so we can avoid calling hooksutils.is_package() for every entry... + PACKAGES = {'distutils', 'distutils.command'} + + for module_name in distutils_submodules: + mapped_name = module_name.replace('setuptools._distutils', 'distutils') + if mapped_name in PACKAGES: + api.add_runtime_package(mapped_name) + else: + api.add_runtime_module(mapped_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.py new file mode 100755 index 000000000..e71843dbc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.py @@ -0,0 +1,37 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2022-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller import compat +from PyInstaller.utils import hooks as hookutils + + +def pre_safe_import_module(api): + if compat.is_linux: + # RHEL/Fedora RPM package for GObject introspection is known to split the `gi` package into two locations: + # - /usr/lib64/python3.x/site-packages/gi + # - /usr/lib/python3.x/site-packages/gi + # The `__init__.py` is located in the first directory, while `repository` and `overrides` are located in + # the second, and `__init__.py` dynamically extends the `__path__` during package import, using + # `__path__ = pkgutil.extend_path(__path__, __name__)`. + # The modulegraph has no way of knowing this, so we need extend the package path in this hook. Otherwise, + # only the first location is scanned, and the `gi.repository` ends up missing. + # + # NOTE: the `get_package_paths`/`get_package_all_paths` helpers read the paths from package's spec without + # importing the (top-level) package, so they do not catch run-time path modifications. Instead, we use + # `get_module_attribute` to import the package in isolated process and query its `__path__` attribute. + try: + paths = hookutils.get_module_attribute(api.module_name, "__path__") + except Exception: + # Most likely `gi` cannot be imported. + paths = [] + + for path in paths: + api.append_package_path(path) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Adw.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Adw.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Adw.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Atk.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Atk.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Atk.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Champlain.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Champlain.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Champlain.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Clutter.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Clutter.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Clutter.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GIRepository.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GIRepository.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GIRepository.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GLib.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GLib.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GLib.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GModule.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GModule.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GModule.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GObject.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GObject.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GObject.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Gdk.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Gdk.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Gdk.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GdkPixbuf.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GdkPixbuf.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GdkPixbuf.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Gio.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Gio.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Gio.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Graphene.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Graphene.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Graphene.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Gsk.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Gsk.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Gsk.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Gst.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Gst.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Gst.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstAllocators.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstAllocators.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstAllocators.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstApp.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstApp.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstApp.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstAudio.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstAudio.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstAudio.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstBadAudio.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstBadAudio.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstBadAudio.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstBase.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstBase.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstBase.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstCheck.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstCheck.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstCheck.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstCodecs.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstCodecs.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstCodecs.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstController.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstController.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstController.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstGL.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstGL.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstGL.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstGLEGL.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstGLEGL.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstGLEGL.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstGLWayland.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstGLWayland.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstGLWayland.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstGLX11.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstGLX11.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstGLX11.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstInsertBin.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstInsertBin.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstInsertBin.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstMpegts.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstMpegts.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstMpegts.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstNet.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstNet.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstNet.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstPbutils.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstPbutils.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstPbutils.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstPlay.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstPlay.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstPlay.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstPlayer.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstPlayer.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstPlayer.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstRtp.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstRtp.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstRtp.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstRtsp.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstRtsp.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstRtsp.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstRtspServer.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstRtspServer.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstRtspServer.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstSdp.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstSdp.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstSdp.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstTag.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstTag.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstTag.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstTranscoder.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstTranscoder.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstTranscoder.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstVideo.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstVideo.py new file mode 100755 index 000000000..e75bfee03 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstVideo.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert + # them to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstVulkan.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstVulkan.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstVulkan.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstVulkanWayland.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstVulkanWayland.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstVulkanWayland.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstVulkanXCB.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstVulkanXCB.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstVulkanXCB.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstWebRTC.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstWebRTC.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GstWebRTC.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Gtk.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Gtk.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Gtk.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GtkChamplain.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GtkChamplain.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GtkChamplain.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GtkClutter.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GtkClutter.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GtkClutter.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GtkSource.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GtkSource.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GtkSource.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GtkosxApplication.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GtkosxApplication.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.GtkosxApplication.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.HarfBuzz.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.HarfBuzz.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.HarfBuzz.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Pango.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Pango.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.Pango.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.PangoCairo.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.PangoCairo.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.PangoCairo.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.cairo.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.cairo.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.cairo.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.freetype2.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.freetype2.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.freetype2.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.xlib.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.xlib.py new file mode 100755 index 000000000..131ce95ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-gi.repository.xlib.py @@ -0,0 +1,16 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + + +def pre_safe_import_module(api): + # PyGObject modules loaded through the gi repository are marked as MissingModules by modulegraph, so we convert them + # to RuntimeModules in order for their hooks to be loaded and executed. + api.add_runtime_module(api.module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-setuptools.extern.six.moves.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-setuptools.extern.six.moves.py new file mode 100755 index 000000000..f8014f071 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-setuptools.extern.six.moves.py @@ -0,0 +1,35 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller import isolated + +# This is basically a copy of pre_safe_import_module/hook-six.moves.py adopted to setuptools.extern.six resp. +# setuptools._vendor.six. Please see pre_safe_import_module/hook-six.moves.py for documentation. + +# Note that the moves are defined in 'setuptools._vendor.six' but are imported under 'setuptools.extern.six'. + + +def pre_safe_import_module(api): + @isolated.call + def real_to_six_module_name(): + try: + import setuptools._vendor.six as six + except ImportError: + import setuptools.extern.six as six + + return { + moved.mod: 'setuptools.extern.six.moves.' + moved.name + for moved in six._moved_attributes if isinstance(moved, (six.MovedModule, six.MovedAttribute)) + } + + api.add_runtime_package(api.module_name) + for real_module_name, six_module_name in real_to_six_module_name.items(): + api.add_alias_module(real_module_name, six_module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-six.moves.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-six.moves.py new file mode 100755 index 000000000..2b4b283d7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-six.moves.py @@ -0,0 +1,60 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller import isolated + + +def pre_safe_import_module(api): + """ + Add the `six.moves` module as a dynamically defined runtime module node and all modules mapped by + `six._SixMetaPathImporter` as aliased module nodes to the passed graph. + + The `six.moves` module is dynamically defined at runtime by the `six` module and hence cannot be imported in the + standard way. Instead, this hook adds a placeholder node for the `six.moves` module to the graph, + which implicitly adds an edge from that node to the node for its parent `six` module. This ensures that the `six` + module will be frozen into the executable. (Phew!) + + `six._SixMetaPathImporter` is a PEP 302-compliant module importer converting imports independent of the current + Python version into imports specific to that version (e.g., under Python 3, from `from six.moves import + tkinter_tix` to `import tkinter.tix`). For each such mapping, this hook adds a corresponding module alias to the + graph allowing PyInstaller to translate the former to the latter. + """ + @isolated.call + def real_to_six_module_name(): + """ + Generate a dictionary from conventional module names to "six.moves" attribute names (e.g., from `tkinter.tix` to + `six.moves.tkinter_tix`). + """ + import six + + # Iterate over the "six._moved_attributes" list rather than the "six._importer.known_modules" dictionary, as + # "urllib"-specific moved modules are overwritten in the latter with unhelpful "LazyModule" objects. If this is + # a moved module or attribute, map the corresponding module. In the case of moved attributes, the attribute's + # module is mapped while the attribute itself is mapped at runtime and hence ignored here. + return { + moved.mod: 'six.moves.' + moved.name + for moved in six._moved_attributes if isinstance(moved, (six.MovedModule, six.MovedAttribute)) + } + + # Add "six.moves" as a runtime package rather than module. Modules cannot physically contain submodules; only + # packages can. In "from"-style import statements (e.g., "from six.moves import queue"), this implies that: + # * Attributes imported from customary modules are guaranteed *NOT* to be submodules. Hence, ModuleGraph justifiably + # ignores these attributes. While some attributes declared by "six.moves" are ignorable non-modules (e.g., + # functions, classes), others are non-ignorable submodules that must be imported. Adding "six.moves" as a runtime + # module causes ModuleGraph to ignore these submodules, which defeats the entire point. + # * Attributes imported from packages could be submodules. To disambiguate non-ignorable submodules from ignorable + # non-submodules (e.g., classes, variables), ModuleGraph first attempts to import these attributes as submodules. + # This is exactly what we want. + if isinstance(real_to_six_module_name, str): + raise SystemExit("pre-safe-import-module hook failed, needs fixing.") + api.add_runtime_package(api.module_name) + for real_module_name, six_module_name in real_to_six_module_name.items(): + api.add_alias_module(real_module_name, six_module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-urllib3.packages.six.moves.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-urllib3.packages.six.moves.py new file mode 100755 index 000000000..f0588f494 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/pre_safe_import_module/hook-urllib3.packages.six.moves.py @@ -0,0 +1,30 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller import isolated + +# This basically is a copy of pre_safe_import_module/hook-six.moves.py adopted to urllib3.packages.six. Please see +# pre_safe_import_module/hook-six.moves.py for documentation. + + +def pre_safe_import_module(api): + @isolated.call + def real_to_six_module_name(): + import urllib3.packages.six as six + + return { + moved.mod: 'urllib3.packages.six.moves.' + moved.name + for moved in six._moved_attributes if isinstance(moved, (six.MovedModule, six.MovedAttribute)) + } + + api.add_runtime_package(api.module_name) + for real_module_name, six_module_name in real_to_six_module_name.items(): + api.add_alias_module(real_module_name, six_module_name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks.dat b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks.dat new file mode 100755 index 000000000..8f6992421 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks.dat @@ -0,0 +1,28 @@ +{ + 'django': ['pyi_rth_django.py'], + 'gi': ['pyi_rth_gi.py'], + 'gi.repository.Gio': ['pyi_rth_gio.py'], + 'gi.repository.GLib': ['pyi_rth_glib.py'], + 'gi.repository.GdkPixbuf': ['pyi_rth_gdkpixbuf.py'], + 'gi.repository.Gtk': ['pyi_rth_gtk.py'], + 'gi.repository.Gst': ['pyi_rth_gstreamer.py'], + 'gst': ['pyi_rth_gstreamer.py'], + 'inspect': ['pyi_rth_inspect.py'], + 'kivy': ['pyi_rth_kivy.py'], + 'kivy.lib.gstplayer': ['pyi_rth_gstreamer.py'], + 'matplotlib': ['pyi_rth_mplconfig.py'], + 'pkgutil': ['pyi_rth_pkgutil.py'], + 'pkg_resources': ['pyi_rth_pkgres.py'], + 'PyQt5': ['pyi_rth_pyqt5.py'], + 'PyQt5.QtWebEngineCore': ['pyi_rth_pyqt5webengine.py'], + 'PyQt6': ['pyi_rth_pyqt6.py'], + 'PyQt6.QtWebEngineCore': ['pyi_rth_pyqt6webengine.py'], + 'PySide2': ['pyi_rth_pyside2.py'], + 'PySide2.QtWebEngineCore': ['pyi_rth_pyside2webengine.py'], + 'PySide6': ['pyi_rth_pyside6.py'], + 'PySide6.QtWebEngineCore': ['pyi_rth_pyside6webengine.py'], + '_tkinter': ['pyi_rth__tkinter.py'], + 'win32com': ['pyi_rth_win32comgenpy.py'], + 'multiprocessing': ['pyi_rth_multiprocessing.py'], + 'setuptools': ['pyi_rth_setuptools.py'], +} diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/__init__.py new file mode 100755 index 000000000..792d60054 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/__init__.py @@ -0,0 +1 @@ +# diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth__tkinter.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth__tkinter.py new file mode 100755 index 000000000..309355e70 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth__tkinter.py @@ -0,0 +1,36 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + + +def _pyi_rthook(): + import os + import sys + + tcldir = os.path.join(sys._MEIPASS, 'tcl') + tkdir = os.path.join(sys._MEIPASS, 'tk') + + # Notify "tkinter" of data directories. On macOS, we do not collect data directories if system Tcl/Tk framework is + # used. On other OSes, we always collect them, so their absence is considered an error. + is_darwin = sys.platform == 'darwin' + + if os.path.isdir(tcldir): + os.environ["TCL_LIBRARY"] = tcldir + elif not is_darwin: + raise FileNotFoundError('Tcl data directory "%s" not found.' % tcldir) + + if os.path.isdir(tkdir): + os.environ["TK_LIBRARY"] = tkdir + elif not is_darwin: + raise FileNotFoundError('Tk data directory "%s" not found.' % tkdir) + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_django.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_django.py new file mode 100755 index 000000000..81243bde5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_django.py @@ -0,0 +1,34 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +# This Django rthook was tested with Django 1.8.3. + + +def _pyi_rthook(): + import django.utils.autoreload + + _old_restart_with_reloader = django.utils.autoreload.restart_with_reloader + + def _restart_with_reloader(*args): + import sys + a0 = sys.argv.pop(0) + try: + return _old_restart_with_reloader(*args) + finally: + sys.argv.insert(0, a0) + + # Override restart_with_reloader() function, otherwise the app might complain that some commands do not exist; + # e.g., runserver. + django.utils.autoreload.restart_with_reloader = _restart_with_reloader + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_gdkpixbuf.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_gdkpixbuf.py new file mode 100755 index 000000000..0bb7a37f0 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_gdkpixbuf.py @@ -0,0 +1,41 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2015-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + + +def _pyi_rthook(): + import atexit + import os + import sys + import tempfile + + pixbuf_file = os.path.join(sys._MEIPASS, 'lib', 'gdk-pixbuf', 'loaders.cache') + + # If we are not on Windows, we need to rewrite the cache -> we rewrite on Mac OS to support --onefile mode + if os.path.exists(pixbuf_file) and sys.platform != 'win32': + with open(pixbuf_file, 'rb') as fp: + contents = fp.read() + + # Create a temporary file with the cache and cleverly replace the prefix we injected with the actual path. + fd, pixbuf_file = tempfile.mkstemp() + with os.fdopen(fd, 'wb') as fp: + libpath = os.path.join(sys._MEIPASS, 'lib').encode('utf-8') + fp.write(contents.replace(b'@executable_path/lib', libpath)) + + try: + atexit.register(os.unlink, pixbuf_file) + except OSError: + pass + + os.environ['GDK_PIXBUF_MODULE_FILE'] = pixbuf_file + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_gi.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_gi.py new file mode 100755 index 000000000..3c3b38270 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_gi.py @@ -0,0 +1,21 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2015-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + + +def _pyi_rthook(): + import os + import sys + + os.environ['GI_TYPELIB_PATH'] = os.path.join(sys._MEIPASS, 'gi_typelibs') + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_gio.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_gio.py new file mode 100755 index 000000000..f9fc307da --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_gio.py @@ -0,0 +1,21 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2015-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + + +def _pyi_rthook(): + import os + import sys + + os.environ['GIO_MODULE_DIR'] = os.path.join(sys._MEIPASS, 'gio_modules') + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_glib.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_glib.py new file mode 100755 index 000000000..35bd7f823 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_glib.py @@ -0,0 +1,37 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2015-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + + +def _pyi_rthook(): + import os + import sys + + # Prepend the frozen application's data dir to XDG_DATA_DIRS. We need to avoid overwriting the existing paths in + # order to allow the frozen application to run system-installed applications (for example, launch a web browser via + # the webbrowser module on Linux). Should the user desire complete isolation of the frozen application from the + # system, they need to clean up XDG_DATA_DIRS at the start of their program (i.e., remove all entries but first). + pyi_data_dir = os.path.join(sys._MEIPASS, 'share') + + xdg_data_dirs = os.environ.get('XDG_DATA_DIRS', None) + if xdg_data_dirs: + if pyi_data_dir not in xdg_data_dirs: + xdg_data_dirs = pyi_data_dir + os.pathsep + xdg_data_dirs + else: + xdg_data_dirs = pyi_data_dir + os.environ['XDG_DATA_DIRS'] = xdg_data_dirs + + # Cleanup aux variables + del xdg_data_dirs + del pyi_data_dir + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_gstreamer.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_gstreamer.py new file mode 100755 index 000000000..ec3495c1b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_gstreamer.py @@ -0,0 +1,32 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + + +def _pyi_rthook(): + import os + import sys + + # Without this environment variable set to 'no' importing 'gst' causes 100% CPU load. (Tested on Mac OS.) + os.environ['GST_REGISTRY_FORK'] = 'no' + + gst_plugin_paths = [sys._MEIPASS, os.path.join(sys._MEIPASS, 'gst-plugins')] + os.environ['GST_PLUGIN_PATH'] = os.pathsep.join(gst_plugin_paths) + + # Prevent permission issues on Windows + os.environ['GST_REGISTRY'] = os.path.join(sys._MEIPASS, 'registry.bin') + + # Only use packaged plugins to prevent GStreamer from crashing when it finds plugins from another version which are + # installed system wide. + os.environ['GST_PLUGIN_SYSTEM_PATH'] = '' + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_gtk.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_gtk.py new file mode 100755 index 000000000..d6ae21cfd --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_gtk.py @@ -0,0 +1,27 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2015-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + + +def _pyi_rthook(): + import os + import sys + + os.environ['GTK_DATA_PREFIX'] = sys._MEIPASS + os.environ['GTK_EXE_PREFIX'] = sys._MEIPASS + os.environ['GTK_PATH'] = sys._MEIPASS + + # Include these here, as GTK will import pango automatically. + os.environ['PANGO_LIBDIR'] = sys._MEIPASS + os.environ['PANGO_SYSCONFDIR'] = os.path.join(sys._MEIPASS, 'etc') # TODO? + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_inspect.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_inspect.py new file mode 100755 index 000000000..5befb39d3 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_inspect.py @@ -0,0 +1,48 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + + +def _pyi_rthook(): + import inspect + import os + import sys + + _orig_inspect_getsourcefile = inspect.getsourcefile + + # Provide custom implementation of inspect.getsourcefile() for frozen applications that properly resolves relative + # filenames obtained from object (e.g., inspect stack-frames). See #5963. + def _pyi_getsourcefile(object): + filename = inspect.getfile(object) + if not os.path.isabs(filename): + # Check if given filename matches the basename of __main__'s __file__. + main_file = getattr(sys.modules['__main__'], '__file__', None) + if main_file and filename == os.path.basename(main_file): + return main_file + + # If filename ends with .py suffix and does not correspond to frozen entry-point script, convert it to + # corresponding .pyc in sys._MEIPASS. + if filename.endswith('.py'): + filename = os.path.normpath(os.path.join(sys._MEIPASS, filename + 'c')) + # Ensure the relative path did not try to jump out of sys._MEIPASS, just in case... + if filename.startswith(sys._MEIPASS): + return filename + elif filename.startswith(sys._MEIPASS) and filename.endswith('.pyc'): + # If filename is already PyInstaller-compatible, prevent any further processing (i.e., with original + # implementation). + return filename + # Use original implementation as a fallback. + return _orig_inspect_getsourcefile(object) + + inspect.getsourcefile = _pyi_getsourcefile + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_kivy.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_kivy.py new file mode 100755 index 000000000..084640167 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_kivy.py @@ -0,0 +1,24 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2015-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + + +def _pyi_rthook(): + import os + import sys + + root = os.path.join(sys._MEIPASS, 'kivy_install') + + os.environ['KIVY_DATA_DIR'] = os.path.join(root, 'data') + os.environ['KIVY_MODULES_DIR'] = os.path.join(root, 'modules') + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_mplconfig.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_mplconfig.py new file mode 100755 index 000000000..6ea9425c9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_mplconfig.py @@ -0,0 +1,46 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +# matplotlib will create $HOME/.matplotlib folder in user's home directory. In this directory there is fontList.cache +# file which lists paths to matplotlib fonts. +# +# When you run your onefile exe for the first time it's extracted to for example "_MEIxxxxx" temp directory and +# fontList.cache file is created with fonts paths pointing to this directory. +# +# Second time you run your exe new directory is created "_MEIyyyyy" but fontList.cache file still points to previous +# directory which was deleted. And then you will get error like: +# +# RuntimeError: Could not open facefile +# +# We need to force matplotlib to recreate config directory every time you run your app. + + +def _pyi_rthook(): + import atexit + import os + import shutil + + import _pyi_rth_utils # PyInstaller's run-time hook utilities module + + # Isolate matplotlib's config dir into temporary directory. + # Use our replacement for `tempfile.mkdtemp` function that properly restricts access to directory on all platforms. + configdir = _pyi_rth_utils.secure_mkdtemp() + os.environ['MPLCONFIGDIR'] = configdir + + try: + # Remove temp directory at application exit and ignore any errors. + atexit.register(shutil.rmtree, configdir, ignore_errors=True) + except OSError: + pass + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_multiprocessing.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_multiprocessing.py new file mode 100755 index 000000000..ae9d257cc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_multiprocessing.py @@ -0,0 +1,110 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2017-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + + +def _pyi_rthook(): + import os + import sys + + import threading + import multiprocessing + import multiprocessing.spawn + + from subprocess import _args_from_interpreter_flags + + # Prevent `spawn` from trying to read `__main__` in from the main script + multiprocessing.process.ORIGINAL_DIR = None + + def _freeze_support(): + # We want to catch the two processes that are spawned by the multiprocessing code: + # - the semaphore tracker, which cleans up named semaphores in the `spawn` multiprocessing mode + # - the fork server, which keeps track of worker processes in the `forkserver` mode. + # Both of these processes are started by spawning a new copy of the running executable, passing it the flags + # from `_args_from_interpreter_flags` and then "-c" and an import statement. + # Look for those flags and the import statement, then `exec()` the code ourselves. + + if ( + len(sys.argv) >= 2 and sys.argv[-2] == '-c' and sys.argv[-1].startswith(( + 'from multiprocessing.semaphore_tracker import main', # Py<3.8 + 'from multiprocessing.resource_tracker import main', # Py>=3.8 + 'from multiprocessing.forkserver import main' + )) and set(sys.argv[1:-2]) == set(_args_from_interpreter_flags()) + ): + exec(sys.argv[-1]) + sys.exit() + + if multiprocessing.spawn.is_forking(sys.argv): + kwds = {} + for arg in sys.argv[2:]: + name, value = arg.split('=') + if value == 'None': + kwds[name] = None + else: + kwds[name] = int(value) + multiprocessing.spawn.spawn_main(**kwds) + sys.exit() + + multiprocessing.freeze_support = multiprocessing.spawn.freeze_support = _freeze_support + + # Bootloader clears the `_MEIPASS2` environment variable, which allows a PyInstaller-frozen executable to run a + # different PyInstaller-frozen executable. However, in the case of `multiprocessing`, we are actually trying + # to run the same executable, so we need to restore `_MEIPASS2` to prevent onefile executable from unpacking + # again in a different directory. + # + # This is needed for `spawn` start method (default on Windows and macOS) and also with `forkserver` start method + # (available on Linux and macOS). It is not needed for `fork` start method (default on Linux and other Unix OSes), + # because fork copies the parent process instead of starting it from scratch. + + # Mix-in to re-set _MEIPASS2 from sys._MEIPASS. + class FrozenSupportMixIn: + _lock = threading.Lock() + + def __init__(self, *args, **kw): + # The whole code block needs be executed under a lock to prevent race conditions between `os.putenv` and + # `os.unsetenv` calls when processes are spawned concurrently from multiple threads. See #7410. + with self._lock: + # We have to set original _MEIPASS2 value from sys._MEIPASS to get --onefile mode working. + os.putenv('_MEIPASS2', sys._MEIPASS) # @UndefinedVariable + try: + super().__init__(*args, **kw) + finally: + # On some platforms (e.g. AIX) 'os.unsetenv()' is not available. In those cases we cannot delete the + # variable but only set it to the empty string. The bootloader can handle this case. + if hasattr(os, 'unsetenv'): + os.unsetenv('_MEIPASS2') + else: + os.putenv('_MEIPASS2', '') + + if sys.platform.startswith('win'): + # Windows; patch `Popen` for `spawn` start method + from multiprocessing import popen_spawn_win32 + + class _SpawnPopen(FrozenSupportMixIn, popen_spawn_win32.Popen): + pass + + popen_spawn_win32.Popen = _SpawnPopen + else: + # UNIX OSes; patch `Popen` for `spawn` and `forkserver` start methods + from multiprocessing import popen_spawn_posix + from multiprocessing import popen_forkserver + + class _SpawnPopen(FrozenSupportMixIn, popen_spawn_posix.Popen): + pass + + class _ForkserverPopen(FrozenSupportMixIn, popen_forkserver.Popen): + pass + + popen_spawn_posix.Popen = _SpawnPopen + popen_forkserver.Popen = _ForkserverPopen + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pkgres.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pkgres.py new file mode 100755 index 000000000..ebfe59488 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pkgres.py @@ -0,0 +1,201 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +# To make pkg_resources work with frozen modules we need to set the 'Provider' class for PyiFrozenImporter. This class +# decides where to look for resources and other stuff. 'pkg_resources.NullProvider' is dedicated to PEP302 import hooks +# like PyiFrozenImporter is. It uses method __loader__.get_data() in methods pkg_resources.resource_string() and +# pkg_resources.resource_stream() +# +# We provide PyiFrozenProvider, which subclasses the NullProvider and implements _has(), _isdir(), and _listdir() +# methods, which are needed for pkg_resources.resource_exists(), resource_isdir(), and resource_listdir() to work. We +# cannot use the DefaultProvider, because it provides filesystem-only implementations (and overrides _get() with a +# filesystem-only one), whereas our provider needs to also support embedded resources. +# +# The PyiFrozenProvider allows querying/listing both PYZ-embedded and on-filesystem resources in a frozen package. The +# results are typically combined for both types of resources (e.g., when listing a directory or checking whether a +# resource exists). When the order of precedence matters, the PYZ-embedded resources take precedence over the +# on-filesystem ones, to keep the behavior consistent with the actual file content retrieval via _get() method (which in +# turn uses PyiFrozenImporter's get_data() method). For example, when checking whether a resource is a directory via +# _isdir(), a PYZ-embedded file will take precedence over a potential on-filesystem directory. Also, in contrast to +# unfrozen packages, the frozen ones do not contain source .py files, which are therefore absent from content listings. + + +def _pyi_rthook(): + import os + import pathlib + import sys + + import pkg_resources + from pyimod02_importers import PyiFrozenImporter + + SYS_PREFIX = pathlib.PurePath(sys._MEIPASS) + + class _TocFilesystem: + """ + A prefix tree implementation for embedded filesystem reconstruction. + """ + def __init__(self, toc_files, toc_dirs=None): + toc_dirs = toc_dirs or [] + # Reconstruct the filesystem hierarchy by building a prefix tree from the given file and directory paths. + self._tree = dict() + + # Data files + for path in toc_files: + path = pathlib.PurePath(path) + current = self._tree + for component in path.parts[:-1]: + current = current.setdefault(component, {}) + current[path.parts[-1]] = '' + + # Extra directories + for path in toc_dirs: + path = pathlib.PurePath(path) + current = self._tree + for component in path.parts: + current = current.setdefault(component, {}) + + def _get_tree_node(self, path): + path = pathlib.PurePath(path) + current = self._tree + for component in path.parts: + if component not in current: + return None + current = current[component] + return current + + def path_exists(self, path): + node = self._get_tree_node(path) + return node is not None # File or directory + + def path_isdir(self, path): + node = self._get_tree_node(path) + if node is None: + return False # Non-existent + if isinstance(node, str): + return False # File + return True + + def path_listdir(self, path): + node = self._get_tree_node(path) + if not isinstance(node, dict): + return [] # Non-existent or file + return list(node.keys()) + + # Cache for reconstructed embedded trees + _toc_tree_cache = {} + + class PyiFrozenProvider(pkg_resources.NullProvider): + """ + Custom pkg_resources provider for PyiFrozenImporter. + """ + def __init__(self, module): + super().__init__(module) + + # Get top-level path; if "module" corresponds to a package, we need the path to the package itself. + # If "module" is a submodule in a package, we need the path to the parent package. + self._pkg_path = pathlib.PurePath(module.__file__).parent + + # Defer initialization of PYZ-embedded resources tree to the first access. + self._embedded_tree = None + + def _init_embedded_tree(self, rel_pkg_path, pkg_name): + # Collect relevant entries from TOC. We are interested in either files that are located in the + # package/module's directory (data files) or in packages that are prefixed with package/module's name + # (to reconstruct subpackage directories). + data_files = [] + package_dirs = [] + for entry in self.loader.toc: + entry_path = pathlib.PurePath(entry) + if rel_pkg_path in entry_path.parents: + # Data file path + data_files.append(entry_path) + elif entry.startswith(pkg_name) and self.loader.is_package(entry): + # Package or subpackage; convert the name to directory path + package_dir = pathlib.PurePath(*entry.split('.')) + package_dirs.append(package_dir) + + # Reconstruct the filesystem + return _TocFilesystem(data_files, package_dirs) + + @property + def embedded_tree(self): + if self._embedded_tree is None: + # Construct a path relative to _MEIPASS directory for searching the TOC. + rel_pkg_path = self._pkg_path.relative_to(SYS_PREFIX) + + # Reconstruct package name prefix (use package path to obtain correct prefix in case of a module). + pkg_name = '.'.join(rel_pkg_path.parts) + + # Initialize and cache the tree, if necessary. + if pkg_name not in _toc_tree_cache: + _toc_tree_cache[pkg_name] = self._init_embedded_tree(rel_pkg_path, pkg_name) + self._embedded_tree = _toc_tree_cache[pkg_name] + return self._embedded_tree + + def _normalize_path(self, path): + # Avoid using Path.resolve(), because it resolves symlinks. This is undesirable, because the pure path in + # self._pkg_path does not have symlinks resolved, so comparison between the two would be faulty. So use + # os.path.abspath() instead to normalize the path. + return pathlib.Path(os.path.abspath(path)) + + def _is_relative_to_package(self, path): + return path == self._pkg_path or self._pkg_path in path.parents + + def _has(self, path): + # Prevent access outside the package. + path = self._normalize_path(path) + if not self._is_relative_to_package(path): + return False + + # Check the filesystem first to avoid unnecessarily computing the relative path... + if path.exists(): + return True + rel_path = path.relative_to(SYS_PREFIX) + return self.embedded_tree.path_exists(rel_path) + + def _isdir(self, path): + # Prevent access outside the package. + path = self._normalize_path(path) + if not self._is_relative_to_package(path): + return False + + # Embedded resources have precedence over filesystem... + rel_path = path.relative_to(SYS_PREFIX) + node = self.embedded_tree._get_tree_node(rel_path) + if node is None: + return path.is_dir() # No match found; try the filesystem. + else: + # str = file, dict = directory + return not isinstance(node, str) + + def _listdir(self, path): + # Prevent access outside the package. + path = self._normalize_path(path) + if not self._is_relative_to_package(path): + return [] + + # Relative path for searching embedded resources. + rel_path = path.relative_to(SYS_PREFIX) + # List content from embedded filesystem... + content = self.embedded_tree.path_listdir(rel_path) + # ... as well as the actual one. + if path.is_dir(): + # Use os.listdir() to avoid having to convert Path objects to strings... Also make sure to de-duplicate + # the results. + path = str(path) # not is_py36 + content = list(set(content + os.listdir(path))) + return content + + pkg_resources.register_loader_type(PyiFrozenImporter, PyiFrozenProvider) + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py new file mode 100755 index 000000000..a4b60305f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pkgutil.py @@ -0,0 +1,91 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- +# +# This rthook overrides pkgutil.iter_modules with custom implementation that uses PyInstaller's PyiFrozenImporter to +# list sub-modules embedded in the PYZ archive. The non-embedded modules (binary extensions, or .pyc modules in +# noarchive build) are handled by original pkgutil iter_modules implementation (and consequently, python's FileFinder). +# +# The preferred way of adding support for iter_modules would be adding non-standard iter_modules() method to +# PyiFrozenImporter itself. However, that seems to work only for path entry finders (for use with sys.path_hooks), while +# PyInstaller's PyiFrozenImporter is registered as meta path finders (for use with sys.meta_path). Turning +# PyiFrozenImporter into path entry finder, would seemingly require the latter to support on-filesystem resources +# (e.g., extension modules) in addition to PYZ-embedded ones. +# +# Therefore, we instead opt for overriding pkgutil.iter_modules with custom implementation that augments the output of +# original implementation with contents of PYZ archive from PyiFrozenImporter's TOC. + + +def _pyi_rthook(): + import os + import pkgutil + import sys + + from pyimod02_importers import PyiFrozenImporter + + _orig_pkgutil_iter_modules = pkgutil.iter_modules + + def _pyi_pkgutil_iter_modules(path=None, prefix=''): + # Use original implementation to discover on-filesystem modules (binary extensions in regular builds, or both + # binary extensions and compiled pyc modules in noarchive debug builds). + yield from _orig_pkgutil_iter_modules(path, prefix) + + # Find the instance of PyInstaller's PyiFrozenImporter. + for importer in pkgutil.iter_importers(): + if isinstance(importer, PyiFrozenImporter): + break + else: + return + + if path is None: + # Search for all top-level packages/modules. These will have no dots in their entry names. + for entry in importer.toc: + if "." in entry: + continue + is_pkg = importer.is_package(entry) + yield pkgutil.ModuleInfo(importer, prefix + entry, is_pkg) + else: + # Use os.path.realpath() to fully resolve any symbolic links in sys._MEIPASS, in order to avoid path + # mis-matches when the given search paths also contain symbolic links and are already fully resolved. + # See #6537 for an example of such a problem with onefile build on macOS, where the temporary directory + # is placed under /var, which is actually a symbolic link to /private/var. + MEIPASS = os.path.realpath(sys._MEIPASS) + + for pkg_path in path: + # Fully resolve the given path, in case it contains symbolic links. + pkg_path = os.path.realpath(pkg_path) + # Ensure it ends with os.path.sep (so we can directly filter out the package itself). + if not pkg_path.endswith(os.path.sep): + pkg_path += os.path.sep + + for entry in importer.toc: + # Get the path to the module, and resolve symbolic links. This implicitly solves the problem with + # macOS .app bundles and packages that contain data files, where package directory is fully + # collected into Contents/Resources, and symbolic link to directory is created in sys._MEIPASS + # (Contents/Frameworks). See #7884. + module_path = os.path.realpath(os.path.join(MEIPASS, entry.replace(".", os.path.sep))) + + # If the module is not in the requested path, skip it. + if not module_path.startswith(pkg_path): + continue + + name = module_path[len(pkg_path):] + + if os.path.sep in name: + # Not a direct child + continue + is_pkg = importer.is_package(entry) + yield pkgutil.ModuleInfo(importer, prefix + name, is_pkg) + + pkgutil.iter_modules = _pyi_pkgutil_iter_modules + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyqt5.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyqt5.py new file mode 100755 index 000000000..be659e837 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyqt5.py @@ -0,0 +1,33 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +# The path to Qt's components may not default to the wheel layout for self-compiled PyQt5 installations. Mandate the +# wheel layout. See ``utils/hooks/qt.py`` for more details. + + +def _pyi_rthook(): + import os + import sys + + # Try PyQt5 5.15.4-style path first... + pyqt_path = os.path.join(sys._MEIPASS, 'PyQt5', 'Qt5') + if not os.path.isdir(pyqt_path): + # ... and fall back to the older version + pyqt_path = os.path.join(sys._MEIPASS, 'PyQt5', 'Qt') + os.environ['QT_PLUGIN_PATH'] = os.path.join(pyqt_path, 'plugins') + os.environ['QML2_IMPORT_PATH'] = os.path.join(pyqt_path, 'qml') + # This is required starting in PyQt5 5.12.3. See discussion in #4293. + if sys.platform.startswith('win') and 'PATH' in os.environ: + os.environ['PATH'] = sys._MEIPASS + os.pathsep + os.environ['PATH'] + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyqt5webengine.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyqt5webengine.py new file mode 100755 index 000000000..ed979fa1e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyqt5webengine.py @@ -0,0 +1,41 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2015-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + + +def _pyi_rthook(): + import os + import sys + + # Special handling is needed only on macOS. + if sys.platform != 'darwin': + return + + # See ``pyi_rth_qt5.py`: use a "standard" PyQt5 layout. + # Try PyQt5 5.15.4-style path first... + pyqt_path = os.path.join(sys._MEIPASS, 'PyQt5', 'Qt5') + if not os.path.isdir(pyqt_path): + # ... and fall back to the older version + pyqt_path = os.path.join(sys._MEIPASS, 'PyQt5', 'Qt') + + # If QtWebEngineProcess was collected from a framework-based Qt build, we need to set QTWEBENGINEPROCESS_PATH. + # If not (a dylib-based build; Anaconda on macOS), it should be found automatically, same as on other OSes. + process_path = os.path.normpath( + os.path.join( + pyqt_path, 'lib', 'QtWebEngineCore.framework', 'Helpers', 'QtWebEngineProcess.app', 'Contents', 'MacOS', + 'QtWebEngineProcess' + ) + ) + if os.path.exists(process_path): + os.environ['QTWEBENGINEPROCESS_PATH'] = process_path + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyqt6.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyqt6.py new file mode 100755 index 000000000..d721f4033 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyqt6.py @@ -0,0 +1,34 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +# The path to Qt's components may not default to the wheel layout for self-compiled PyQt6 installations. Mandate the +# wheel layout. See ``utils/hooks/qt.py`` for more details. + + +def _pyi_rthook(): + import os + import sys + + # Try PyQt6 6.0.3-style path first... + pyqt_path = os.path.join(sys._MEIPASS, 'PyQt6', 'Qt6') + if not os.path.isdir(pyqt_path): + # ... and fall back to the older version. + pyqt_path = os.path.join(sys._MEIPASS, 'PyQt6', 'Qt') + os.environ['QT_PLUGIN_PATH'] = os.path.join(pyqt_path, 'plugins') + os.environ['QML2_IMPORT_PATH'] = os.path.join(pyqt_path, 'qml') + # Modelled after similar PATH modification in PyQt5 rthook. With PyQt6, this modification seems necessary for SSL + # DLLs to be found in onefile builds. + if sys.platform.startswith('win') and 'PATH' in os.environ: + os.environ['PATH'] = sys._MEIPASS + os.pathsep + os.environ['PATH'] + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyqt6webengine.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyqt6webengine.py new file mode 100755 index 000000000..fbf4b4bac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyqt6webengine.py @@ -0,0 +1,45 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2015-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + + +def _pyi_rthook(): + import os + import sys + + # Special handling is needed only on macOS. + if sys.platform != 'darwin': + return + + # See ``pyi_rth_qt6.py`: use a "standard" PyQt6 layout. + + # NOTE: QtWebEngine support was added in Qt6 6.2.x series, so we do not need to worry about pre-6.0.3 path layout. + pyqt_path = os.path.join(sys._MEIPASS, 'PyQt6', 'Qt6') + + # If QtWebEngineProcess was collected from a framework-based Qt build, we need to set QTWEBENGINEPROCESS_PATH. + # If not (a dylib-based build; Anaconda on macOS), it should be found automatically, same as on other OSes. + process_path = os.path.normpath( + os.path.join( + pyqt_path, 'lib', 'QtWebEngineCore.framework', 'Helpers', 'QtWebEngineProcess.app', 'Contents', 'MacOS', + 'QtWebEngineProcess' + ) + ) + if os.path.exists(process_path): + os.environ['QTWEBENGINEPROCESS_PATH'] = process_path + + # As of Qt 6.3.1, we need to disable sandboxing to make QtWebEngineProcess to work at all with the way + # PyInstaller currently collects libraries from Qt .framework bundles. + # This runtime hook should avoid importing PyQt6, so we have no way of querying the version, and always disable + # sandboxing. + os.environ['QTWEBENGINE_DISABLE_SANDBOX'] = '1' + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyside2.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyside2.py new file mode 100755 index 000000000..359e91e76 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyside2.py @@ -0,0 +1,33 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +# The path to Qt's components may not default to the wheel layout for self-compiled PySide2 installations. Mandate the +# wheel layout. See ``utils/hooks/qt.py`` for more details. + + +def _pyi_rthook(): + import os + import sys + + if sys.platform.startswith('win'): + pyqt_path = os.path.join(sys._MEIPASS, 'PySide2') + else: + pyqt_path = os.path.join(sys._MEIPASS, 'PySide2', 'Qt') + os.environ['QT_PLUGIN_PATH'] = os.path.join(pyqt_path, 'plugins') + os.environ['QML2_IMPORT_PATH'] = os.path.join(pyqt_path, 'qml') + # Modelled after similar PATH modification in PyQt5 rthook. With PySide2, this modification seems necessary for SSL + # DLLs to be found in onefile builds (provided they were available during collection). + if sys.platform.startswith('win') and 'PATH' in os.environ: + os.environ['PATH'] = sys._MEIPASS + os.pathsep + os.environ['PATH'] + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyside2webengine.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyside2webengine.py new file mode 100755 index 000000000..8c53fe29d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyside2webengine.py @@ -0,0 +1,34 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2015-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + + +def _pyi_rthook(): + import os + import sys + + # Special handling is needed only on macOS. + if sys.platform != 'darwin': + return + + # If QtWebEngineProcess was collected from a framework-based Qt build, we need to set QTWEBENGINEPROCESS_PATH. + # If not (a dylib-based build; Anaconda on macOS), it should be found automatically, same as on other OSes. + process_path = os.path.normpath( + os.path.join( + sys._MEIPASS, 'PySide2', 'Qt', 'lib', 'QtWebEngineCore.framework', 'Helpers', 'QtWebEngineProcess.app', + 'Contents', 'MacOS', 'QtWebEngineProcess' + ) + ) + if os.path.exists(process_path): + os.environ['QTWEBENGINEPROCESS_PATH'] = process_path + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyside6.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyside6.py new file mode 100755 index 000000000..1f49c09f1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyside6.py @@ -0,0 +1,33 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +# The path to Qt's components may not default to the wheel layout for self-compiled PySide6 installations. Mandate the +# wheel layout. See ``utils/hooks/qt.py`` for more details. + + +def _pyi_rthook(): + import os + import sys + + if sys.platform.startswith('win'): + pyqt_path = os.path.join(sys._MEIPASS, 'PySide6') + else: + pyqt_path = os.path.join(sys._MEIPASS, 'PySide6', 'Qt') + os.environ['QT_PLUGIN_PATH'] = os.path.join(pyqt_path, 'plugins') + os.environ['QML2_IMPORT_PATH'] = os.path.join(pyqt_path, 'qml') + # Modelled after similar PATH modification in PyQt5 rthook. With PySide6, this modification seems necessary for SSL + # DLLs to be found in onefile builds (provided they were available during collection). + if sys.platform.startswith('win') and 'PATH' in os.environ: + os.environ['PATH'] = sys._MEIPASS + os.pathsep + os.environ['PATH'] + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyside6webengine.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyside6webengine.py new file mode 100755 index 000000000..c61f36bd7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_pyside6webengine.py @@ -0,0 +1,39 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2015-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + + +def _pyi_rthook(): + import os + import sys + + if sys.platform != 'darwin': + return + + # If QtWebEngineProcess was collected from a framework-based Qt build, we need to set QTWEBENGINEPROCESS_PATH. + # If not (a dylib-based build; Anaconda on macOS), it should be found automatically, same as on other OSes. + process_path = os.path.normpath( + os.path.join( + sys._MEIPASS, 'PySide6', 'Qt', 'lib', 'QtWebEngineCore.framework', 'Helpers', 'QtWebEngineProcess.app', + 'Contents', 'MacOS', 'QtWebEngineProcess' + ) + ) + if os.path.exists(process_path): + os.environ['QTWEBENGINEPROCESS_PATH'] = process_path + + # As of Qt 6.3.1, we need to disable sandboxing to make QtWebEngineProcess to work at all with the way + # PyInstaller currently collects libraries from Qt .framework bundles. + # This runtime hook should avoid importing PySide6, so we have no way of querying the version, and always + # disable sandboxing. + os.environ['QTWEBENGINE_DISABLE_SANDBOX'] = '1' + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_setuptools.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_setuptools.py new file mode 100755 index 000000000..0a3ffb82d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_setuptools.py @@ -0,0 +1,37 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2022-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +# This runtime hook performs the equivalent of the distutils-precedence.pth from the setuptools package; +# it registers a special meta finder that diverts import of distutils to setuptools._distutils, if available. + + +def _pyi_rthook(): + def _install_setuptools_distutils_hack(): + import os + import setuptools + + # We need to query setuptools version at runtime, because the default value for SETUPTOOLS_USE_DISTUTILS + # has changed at version 60.0 from "stdlib" to "local", and we want to mimic that behavior. + setuptools_major = int(setuptools.__version__.split('.')[0]) + default_value = "stdlib" if setuptools_major < 60 else "local" + + if os.environ.get("SETUPTOOLS_USE_DISTUTILS", default_value) == "local": + import _distutils_hack + _distutils_hack.add_shim() + + try: + _install_setuptools_distutils_hack() + except Exception: + pass + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_win32comgenpy.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_win32comgenpy.py new file mode 100755 index 000000000..a9bbbd1a1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/hooks/rthooks/pyi_rth_win32comgenpy.py @@ -0,0 +1,47 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +# Put the cache generated by `win32com.client.gencache` into isolated temporary directory. Historically, this was +# required due to earlier versions of `pywin32` using the `site-packages\win32com\client\gen_py` directory for +# the cache by default. Nowadays, the default location for the cache seems to be in the configured temporary directory +# (pointed to by TEMP or TMP, for example %LOCALAPPDATA%\Temp), so strictly speaking, the relocation is not necessary +# anymore. But for the time being, we are keeping it around to isolate the frozen application from the rest of the +# system. + + +def _pyi_rthook(): + import atexit + import os + import shutil + + import win32com + + import _pyi_rth_utils # PyInstaller's run-time hook utilities module + + # Create temporary directory. + # Use our replacement for `tempfile.mkdtemp` function that properly restricts access to directory on all platforms. + supportdir = _pyi_rth_utils.secure_mkdtemp() + # The actual cache directory needs to be named `gen_py`, so create a sub-directory. + genpydir = os.path.join(supportdir, 'gen_py') + os.makedirs(genpydir, exist_ok=True) + + # Remove the teporary directory at application exit, ignoring errors. + atexit.register(shutil.rmtree, supportdir, ignore_errors=True) + + # Override the default path to gen_py cache. + win32com.__gen_path__ = genpydir + + # Override the sub-module paths for win32com.gen_py run-time sub-package. + win32com.gen_py.__path__ = [genpydir] + + +_pyi_rthook() +del _pyi_rthook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/isolated/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/isolated/__init__.py new file mode 100755 index 000000000..eba796080 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/isolated/__init__.py @@ -0,0 +1,31 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) or, at the user's discretion, the MIT License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception OR MIT) +# ----------------------------------------------------------------------------- +""" +PyInstaller hooks typically will need to import the package which they are written for but doing so may manipulate +globals such as :data:`sys.path` or :data:`os.environ` in ways that affect the build. For example, on Windows, +Qt's binaries are added to then loaded via ``PATH`` in such a way that if you import multiple Qt variants in one +session then there is no guarantee which variant's binaries each variant will get! + +To get around this, PyInstaller does any such tasks in an isolated Python subprocess and ships a +:mod:`PyInstaller.isolated` submodule to do so in hooks. :: + + from PyInstaller import isolated + +This submodule provides: + +* :func:`isolated.call() ` to evaluate functions in isolation. +* :func:`@isolated.decorate ` to mark a function as always called in isolation. +* :class:`isolated.Python() ` to efficiently call many functions in a single child instance of Python. + +""" + +# ruff: noqa +from ._parent import Python, call, decorate diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/isolated/_child.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/isolated/_child.py new file mode 100755 index 000000000..1411097a7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/isolated/_child.py @@ -0,0 +1,97 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) or, at the user's discretion, the MIT License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception OR MIT) +# ----------------------------------------------------------------------------- +""" +The child process to be invoked by IsolatedPython(). + +This file is to be run directly with pipe handles for reading from and writing to the parent process as command line +arguments. + +""" + +import sys +import os +import types +from marshal import loads, dumps +from base64 import b64encode, b64decode +from traceback import format_exception + +if os.name == "nt": + from msvcrt import open_osfhandle + + def _open(osf_handle, mode): + # Convert system file handles to file descriptors before opening them. + return open(open_osfhandle(osf_handle, 0), mode) +else: + _open = open + + +def run_next_command(read_fh, write_fh): + """ + Listen to **read_fh** for the next function to run. Write the result to **write_fh**. + """ + + # Check the first line of input. Receiving an empty line is the signal that there are no more tasks to be ran. + first_line = read_fh.readline() + if first_line == b"\n": + # It's time to end this child process + return False + + # There are 5 lines to read: The function's code, its default args, its default kwargs, its args, and its kwargs. + code = loads(b64decode(first_line.strip())) + _defaults = loads(b64decode(read_fh.readline().strip())) + _kwdefaults = loads(b64decode(read_fh.readline().strip())) + args = loads(b64decode(read_fh.readline().strip())) + kwargs = loads(b64decode(read_fh.readline().strip())) + + try: + # Define the global namespace available to the function. + GLOBALS = {"__builtins__": __builtins__, "__isolated__": True} + # Reconstruct the function. + function = types.FunctionType(code, GLOBALS) + function.__defaults__ = _defaults + function.__kwdefaults__ = _kwdefaults + + # Run it. + output = function(*args, **kwargs) + + # Verify that the output is serialise-able (i.e. no custom types or module or function references) here so that + # it's caught if it fails. + marshalled = dumps((True, output)) + + except BaseException as ex: + # An exception happened whilst either running the function or serialising its output. Send back a string + # version of the traceback (unfortunately raw traceback objects are not marshal-able) and a boolean to say + # that it failed. + tb_lines = format_exception(type(ex), ex, ex.__traceback__) + if tb_lines[0] == "Traceback (most recent call last):\n": + # This particular line is distracting. Get rid of it. + tb_lines = tb_lines[1:] + marshalled = dumps((False, "".join(tb_lines).rstrip())) + + # Send the output (return value or traceback) back to the parent. + write_fh.write(b64encode(marshalled)) + write_fh.write(b"\n") + write_fh.flush() + + # Signal that an instruction was ran (successfully or otherwise). + return True + + +if __name__ == '__main__': + read_from_parent, write_to_parent = map(int, sys.argv[1:]) + + with _open(read_from_parent, "rb") as read_fh: + with _open(write_to_parent, "wb") as write_fh: + sys.path = loads(b64decode(read_fh.readline())) + + # Keep receiving and running instructions until the parent sends the signal to stop. + while run_next_command(read_fh, write_fh): + pass diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/isolated/_parent.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/isolated/_parent.py new file mode 100755 index 000000000..882151a8b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/isolated/_parent.py @@ -0,0 +1,405 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2021-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) or, at the user's discretion, the MIT License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception OR MIT) +# ----------------------------------------------------------------------------- + +import os +from pathlib import Path +from marshal import loads, dumps +from base64 import b64encode, b64decode +import functools +import subprocess +import sys + +from PyInstaller import compat +from PyInstaller import log as logging + +logger = logging.getLogger(__name__) + +# WinAPI bindings for Windows-specific codepath +if os.name == "nt": + import msvcrt + import ctypes + import ctypes.wintypes + + # CreatePipe + class SECURITY_ATTRIBUTES(ctypes.Structure): + _fields_ = [ + ("nLength", ctypes.wintypes.DWORD), + ("lpSecurityDescriptor", ctypes.wintypes.LPVOID), + ("bInheritHandle", ctypes.wintypes.BOOL), + ] + + HANDLE_FLAG_INHERIT = 0x0001 + + LPSECURITY_ATTRIBUTES = ctypes.POINTER(SECURITY_ATTRIBUTES) + + CreatePipe = ctypes.windll.kernel32.CreatePipe + CreatePipe.argtypes = [ + ctypes.POINTER(ctypes.wintypes.HANDLE), + ctypes.POINTER(ctypes.wintypes.HANDLE), + LPSECURITY_ATTRIBUTES, + ctypes.wintypes.DWORD, + ] + CreatePipe.restype = ctypes.wintypes.BOOL + + # CloseHandle + CloseHandle = ctypes.windll.kernel32.CloseHandle + CloseHandle.argtypes = [ctypes.wintypes.HANDLE] + CloseHandle.restype = ctypes.wintypes.BOOL + +CHILD_PY = Path(__file__).with_name("_child.py") + + +def create_pipe(read_handle_inheritable, write_handle_inheritable): + """ + Create a one-way pipe for sending data to child processes. + + Args: + read_handle_inheritable: + A boolean flag indicating whether the handle corresponding to the read end-point of the pipe should be + marked as inheritable by subprocesses. + write_handle_inheritable: + A boolean flag indicating whether the handle corresponding to the write end-point of the pipe should be + marked as inheritable by subprocesses. + + Returns: + A read/write pair of file descriptors (which are just integers) on posix or system file handles on Windows. + + The pipe may be used either by this process or subprocesses of this process but not globally. + """ + return _create_pipe_impl(read_handle_inheritable, write_handle_inheritable) + + +def close_pipe_endpoint(pipe_handle): + """ + Close the file descriptor (posix) or handle (Windows) belonging to a pipe. + """ + return _close_pipe_endpoint_impl(pipe_handle) + + +if os.name == "nt": + + def _create_pipe_impl(read_handle_inheritable, write_handle_inheritable): + # Use WinAPI CreatePipe function to create the pipe. Python's os.pipe() does the same, but wraps the resulting + # handles into inheritable file descriptors (https://github.com/python/cpython/issues/77046). Instead, we want + # just handles, and will set the inheritable flag on corresponding handle ourselves. + read_handle = ctypes.wintypes.HANDLE() + write_handle = ctypes.wintypes.HANDLE() + + # SECURITY_ATTRIBUTES with inherit handle set to True + security_attributes = SECURITY_ATTRIBUTES() + security_attributes.nLength = ctypes.sizeof(security_attributes) + security_attributes.bInheritHandle = True + security_attributes.lpSecurityDescriptor = None + + # CreatePipe() + succeeded = CreatePipe( + ctypes.byref(read_handle), # hReadPipe + ctypes.byref(write_handle), # hWritePipe + ctypes.byref(security_attributes), # lpPipeAttributes + 0, # nSize + ) + if not succeeded: + raise ctypes.WinError() + + # Set inheritable flags. Instead of binding and using SetHandleInformation WinAPI function, we can use + # os.set_handle_inheritable(). + os.set_handle_inheritable(read_handle.value, read_handle_inheritable) + os.set_handle_inheritable(write_handle.value, write_handle_inheritable) + + return read_handle.value, write_handle.value + + def _close_pipe_endpoint_impl(pipe_handle): + succeeded = CloseHandle(pipe_handle) + if not succeeded: + raise ctypes.WinError() +else: + + def _create_pipe_impl(read_fd_inheritable, write_fd_inheritable): + # Create pipe, using os.pipe() + read_fd, write_fd = os.pipe() + + # The default behaviour of pipes is that they are process specific. I.e., they can only be used by this + # process to talk to itself. Setting inheritable flags means that child processes may also use these pipes. + os.set_inheritable(read_fd, read_fd_inheritable) + os.set_inheritable(write_fd, write_fd_inheritable) + + return read_fd, write_fd + + def _close_pipe_endpoint_impl(pipe_fd): + os.close(pipe_fd) + + +def child(read_from_parent: int, write_to_parent: int): + """ + Spawn a Python subprocess sending it the two file descriptors it needs to talk back to this parent process. + """ + if os.name != 'nt': + # Explicitly disabling close_fds is a requirement for making file descriptors inheritable by child processes. + extra_kwargs = { + "env": _subprocess_env(), + "close_fds": False, + } + else: + # On Windows, we can use subprocess.STARTUPINFO to explicitly pass the list of file handles to be inherited, + # so we can avoid disabling close_fds + extra_kwargs = { + "env": _subprocess_env(), + "close_fds": True, + "startupinfo": subprocess.STARTUPINFO(lpAttributeList={"handle_list": [read_from_parent, write_to_parent]}) + } + + # Run the _child.py script directly passing it the two file descriptors it needs to talk back to the parent. + cmd, options = compat.__wrap_python([str(CHILD_PY), str(read_from_parent), str(write_to_parent)], extra_kwargs) + + # I'm intentionally leaving stdout and stderr alone so that print() can still be used for emergency debugging and + # unhandled errors in the child are still visible. + return subprocess.Popen(cmd, **options) + + +def _subprocess_env(): + """ + Define the environment variables to be readable in a child process. + """ + from PyInstaller.config import CONF + python_path = CONF["pathex"] + if "PYTHONPATH" in os.environ: + python_path = python_path + [os.environ["PYTHONPATH"]] + env = os.environ.copy() + env["PYTHONPATH"] = os.pathsep.join(python_path) + return env + + +class Python: + """ + Start and connect to a separate Python subprocess. + + This is the lowest level of public API provided by this module. The advantage of using this class directly is + that it allows multiple functions to be evaluated in a single subprocess, making it faster than multiple calls to + :func:`call`. + + The ``strict_mode`` argument controls behavior when the child process fails to shut down; if strict mode is enabled, + an error is raised, otherwise only warning is logged. If the value of ``strict_mode`` is ``None``, the value of + ``PyInstaller.compat.strict_collect_mode`` is used (which in turn is controlled by the + ``PYINSTALLER_STRICT_COLLECT_MODE`` environment variable. + + Examples: + To call some predefined functions ``x = foo()``, ``y = bar("numpy")`` and ``z = bazz(some_flag=True)`` all using + the same isolated subprocess use:: + + with isolated.Python() as child: + x = child.call(foo) + y = child.call(bar, "numpy") + z = child.call(bazz, some_flag=True) + + """ + def __init__(self, strict_mode=None): + self._child = None + + # Re-use the compat.strict_collect_mode and its PYINSTALLER_STRICT_COLLECT_MODE environment variable for + # default strict-mode setting. + self._strict_mode = strict_mode if strict_mode is not None else compat.strict_collect_mode + + def __enter__(self): + # We need two pipes. One for the child to send data to the parent. The (write) end-point passed to the + # child needs to be marked as inheritable. + read_from_child, write_to_parent = create_pipe(False, True) + # And one for the parent to send data to the child. The (read) end-point passed to the child needs to be + # marked as inheritable. + read_from_parent, write_to_child = create_pipe(True, False) + + # Spawn a Python subprocess sending it the two file descriptors it needs to talk back to this parent process. + self._child = child(read_from_parent, write_to_parent) + + # Close the end-points that were inherited by the child. + close_pipe_endpoint(read_from_parent) + close_pipe_endpoint(write_to_parent) + del read_from_parent + del write_to_parent + + # Open file handles to talk to the child. This should fully transfer ownership of the underlying file + # descriptor to the opened handle; so when we close the latter, the former should be closed as well. + if os.name == 'nt': + # On Windows, we must first open file descriptor on top of the handle using _open_osfhandle (which + # python wraps in msvcrt.open_osfhandle). According to MSDN, this transfers the ownership of the + # underlying file handle to the file descriptors; i.e., they are both closed when the file descriptor + # is closed). + self._write_handle = os.fdopen(msvcrt.open_osfhandle(write_to_child, 0), "wb") + self._read_handle = os.fdopen(msvcrt.open_osfhandle(read_from_child, 0), "rb") + else: + self._write_handle = os.fdopen(write_to_child, "wb") + self._read_handle = os.fdopen(read_from_child, "rb") + + self._send(sys.path) + + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + # Send the signal (a blank line) to the child to tell it that it's time to stop. + self._write_handle.write(b"\n") + self._write_handle.flush() + + # Wait for the child process to exit. The timeout is necessary for corner cases when the sub-process fails to + # exit (such as due to dangling non-daemon threads; see #7290). At this point, the subprocess already did all + # its work, so it should be safe to terminate. And as we expect it to shut down quickly (or not at all), the + # timeout is relatively short. + # + # In strict build mode, we raise an error when the subprocess fails to exit on its own, but do so only after + # we attempt to kill the subprocess, to avoid leaving zombie processes. + shutdown_error = False + + try: + self._child.wait(timeout=5) + except subprocess.TimeoutExpired: + logger.warning("Timed out while waiting for the child process to exit!") + shutdown_error = True + self._child.kill() + try: + self._child.wait(timeout=15) + except subprocess.TimeoutExpired: + logger.warning("Timed out while waiting for the child process to be killed!") + # Give up and fall through + + # Close the handles. This should also close the underlying file descriptors. + self._write_handle.close() + self._read_handle.close() + del self._read_handle, self._write_handle + + self._child = None + + # Raise an error in strict mode, after all clean-up has been performed. + if shutdown_error and self._strict_mode: + raise RuntimeError("Timed out while waiting for the child process to exit!") + + def call(self, function, *args, **kwargs): + """ + Call a function in the child Python. Retrieve its return value. Usage of this method is identical to that + of the :func:`call` function. + """ + if self._child is None: + raise RuntimeError("An isolated.Python object must be used in a 'with' clause.") + + self._send(function.__code__, function.__defaults__, function.__kwdefaults__, args, kwargs) + + # Read a single line of output back from the child. This contains if the function worked and either its return + # value or a traceback. This will block indefinitely until it receives a '\n' byte. + ok, output = loads(b64decode(self._read_handle.readline())) + + # If all went well, then ``output`` is the return value. + if ok: + return output + + # Otherwise an error happened and ``output`` is a string-ified stacktrace. Raise an error appending the + # stacktrace. Having the output in this order gives a nice fluent transition from parent to child in the stack + # trace. + raise RuntimeError(f"Child process call to {function.__name__}() failed with:\n" + output) + + def _send(self, *objects): + for object in objects: + self._write_handle.write(b64encode(dumps(object))) + self._write_handle.write(b"\n") + # Flushing is very important. Without it, the data is not sent but forever sits in a buffer so that the child is + # forever waiting for its data and the parent in turn is forever waiting for the child's response. + self._write_handle.flush() + + +def call(function, *args, **kwargs): + r""" + Call a function with arguments in a separate child Python. Retrieve its return value. + + Args: + function: + The function to send and invoke. + *args: + **kwargs: + Positional and keyword arguments to send to the function. These must be simple builtin types - not custom + classes. + Returns: + The return value of the function. Again, these must be basic types serialisable by :func:`marshal.dumps`. + Raises: + RuntimeError: + Any exception which happens inside an isolated process is caught and reraised in the parent process. + + To use, define a function which returns the information you're looking for. Any imports it requires must happen in + the body of the function. For example, to safely check the output of ``matplotlib.get_data_path()`` use:: + + # Define a function to be ran in isolation. + def get_matplotlib_data_path(): + import matplotlib + return matplotlib.get_data_path() + + # Call it with isolated.call(). + get_matplotlib_data_path = isolated.call(matplotlib_data_path) + + For single use functions taking no arguments like the above you can abuse the decorator syntax slightly to define + and execute a function in one go. :: + + >>> @isolated.call + ... def matplotlib_data_dir(): + ... import matplotlib + ... return matplotlib.get_data_path() + >>> matplotlib_data_dir + '/home/brenainn/.pyenv/versions/3.9.6/lib/python3.9/site-packages/matplotlib/mpl-data' + + Functions may take positional and keyword arguments and return most generic Python data types. :: + + >>> def echo_parameters(*args, **kwargs): + ... return args, kwargs + >>> isolated.call(echo_parameters, 1, 2, 3) + (1, 2, 3), {} + >>> isolated.call(echo_parameters, foo=["bar"]) + (), {'foo': ['bar']} + + Notes: + To make a function behave differently if it's isolated, check for the ``__isolated__`` global. :: + + if globals().get("__isolated__", False): + # We're inside a child process. + ... + else: + # This is the master process. + ... + + """ + with Python() as isolated: + return isolated.call(function, *args, **kwargs) + + +def decorate(function): + """ + Decorate a function so that it is always called in an isolated subprocess. + + Examples: + + To use, write a function then prepend ``@isolated.decorate``. :: + + @isolated.decorate + def add_1(x): + '''Add 1 to ``x``, displaying the current process ID.''' + import os + print(f"Process {os.getpid()}: Adding 1 to {x}.") + return x + 1 + + The resultant ``add_1()`` function can now be called as you would a + normal function and it'll automatically use a subprocess. + + >>> add_1(4) + Process 4920: Adding 1 to 4. + 5 + >>> add_1(13.2) + Process 4928: Adding 1 to 13.2. + 14.2 + + """ + @functools.wraps(function) + def wrapped(*args, **kwargs): + return call(function, *args, **kwargs) + + return wrapped diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/README.rst b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/README.rst new file mode 100755 index 000000000..a09f6d501 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/README.rst @@ -0,0 +1,49 @@ +Custom modifications of 3rd party libraries +=========================================== + +NOTE: PyInstaller does not extend PYTHONPATH (sys.path) with this directory +that contains bundled 3rd party libraries. + +Some users complained that PyInstaller failed because their apps were using +too old versions of some libraries that PyInstaller uses too and that's why +extending sys.path was dropped. + +All libraries are tweaked to be importable as:: + + from PyInstaller.lib.LIB_NAME import xyz + +In libraries replace imports like:: + + from altgraph import y + from modulegraph import z + +with relative prefix:: + + from ..altgraph import y + from ..modulegraph import z + + +altgraph +---------- + +- add fixed version string to ./altgraph/__init__.py:: + + # For PyInstaller/lib/ define the version here, since there is no + # package-resource. + __version__ = '0.13' + + +modulegraph +----------- + +https://bitbucket.org/ronaldoussoren/modulegraph/downloads + +- TODO Use official modulegraph version when following issue is resolved and pull request merged + https://bitbucket.org/ronaldoussoren/modulegraph/issues/28/__main__-module-being-analyzed-for-wheel + +- add fixed version string to ./modulegraph/__init__.py:: + + # For PyInstaller/lib/ define the version here, since there is no + # package-resource. + __version__ = '0.13' + diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/__init__.py new file mode 100755 index 000000000..792d60054 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/__init__.py @@ -0,0 +1 @@ +# diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/__init__.py new file mode 100755 index 000000000..94461691c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/__init__.py @@ -0,0 +1 @@ +__version__ = '0.17' diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/__main__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/__main__.py new file mode 100755 index 000000000..ea4670b0e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/__main__.py @@ -0,0 +1,89 @@ +import sys +import os +import argparse +from .modulegraph import ModuleGraph + + +def parse_arguments(): + parser = argparse.ArgumentParser( + conflict_handler='resolve', prog='%s -mmodulegraph' % ( + os.path.basename(sys.executable))) + parser.add_argument( + '-d', action='count', dest='debug', default=1, + help='Increase debug level') + parser.add_argument( + '-q', action='store_const', dest='debug', const=0, + help='Clear debug level') + parser.add_argument( + '-m', '--modules', action='store_true', + dest='domods', default=False, + help='arguments are module names, not script files') + parser.add_argument( + '-x', metavar='NAME', action='append', dest='excludes', + default=[], help='Add NAME to the excludes list') + parser.add_argument( + '-p', action='append', metavar='PATH', dest='addpath', default=[], + help='Add PATH to the module search path') + parser.add_argument( + '-g', '--dot', action='store_const', dest='output', const='dot', + help='Output a .dot graph') + parser.add_argument( + '-h', '--html', action='store_const', + dest='output', const='html', help='Output a HTML file') + parser.add_argument( + 'scripts', metavar='SCRIPT', nargs='+', help='scripts to analyse') + + opts = parser.parse_args() + return opts + + +def create_graph(scripts, domods, debuglevel, excludes, path_extras): + # Set the path based on sys.path and the script directory + path = sys.path[:] + + if domods: + del path[0] + else: + path[0] = os.path.dirname(scripts[0]) + + path = path_extras + path + if debuglevel > 1: + print("path:", file=sys.stderr) + for item in path: + print(" ", repr(item), file=sys.stderr) + + # Create the module finder and turn its crank + mf = ModuleGraph(path, excludes=excludes, debug=debuglevel) + for arg in scripts: + if domods: + if arg[-2:] == '.*': + mf.import_hook(arg[:-2], None, ["*"]) + else: + mf.import_hook(arg) + else: + mf.add_script(arg) + return mf + + +def output_graph(output_format, mf): + if output_format == 'dot': + mf.graphreport() + elif output_format == 'html': + mf.create_xref() + else: + mf.report() + + +def main(): + opts = parse_arguments() + mf = create_graph( + opts.scripts, opts.domods, opts.debug, + opts.excludes, opts.addpath) + output_graph(opts.output, mf) + + +if __name__ == '__main__': # pragma: no cover + try: + main() + except KeyboardInterrupt: + print("\n[interrupt]") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/_compat.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/_compat.py new file mode 100755 index 000000000..68fa92364 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/_compat.py @@ -0,0 +1,25 @@ +import sys + +if sys.version_info[0] == 2: + PY2 = True + + from StringIO import StringIO + BytesIO = StringIO + from urllib import pathname2url + _cOrd = ord + + # File open mode for reading (univeral newlines) + _READ_MODE = "rU" + +else: + PY2 = False + + from urllib.request import pathname2url + from io import BytesIO, StringIO + _cOrd = int + _READ_MODE = "r" + +if sys.version_info < (3,): + from dis3 import get_instructions +else: + from dis import get_instructions diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/find_modules.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/find_modules.py new file mode 100755 index 000000000..14f7fb5dc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/find_modules.py @@ -0,0 +1,114 @@ +""" +modulegraph.find_modules - High-level module dependency finding interface +========================================================================= + +History +........ + +Originally (loosely) based on code in py2exe's build_exe.py by Thomas Heller. +""" +import sys +import os +import pkgutil + +from . import modulegraph +from .modulegraph import Alias + +_PLATFORM_MODULES = {'posix', 'nt', 'os2', 'mac', 'ce', 'riscos'} + + +def get_implies(): + result = { + # imports done from builtin modules in C code + # (untrackable by modulegraph) + "_curses": ["curses"], + "posix": ["resource"], + "gc": ["time"], + "time": ["_strptime"], + "datetime": ["time"], + "MacOS": ["macresource"], + "cPickle": ["copy_reg", "cStringIO"], + "parser": ["copy_reg"], + "codecs": ["encodings"], + "cStringIO": ["copy_reg"], + "_sre": ["copy", "string", "sre"], + "zipimport": ["zlib"], + + # Python 3.2: + "_datetime": ["time", "_strptime"], + "_json": ["json.decoder"], + "_pickle": ["codecs", "copyreg", "_compat_pickle"], + "_posixsubprocess": ["gc"], + "_ssl": ["socket"], + + # Python 3.3: + "_elementtree": ["copy", "xml.etree.ElementPath"], + + # mactoolboxglue can do a bunch more of these + # that are far harder to predict, these should be tracked + # manually for now. + + # this isn't C, but it uses __import__ + "anydbm": ["dbhash", "gdbm", "dbm", "dumbdbm", "whichdb"], + # package aliases + "wxPython.wx": Alias('wx'), + + } + + if sys.version_info[0] == 3: + result["_sre"] = ["copy", "re"] + result["parser"] = ["copyreg"] + + # _frozen_importlib is part of the interpreter itself + result["_frozen_importlib"] = None + + if sys.version_info[0] == 2 and sys.version_info[1] >= 5: + result.update({ + "email.base64MIME": Alias("email.base64mime"), + "email.Charset": Alias("email.charset"), + "email.Encoders": Alias("email.encoders"), + "email.Errors": Alias("email.errors"), + "email.Feedparser": Alias("email.feedParser"), + "email.Generator": Alias("email.generator"), + "email.Header": Alias("email.header"), + "email.Iterators": Alias("email.iterators"), + "email.Message": Alias("email.message"), + "email.Parser": Alias("email.parser"), + "email.quopriMIME": Alias("email.quoprimime"), + "email.Utils": Alias("email.utils"), + "email.MIMEAudio": Alias("email.mime.audio"), + "email.MIMEBase": Alias("email.mime.base"), + "email.MIMEImage": Alias("email.mime.image"), + "email.MIMEMessage": Alias("email.mime.message"), + "email.MIMEMultipart": Alias("email.mime.multipart"), + "email.MIMENonMultipart": Alias("email.mime.nonmultipart"), + "email.MIMEText": Alias("email.mime.text"), + }) + + if sys.version_info[:2] >= (2, 5): + result["_elementtree"] = ["pyexpat"] + + import xml.etree + for _, module_name, is_package in pkgutil.iter_modules(xml.etree.__path__): + if not is_package: + result["_elementtree"].append("xml.etree.%s" % (module_name,)) + + if sys.version_info[:2] >= (2, 6): + result['future_builtins'] = ['itertools'] + + # os.path is an alias for a platform specific submodule, + # ensure that the graph shows this. + result['os.path'] = Alias(os.path.__name__) + + return result + + +def _replacePackages(): + REPLACEPACKAGES = { + '_xmlplus': 'xml', + } + for k, v in REPLACEPACKAGES.items(): + modulegraph.replacePackage(k, v) + + +_replacePackages() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/modulegraph.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/modulegraph.py new file mode 100755 index 000000000..81829dc38 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/modulegraph.py @@ -0,0 +1,3279 @@ +""" +Find modules used by a script, using bytecode analysis. + +Based on the stdlib modulefinder by Thomas Heller and Just van Rossum, +but uses a graph data structure and 2.3 features + +XXX: Verify all calls to _import_hook (and variants) to ensure that +imports are done in the right way. +""" +#FIXME: To decrease the likelihood of ModuleGraph exceeding the recursion limit +#and hence unpredictably raising fatal exceptions, increase the recursion +#limit at PyInstaller startup (i.e., in the +#PyInstaller.building.build_main.build() function). For details, see: +# https://github.com/pyinstaller/pyinstaller/issues/1919#issuecomment-216016176 + +import pkg_resources + +import ast +import codecs +import marshal +import os +import pkgutil +import sys +import re +from collections import deque, namedtuple +import warnings +import importlib.util +import importlib.machinery + +from altgraph.ObjectGraph import ObjectGraph +from altgraph import GraphError + +from . import util +from . import zipio +from ._compat import BytesIO, pathname2url, _READ_MODE + + +BOM = codecs.BOM_UTF8.decode('utf-8') + + +class BUILTIN_MODULE: + def is_package(fqname): + return False + + +class NAMESPACE_PACKAGE: + def __init__(self, namespace_dirs): + self.namespace_dirs = namespace_dirs + + def is_package(self, fqname): + return True + + +#FIXME: Leverage this rather than magic numbers below. +ABSOLUTE_OR_RELATIVE_IMPORT_LEVEL = -1 +""" +Constant instructing the builtin `__import__()` function to attempt both +absolute and relative imports. +""" + + +#FIXME: Leverage this rather than magic numbers below. +ABSOLUTE_IMPORT_LEVEL = 0 +""" +Constant instructing the builtin `__import__()` function to attempt only +absolute imports. +""" + + +#FIXME: Leverage this rather than magic numbers below. +DEFAULT_IMPORT_LEVEL = ( + ABSOLUTE_OR_RELATIVE_IMPORT_LEVEL if sys.version_info[0] == 2 else + ABSOLUTE_IMPORT_LEVEL) +""" +Constant instructing the builtin `__import__()` function to attempt the default +import style specific to the active Python interpreter. + +Specifically, under: + +* Python 2, this defaults to attempting both absolute and relative imports. +* Python 3, this defaults to attempting only absolute imports. +""" + +# Reverse sort by length so when comparing filenames the longest match first +_IMPORTABLE_FILETYPE_EXTS = sorted(importlib.machinery.all_suffixes(), + key=lambda p: len(p), reverse=True) + +# Modulegraph does a good job at simulating Python's, but it can not +# handle packagepath modifications packages make at runtime. Therefore there +# is a mechanism whereby you can register extra paths in this map for a +# package, and it will be honored. +# +# Note this is a mapping is lists of paths. +_packagePathMap = {} + +# Prefix used in magic .pth files used by setuptools to create namespace +# packages without an __init__.py file. +# +# The value is a list of such prefixes as the prefix varies with versions of +# setuptools. +_SETUPTOOLS_NAMESPACEPKG_PTHs=( + # setuptools 31.0.0 + ("import sys, types, os;has_mfs = sys.version_info > (3, 5);" + "p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('"), + # distribute 0.6.10 + ("import sys,types,os; p = os.path.join(" + "sys._getframe(1).f_locals['sitedir'], *('"), + # setuptools 0.6c9, distribute 0.6.12 + ("import sys,new,os; p = os.path.join(sys._getframe(" + "1).f_locals['sitedir'], *('"), + # setuptools 28.1.0 + ("import sys, types, os;p = os.path.join(" + "sys._getframe(1).f_locals['sitedir'], *('"), + # setuptools 28.7.0 + ("import sys, types, os;pep420 = sys.version_info > (3, 3);" + "p = os.path.join(sys._getframe(1).f_locals['sitedir'], *('"), +) + + +class InvalidRelativeImportError (ImportError): + pass + + +def _namespace_package_path(fqname, pathnames, path=None): + """ + Return the __path__ for the python package in *fqname*. + + This function uses setuptools metadata to extract information + about namespace packages from installed eggs. + """ + working_set = pkg_resources.WorkingSet(path) + + path = list(pathnames) + + for dist in working_set: + if dist.has_metadata('namespace_packages.txt'): + namespaces = dist.get_metadata( + 'namespace_packages.txt').splitlines() + if fqname in namespaces: + nspath = os.path.join(dist.location, *fqname.split('.')) + if nspath not in path: + path.append(nspath) + + return path + +_strs = re.compile(r'''^\s*["']([A-Za-z0-9_]+)["'],?\s*''') # "<- emacs happy + + +def _eval_str_tuple(value): + """ + Input is the repr of a tuple of strings, output + is that tuple. + + This only works with a tuple where the members are + python identifiers. + """ + if not (value.startswith('(') and value.endswith(')')): + raise ValueError(value) + + orig_value = value + value = value[1:-1] + + result = [] + while value: + m = _strs.match(value) + if m is None: + raise ValueError(orig_value) + + result.append(m.group(1)) + value = value[len(m.group(0)):] + + return tuple(result) + + +def _path_from_importerror(exc, default): + # This is a hack, but sadly enough the necessary information + # isn't available otherwise. + m = re.match(r'^No module named (\S+)$', str(exc)) + if m is not None: + return m.group(1) + + return default + + +def os_listdir(path): + """ + Deprecated name + """ + warnings.warn( + "Use zipio.listdir instead of os_listdir", + DeprecationWarning) + return zipio.listdir(path) + + +def _code_to_file(co): + """ Convert code object to a .pyc pseudo-file """ + if sys.version_info >= (3, 7): + header = importlib.util.MAGIC_NUMBER + (b'\0' * 12) + elif sys.version_info >= (3, 4): + header = importlib.util.MAGIC_NUMBER + (b'\0' * 8) + else: + header = importlib.util.MAGIC_NUMBER + (b'\0' * 4) + return BytesIO(header + marshal.dumps(co)) + + +def AddPackagePath(packagename, path): + warnings.warn( + "Use addPackagePath instead of AddPackagePath", + DeprecationWarning) + addPackagePath(packagename, path) + + +def addPackagePath(packagename, path): + paths = _packagePathMap.get(packagename, []) + paths.append(path) + _packagePathMap[packagename] = paths + + +_replacePackageMap = {} + + +# This ReplacePackage mechanism allows modulefinder to work around the +# way the _xmlplus package injects itself under the name "xml" into +# sys.modules at runtime by calling ReplacePackage("_xmlplus", "xml") +# before running ModuleGraph. +def ReplacePackage(oldname, newname): + warnings.warn("use replacePackage instead of ReplacePackage", + DeprecationWarning) + replacePackage(oldname, newname) + + +def replacePackage(oldname, newname): + _replacePackageMap[oldname] = newname + + +#FIXME: What is this? Do we actually need this? This appears to provide +#significantly more fine-grained metadata than PyInstaller will ever require. +#It consumes a great deal of space (slots or no slots), since we store an +#instance of this class for each edge of the graph. +class DependencyInfo (namedtuple("DependencyInfo", + ["conditional", "function", "tryexcept", "fromlist"])): + __slots__ = () + + def _merged(self, other): + if (not self.conditional and not self.function and not self.tryexcept) \ + or (not other.conditional and not other.function and not other.tryexcept): + return DependencyInfo( + conditional=False, + function=False, + tryexcept=False, + fromlist=self.fromlist and other.fromlist) + + else: + return DependencyInfo( + conditional=self.conditional or other.conditional, + function=self.function or other.function, + tryexcept=self.tryexcept or other.tryexcept, + fromlist=self.fromlist and other.fromlist) + + +#FIXME: Shift the following Node class hierarchy into a new +#"PyInstaller.lib.modulegraph.node" module. This module is much too long. +#FIXME: Refactor "_deferred_imports" from a tuple into a proper lightweight +#class leveraging "__slots__". If not for backward compatibility, we'd just +#leverage a named tuple -- but this should do just as well. +#FIXME: Move the "packagepath" attribute into the "Package" class. Only +#packages define the "__path__" special attribute. The codebase currently +#erroneously tests whether "module.packagepath is not None" to determine +#whether a node is a package or not. However, "isinstance(module, Package)" is +#a significantly more reliable test. Refactor the former into the latter. +class Node: + """ + Abstract base class (ABC) of all objects added to a `ModuleGraph`. + + Attributes + ---------- + code : codeobject + Code object of the pure-Python module corresponding to this graph node + if any _or_ `None` otherwise. + graphident : str + Synonym of `identifier` required by the `ObjectGraph` superclass of the + `ModuleGraph` class. For readability, the `identifier` attribute should + typically be used instead. + filename : str + Absolute path of this graph node's corresponding module, package, or C + extension if any _or_ `None` otherwise. + identifier : str + Fully-qualified name of this graph node's corresponding module, + package, or C extension. + packagepath : str + List of the absolute paths of all directories comprising this graph + node's corresponding package. If this is a: + * Non-namespace package, this list contains exactly one path. + * Namespace package, this list contains one or more paths. + _deferred_imports : list + List of all target modules imported by the source module corresponding + to this graph node whole importations have been deferred for subsequent + processing in between calls to the `_ModuleGraph._scan_code()` and + `_ModuleGraph._process_imports()` methods for this source module _or_ + `None` otherwise. Each element of this list is a 3-tuple + `(have_star, _safe_import_hook_args, _safe_import_hook_kwargs)` + collecting the importation of a target module from this source module + for subsequent processing, where: + * `have_star` is a boolean `True` only if this is a `from`-style star + import (e.g., resembling `from {target_module_name} import *`). + * `_safe_import_hook_args` is a (typically non-empty) sequence of all + positional arguments to be passed to the `_safe_import_hook()` method + to add this importation to the graph. + * `_safe_import_hook_kwargs` is a (typically empty) dictionary of all + keyword arguments to be passed to the `_safe_import_hook()` method + to add this importation to the graph. + Unlike functional languages, Python imposes a maximum depth on the + interpreter stack (and hence recursion). On breaching this depth, + Python raises a fatal `RuntimeError` exception. Since `ModuleGraph` + parses imports recursively rather than iteratively, this depth _was_ + commonly breached before the introduction of this list. Python + environments installing a large number of modules (e.g., Anaconda) were + particularly susceptible. Why? Because `ModuleGraph` concurrently + descended through both the abstract syntax trees (ASTs) of all source + modules being parsed _and_ the graph of all target modules imported by + these source modules being built. The stack thus consisted of + alternating layers of AST and graph traversal. To unwind such + alternation and effectively halve the stack depth, `ModuleGraph` now + descends through the abstract syntax tree (AST) of each source module + being parsed and adds all importations originating within this module + to this list _before_ descending into the graph of these importations. + See pyinstaller/pyinstaller/#1289 for further details. + _global_attr_names : set + Set of the unqualified names of all global attributes (e.g., classes, + variables) defined in the pure-Python module corresponding to this + graph node if any _or_ the empty set otherwise. This includes the names + of all attributes imported via `from`-style star imports from other + existing modules (e.g., `from {target_module_name} import *`). This + set is principally used to differentiate the non-ignorable importation + of non-existent submodules in a package from the ignorable importation + of existing global attributes defined in that package's pure-Python + `__init__` submodule in `from`-style imports (e.g., `bar` in + `from foo import bar`, which may be either a submodule or attribute of + `foo`), as such imports ambiguously allow both. This set is _not_ used + to differentiate submodules from attributes in `import`-style imports + (e.g., `bar` in `import foo.bar`, which _must_ be a submodule of + `foo`), as such imports unambiguously allow only submodules. + _starimported_ignored_module_names : set + Set of the fully-qualified names of all existing unparsable modules + that the existing parsable module corresponding to this graph node + attempted to perform one or more "star imports" from. If this module + either does _not_ exist or does but is unparsable, this is the empty + set. Equivalently, this set contains each fully-qualified name + `{trg_module_name}` for which: + * This module contains an import statement of the form + `from {trg_module_name} import *`. + * The module whose name is `{trg_module_name}` exists but is _not_ + parsable by `ModuleGraph` (e.g., due to _not_ being pure-Python). + **This set is currently defined but otherwise ignored.** + _submodule_basename_to_node : dict + Dictionary mapping from the unqualified name of each submodule + contained by the parent module corresponding to this graph node to that + submodule's graph node. If this dictionary is non-empty, this parent + module is typically but _not_ always a package (e.g., the non-package + `os` module containing the `os.path` submodule). + """ + + __slots__ = [ + 'code', + 'filename', + 'graphident', + 'identifier', + 'packagepath', + '_deferred_imports', + '_global_attr_names', + '_starimported_ignored_module_names', + '_submodule_basename_to_node', + ] + + def __init__(self, identifier): + """ + Initialize this graph node. + + Parameters + ---------- + identifier : str + Fully-qualified name of this graph node's corresponding module, + package, or C extension. + """ + + self.code = None + self.filename = None + self.graphident = identifier + self.identifier = identifier + self.packagepath = None + self._deferred_imports = None + self._global_attr_names = set() + self._starimported_ignored_module_names = set() + self._submodule_basename_to_node = dict() + + + def is_global_attr(self, attr_name): + """ + `True` only if the pure-Python module corresponding to this graph node + defines a global attribute (e.g., class, variable) with the passed + name. + + If this module is actually a package, this method instead returns + `True` only if this package's pure-Python `__init__` submodule defines + such a global attribute. In this case, note that this package may still + contain an importable submodule of the same name. Callers should + attempt to import this attribute as a submodule of this package + _before_ assuming this attribute to be an ignorable global. See + "Examples" below for further details. + + Parameters + ---------- + attr_name : str + Unqualified name of the attribute to be tested. + + Returns + ---------- + bool + `True` only if this module defines this global attribute. + + Examples + ---------- + Consider a hypothetical module `foo` containing submodules `bar` and + `__init__` where the latter assigns `bar` to be a global variable + (possibly star-exported via the special `__all__` global variable): + + >>> # In "foo.__init__": + >>> bar = 3.1415 + + Python 2 and 3 both permissively permit this. This method returns + `True` in this case (i.e., when called on the `foo` package's graph + node, passed the attribute name `bar`) despite the importability of the + `foo.bar` submodule. + """ + + return attr_name in self._global_attr_names + + + def is_submodule(self, submodule_basename): + """ + `True` only if the parent module corresponding to this graph node + contains the submodule with the passed name. + + If `True`, this parent module is typically but _not_ always a package + (e.g., the non-package `os` module containing the `os.path` submodule). + + Parameters + ---------- + submodule_basename : str + Unqualified name of the submodule to be tested. + + Returns + ---------- + bool + `True` only if this parent module contains this submodule. + """ + + return submodule_basename in self._submodule_basename_to_node + + + def add_global_attr(self, attr_name): + """ + Record the global attribute (e.g., class, variable) with the passed + name to be defined by the pure-Python module corresponding to this + graph node. + + If this module is actually a package, this method instead records this + attribute to be defined by this package's pure-Python `__init__` + submodule. + + Parameters + ---------- + attr_name : str + Unqualified name of the attribute to be added. + """ + + self._global_attr_names.add(attr_name) + + + def add_global_attrs_from_module(self, target_module): + """ + Record all global attributes (e.g., classes, variables) defined by the + target module corresponding to the passed graph node to also be defined + by the source module corresponding to this graph node. + + If the source module is actually a package, this method instead records + these attributes to be defined by this package's pure-Python `__init__` + submodule. + + Parameters + ---------- + target_module : Node + Graph node of the target module to import attributes from. + """ + + self._global_attr_names.update(target_module._global_attr_names) + + + def add_submodule(self, submodule_basename, submodule_node): + """ + Add the submodule with the passed name and previously imported graph + node to the parent module corresponding to this graph node. + + This parent module is typically but _not_ always a package (e.g., the + non-package `os` module containing the `os.path` submodule). + + Parameters + ---------- + submodule_basename : str + Unqualified name of the submodule to add to this parent module. + submodule_node : Node + Graph node of this submodule. + """ + + self._submodule_basename_to_node[submodule_basename] = submodule_node + + + def get_submodule(self, submodule_basename): + """ + Graph node of the submodule with the passed name in the parent module + corresponding to this graph node. + + If this parent module does _not_ contain this submodule, an exception + is raised. Else, this parent module is typically but _not_ always a + package (e.g., the non-package `os` module containing the `os.path` + submodule). + + Parameters + ---------- + module_basename : str + Unqualified name of the submodule to retrieve. + + Returns + ---------- + Node + Graph node of this submodule. + """ + + return self._submodule_basename_to_node[submodule_basename] + + + def get_submodule_or_none(self, submodule_basename): + """ + Graph node of the submodule with the passed unqualified name in the + parent module corresponding to this graph node if this module contains + this submodule _or_ `None`. + + This parent module is typically but _not_ always a package (e.g., the + non-package `os` module containing the `os.path` submodule). + + Parameters + ---------- + submodule_basename : str + Unqualified name of the submodule to retrieve. + + Returns + ---------- + Node + Graph node of this submodule if this parent module contains this + submodule _or_ `None`. + """ + + return self._submodule_basename_to_node.get(submodule_basename) + + + def remove_global_attr_if_found(self, attr_name): + """ + Record the global attribute (e.g., class, variable) with the passed + name if previously recorded as defined by the pure-Python module + corresponding to this graph node to be subsequently undefined by the + same module. + + If this module is actually a package, this method instead records this + attribute to be undefined by this package's pure-Python `__init__` + submodule. + + This method is intended to be called on globals previously defined by + this module that are subsequently undefined via the `del` built-in by + this module, thus "forgetting" or "undoing" these globals. + + For safety, there exists no corresponding `remove_global_attr()` + method. While defining this method is trivial, doing so would invite + `KeyError` exceptions on scanning valid Python that lexically deletes a + global in a scope under this module's top level (e.g., in a function) + _before_ defining this global at this top level. Since `ModuleGraph` + cannot and should not (re)implement a full-blown Python interpreter, + ignoring out-of-order deletions is the only sane policy. + + Parameters + ---------- + attr_name : str + Unqualified name of the attribute to be removed. + """ + + if self.is_global_attr(attr_name): + self._global_attr_names.remove(attr_name) + + def __eq__(self, other): + try: + otherIdent = getattr(other, 'graphident') + except AttributeError: + return False + + return self.graphident == otherIdent + + def __ne__(self, other): + try: + otherIdent = getattr(other, 'graphident') + except AttributeError: + return True + + return self.graphident != otherIdent + + def __lt__(self, other): + try: + otherIdent = getattr(other, 'graphident') + except AttributeError: + return NotImplemented + + return self.graphident < otherIdent + + def __le__(self, other): + try: + otherIdent = getattr(other, 'graphident') + except AttributeError: + return NotImplemented + + return self.graphident <= otherIdent + + def __gt__(self, other): + try: + otherIdent = getattr(other, 'graphident') + except AttributeError: + return NotImplemented + + return self.graphident > otherIdent + + def __ge__(self, other): + try: + otherIdent = getattr(other, 'graphident') + except AttributeError: + return NotImplemented + + return self.graphident >= otherIdent + + def __hash__(self): + return hash(self.graphident) + + def infoTuple(self): + return (self.identifier,) + + def __repr__(self): + return '%s%r' % (type(self).__name__, self.infoTuple()) + + +# TODO: This indirection is, frankly, unnecessary. The +# ModuleGraph.alias_module() should directly add the desired AliasNode instance +# to the graph rather than indirectly adding an Alias instance to the +# "lazynodes" dictionary. +class Alias(str): + """ + Placeholder aliasing an existing source module to a non-existent target + module (i.e., the desired alias). + + For obscure reasons, this class subclasses `str`. Each instance of this + class is the fully-qualified name of the existing source module being + aliased. Unlike the related `AliasNode` class, instances of this class are + _not_ actual nodes and hence _not_ added to the graph; they only facilitate + communication between the `ModuleGraph.alias_module()` and + `ModuleGraph.find_node()` methods. + """ + + +class AliasNode(Node): + """ + Graph node representing the aliasing of an existing source module under a + non-existent target module name (i.e., the desired alias). + """ + + def __init__(self, name, node): + """ + Initialize this alias. + + Parameters + ---------- + name : str + Fully-qualified name of the non-existent target module to be + created (as an alias of the existing source module). + node : Node + Graph node of the existing source module being aliased. + """ + super(AliasNode, self).__init__(name) + + #FIXME: Why only some? Why not *EVERYTHING* except "graphident", which + #must remain equal to "name" for lookup purposes? This is, after all, + #an alias. The idea is for the two nodes to effectively be the same. + + # Copy some attributes from this source module into this target alias. + for attr_name in ( + 'identifier', 'packagepath', + '_global_attr_names', '_starimported_ignored_module_names', + '_submodule_basename_to_node'): + if hasattr(node, attr_name): + setattr(self, attr_name, getattr(node, attr_name)) + + + def infoTuple(self): + return (self.graphident, self.identifier) + + +class BadModule(Node): + pass + + +class ExcludedModule(BadModule): + pass + + +class MissingModule(BadModule): + pass + + +class InvalidRelativeImport (BadModule): + def __init__(self, relative_path, from_name): + identifier = relative_path + if relative_path.endswith('.'): + identifier += from_name + else: + identifier += '.' + from_name + super(InvalidRelativeImport, self).__init__(identifier) + self.relative_path = relative_path + self.from_name = from_name + + def infoTuple(self): + return (self.relative_path, self.from_name) + + +class Script(Node): + def __init__(self, filename): + super(Script, self).__init__(filename) + self.filename = filename + + def infoTuple(self): + return (self.filename,) + + +class BaseModule(Node): + def __init__(self, name, filename=None, path=None): + super(BaseModule, self).__init__(name) + self.filename = filename + self.packagepath = path + + def infoTuple(self): + return tuple(filter(None, (self.identifier, self.filename, self.packagepath))) + + +class BuiltinModule(BaseModule): + pass + + +class SourceModule(BaseModule): + pass + + +class InvalidSourceModule(SourceModule): + pass + + +class CompiledModule(BaseModule): + pass + + +class InvalidCompiledModule(BaseModule): + pass + + +class Extension(BaseModule): + pass + + +class Package(BaseModule): + """ + Graph node representing a non-namespace package. + """ + pass + + +class ExtensionPackage(Extension, Package): + """ + Graph node representing a package where the __init__ module is an extension + module. + """ + pass + + +class NamespacePackage(Package): + """ + Graph node representing a namespace package. + """ + pass + + +class RuntimeModule(BaseModule): + """ + Graph node representing a non-package Python module dynamically defined at + runtime. + + Most modules are statically defined on-disk as standard Python files. + Some modules, however, are dynamically defined in-memory at runtime + (e.g., `gi.repository.Gst`, dynamically defined by the statically + defined `gi.repository.__init__` module). + + This node represents such a runtime module. Since this is _not_ a package, + all attempts to import submodules from this module in `from`-style import + statements (e.g., the `queue` submodule in `from six.moves import queue`) + will be silently ignored. + + To ensure that the parent package of this module if any is also imported + and added to the graph, this node is typically added to the graph by + calling the `ModuleGraph.add_module()` method. + """ + pass + + +class RuntimePackage(Package): + """ + Graph node representing a non-namespace Python package dynamically defined + at runtime. + + Most packages are statically defined on-disk as standard subdirectories + containing `__init__.py` files. Some packages, however, are dynamically + defined in-memory at runtime (e.g., `six.moves`, dynamically defined by + the statically defined `six` module). + + This node represents such a runtime package. All attributes imported from + this package in `from`-style import statements that are submodules of this + package (e.g., the `queue` submodule in `from six.moves import queue`) will + be imported rather than ignored. + + To ensure that the parent package of this package if any is also imported + and added to the graph, this node is typically added to the graph by + calling the `ModuleGraph.add_module()` method. + """ + pass + + +#FIXME: Safely removable. We don't actually use this anywhere. After removing +#this class, remove the corresponding entry from "compat". +class FlatPackage(BaseModule): + def __init__(self, *args, **kwds): + warnings.warn( + "This class will be removed in a future version of modulegraph", + DeprecationWarning) + super(FlatPackage, *args, **kwds) + + +#FIXME: Safely removable. We don't actually use this anywhere. After removing +#this class, remove the corresponding entry from "compat". +class ArchiveModule(BaseModule): + def __init__(self, *args, **kwds): + warnings.warn( + "This class will be removed in a future version of modulegraph", + DeprecationWarning) + super(FlatPackage, *args, **kwds) + + +# HTML templates for ModuleGraph generator +header = """\ + + + + + %(TITLE)s + + + +

%(TITLE)s

""" +entry = """ +
+ + %(CONTENT)s +
""" +contpl = """%(NAME)s %(TYPE)s""" +contpl_linked = """\ +%(NAME)s +%(TYPE)s""" +imports = """\ +
+%(HEAD)s: + %(LINKS)s +
+""" +footer = """ + +""" + + +def _ast_names(names): + result = [] + for nm in names: + if isinstance(nm, ast.alias): + result.append(nm.name) + else: + result.append(nm) + + result = [r for r in result if r != '__main__'] + return result + + +def uniq(seq): + """Remove duplicates from a list, preserving order""" + # Taken from https://stackoverflow.com/questions/480214 + seen = set() + seen_add = seen.add + return [x for x in seq if not (x in seen or seen_add(x))] + + +if sys.version_info[0] == 2: + DEFAULT_IMPORT_LEVEL = -1 +else: + DEFAULT_IMPORT_LEVEL = 0 + + +class _Visitor(ast.NodeVisitor): + def __init__(self, graph, module): + self._graph = graph + self._module = module + self._level = DEFAULT_IMPORT_LEVEL + self._in_if = [False] + self._in_def = [False] + self._in_tryexcept = [False] + + @property + def in_if(self): + return self._in_if[-1] + + @property + def in_def(self): + return self._in_def[-1] + + @property + def in_tryexcept(self): + return self._in_tryexcept[-1] + + + def _collect_import(self, name, fromlist, level): + if sys.version_info[0] == 2: + if name == '__future__' and 'absolute_import' in (fromlist or ()): + self._level = 0 + + have_star = False + if fromlist is not None: + fromlist = uniq(fromlist) + if '*' in fromlist: + fromlist.remove('*') + have_star = True + + # Record this import as originating from this module for subsequent + # handling by the _process_imports() method. + self._module._deferred_imports.append( + (have_star, + (name, self._module, fromlist, level), + {'edge_attr': DependencyInfo( + conditional=self.in_if, + tryexcept=self.in_tryexcept, + function=self.in_def, + fromlist=False)})) + + + def visit_Import(self, node): + for nm in _ast_names(node.names): + self._collect_import(nm, None, self._level) + + def visit_ImportFrom(self, node): + level = node.level if node.level != 0 else self._level + self._collect_import(node.module or '', _ast_names(node.names), level) + + def visit_If(self, node): + self._in_if.append(True) + self.generic_visit(node) + self._in_if.pop() + + def visit_FunctionDef(self, node): + self._in_def.append(True) + self.generic_visit(node) + self._in_def.pop() + + visit_AsyncFunctionDef = visit_FunctionDef + + def visit_Try(self, node): + self._in_tryexcept.append(True) + self.generic_visit(node) + self._in_tryexcept.pop() + + def visit_TryExcept(self, node): + self._in_tryexcept.append(True) + self.generic_visit(node) + self._in_tryexcept.pop() + + def visit_Expression(self, node): + # Expression node's cannot contain import statements or + # other nodes that are relevant for us. + pass + + # Expression isn't actually used as such in AST trees, + # therefore define visitors for all kinds of expression nodes. + visit_BoolOp = visit_Expression + visit_BinOp = visit_Expression + visit_UnaryOp = visit_Expression + visit_Lambda = visit_Expression + visit_IfExp = visit_Expression + visit_Dict = visit_Expression + visit_Set = visit_Expression + visit_ListComp = visit_Expression + visit_SetComp = visit_Expression + visit_ListComp = visit_Expression + visit_GeneratorExp = visit_Expression + visit_Compare = visit_Expression + visit_Yield = visit_Expression + visit_YieldFrom = visit_Expression + visit_Await = visit_Expression + visit_Call = visit_Expression + visit_Await = visit_Expression + + +class ModuleGraph(ObjectGraph): + """ + Directed graph whose nodes represent modules and edges represent + dependencies between these modules. + """ + + + def createNode(self, cls, name, *args, **kw): + m = self.find_node(name) + + if m is None: + #assert m is None, m + m = super(ModuleGraph, self).createNode(cls, name, *args, **kw) + + return m + + + def __init__(self, path=None, excludes=(), replace_paths=(), implies=(), graph=None, debug=0): + super(ModuleGraph, self).__init__(graph=graph, debug=debug) + if path is None: + path = sys.path + self.path = path + self.lazynodes = {} + # excludes is stronger than implies + self.lazynodes.update(dict(implies)) + for m in excludes: + self.lazynodes[m] = None + self.replace_paths = replace_paths + + self.set_setuptools_nspackages() + # Maintain own list of package path mappings in the scope of Modulegraph + # object. + self._package_path_map = _packagePathMap + + def set_setuptools_nspackages(self): + # This is used when running in the test-suite + self.nspackages = self._calc_setuptools_nspackages() + + def _calc_setuptools_nspackages(self): + # Setuptools has some magic handling for namespace + # packages when using 'install --single-version-externally-managed' + # (used by system packagers and also by pip) + # + # When this option is used namespace packages are writting to + # disk *without* an __init__.py file, which means the regular + # import machinery will not find them. + # + # We therefore explicitly look for the hack used by + # setuptools to get this kind of namespace packages to work. + + pkgmap = {} + + for entry in self.path: + importer = pkg_resources.get_importer(entry) + + if isinstance(importer, importlib.machinery.FileFinder): + try: + ldir = os.listdir(entry) + except os.error: + continue + + for fn in ldir: + if fn.endswith('-nspkg.pth'): + with open(os.path.join(entry, fn), _READ_MODE) as fp: + for ln in fp: + for pfx in _SETUPTOOLS_NAMESPACEPKG_PTHs: + if ln.startswith(pfx): + try: + start = len(pfx)-2 + stop = ln.index(')', start)+1 + except ValueError: + continue + + pkg = _eval_str_tuple(ln[start:stop]) + identifier = ".".join(pkg) + subdir = os.path.join(entry, *pkg) + if os.path.exists(os.path.join(subdir, '__init__.py')): + # There is a real __init__.py, + # ignore the setuptools hack + continue + + if identifier in pkgmap: + pkgmap[identifier].append(subdir) + else: + pkgmap[identifier] = [subdir] + break + + return pkgmap + + def implyNodeReference(self, node, other, edge_data=None): + """ + Create a reference from the passed source node to the passed other node, + implying the former to depend upon the latter. + + While the source node _must_ be an existing graph node, the target node + may be either an existing graph node _or_ a fully-qualified module name. + In the latter case, the module with that name and all parent packages of + that module will be imported _without_ raising exceptions and for each + newly imported module or package: + + * A new graph node will be created for that module or package. + * A reference from the passed source node to that module or package will + be created. + + This method allows dependencies between Python objects _not_ importable + with standard techniques (e.g., module aliases, C extensions). + + Parameters + ---------- + node : str + Graph node for this reference's source module or package. + other : {Node, str} + Either a graph node _or_ fully-qualified name for this reference's + target module or package. + """ + + if isinstance(other, Node): + self._updateReference(node, other, edge_data) + else: + if isinstance(other, tuple): + raise ValueError(other) + others = self._safe_import_hook(other, node, None) + for other in others: + self._updateReference(node, other, edge_data) + + def outgoing(self, fromnode): + """ + Yield all nodes that `fromnode` dependes on (that is, + all modules that `fromnode` imports. + """ + + node = self.find_node(fromnode) + out_edges, _ = self.get_edges(node) + return out_edges + + getReferences = outgoing + + def incoming(self, tonode, collapse_missing_modules=True): + node = self.find_node(tonode) + _, in_edges = self.get_edges(node) + + if collapse_missing_modules: + for n in in_edges: + if isinstance(n, MissingModule): + for n in self.incoming(n, False): + yield n + + else: + yield n + + else: + for n in in_edges: + yield n + + getReferers = incoming + + def hasEdge(self, fromnode, tonode): + """ Return True iff there is an edge from 'fromnode' to 'tonode' """ + fromnode = self.find_node(fromnode) + tonode = self.find_node(tonode) + + return self.graph.edge_by_node(fromnode, tonode) is not None + + def foldReferences(self, packagenode): + """ + Create edges to/from `packagenode` based on the edges to/from all + submodules of that package _and_ then hide the graph nodes + corresponding to those submodules. + """ + + pkg = self.find_node(packagenode) + + for n in self.nodes(): + if not n.identifier.startswith(pkg.identifier + '.'): + continue + + iter_out, iter_inc = self.get_edges(n) + for other in iter_out: + if other.identifier.startswith(pkg.identifier + '.'): + continue + + if not self.hasEdge(pkg, other): + # Ignore circular dependencies + self._updateReference(pkg, other, 'pkg-internal-import') + + for other in iter_inc: + if other.identifier.startswith(pkg.identifier + '.'): + # Ignore circular dependencies + continue + + if not self.hasEdge(other, pkg): + self._updateReference(other, pkg, 'pkg-import') + + self.graph.hide_node(n) + + # TODO: unfoldReferences(pkg) that restore the submodule nodes and + # removes 'pkg-import' and 'pkg-internal-import' edges. Care should + # be taken to ensure that references are correct if multiple packages + # are folded and then one of them in unfolded + + def _updateReference(self, fromnode, tonode, edge_data): + try: + ed = self.edgeData(fromnode, tonode) + except (KeyError, GraphError): # XXX: Why 'GraphError' + return self.add_edge(fromnode, tonode, edge_data) + + if not (isinstance(ed, DependencyInfo) and isinstance(edge_data, DependencyInfo)): + self.updateEdgeData(fromnode, tonode, edge_data) + else: + self.updateEdgeData(fromnode, tonode, ed._merged(edge_data)) + + def add_edge(self, fromnode, tonode, edge_data='direct'): + """ + Create a reference from fromnode to tonode + """ + return super(ModuleGraph, self).createReference(fromnode, tonode, edge_data=edge_data) + + createReference = add_edge + + def find_node(self, name, create_nspkg=True): + """ + Graph node uniquely identified by the passed fully-qualified module + name if this module has been added to the graph _or_ `None` otherwise. + + If (in order): + + . A namespace package with this identifier exists _and_ the passed + `create_nspkg` parameter is `True`, this package will be + instantiated and returned. + . A lazy node with this identifier and: + * No dependencies exists, this node will be instantiated and + returned. + * Dependencies exists, this node and all transitive dependencies of + this node be instantiated and this node returned. + . A non-lazy node with this identifier exists, this node will be + returned as is. + + Parameters + ---------- + name : str + Fully-qualified name of the module whose graph node is to be found. + create_nspkg : bool + Whether or not to implicitly instantiate namespace packages. If + `True` _and_ this name is that of a previously registered namespace + package (i.e., in `self.nspackages`) not already added to the + graph, this package will be added to the graph. Defaults to `True`. + + Returns + ---------- + Node + Graph node of this module if added to the graph _or_ `None` + otherwise. + """ + + data = super(ModuleGraph, self).findNode(name) + + if data is not None: + return data + + if name in self.lazynodes: + deps = self.lazynodes.pop(name) + + if deps is None: + # excluded module + m = self.createNode(ExcludedModule, name) + elif isinstance(deps, Alias): + other = self._safe_import_hook(deps, None, None).pop() + m = self.createNode(AliasNode, name, other) + self.implyNodeReference(m, other) + else: + m = self._safe_import_hook(name, None, None).pop() + for dep in deps: + self.implyNodeReference(m, dep) + + return m + + if name in self.nspackages and create_nspkg: + # name is a --single-version-externally-managed + # namespace package (setuptools/distribute) + pathnames = self.nspackages.pop(name) + m = self.createNode(NamespacePackage, name) + + # FIXME: The filename must be set to a string to ensure that py2app + # works, it is not clear yet why that is. Setting to None would be + # cleaner. + m.filename = '-' + m.packagepath = _namespace_package_path(name, pathnames, self.path) + + # As per comment at top of file, simulate runtime packagepath additions. + m.packagepath = m.packagepath + self._package_path_map.get(name, []) + return m + + return None + + findNode = find_node + iter_graph = ObjectGraph.flatten + + def add_script(self, pathname, caller=None): + """ + Create a node by path (not module name). It is expected to be a Python + source file, and will be scanned for dependencies. + """ + self.msg(2, "run_script", pathname) + + pathname = os.path.realpath(pathname) + m = self.find_node(pathname) + if m is not None: + return m + + if sys.version_info[0] != 2: + with open(pathname, 'rb') as fp: + encoding = util.guess_encoding(fp) + + with open(pathname, _READ_MODE, encoding=encoding) as fp: + contents = fp.read() + '\n' + if contents.startswith(BOM): + # Ignore BOM at start of input + contents = contents[1:] + + else: + with open(pathname, _READ_MODE) as fp: + contents = fp.read() + '\n' + + co_ast = compile(contents, pathname, 'exec', ast.PyCF_ONLY_AST, True) + co = compile(co_ast, pathname, 'exec', 0, True) + m = self.createNode(Script, pathname) + self._updateReference(caller, m, None) + n = self._scan_code(m, co, co_ast) + self._process_imports(n) + m.code = co + if self.replace_paths: + m.code = self._replace_paths_in_code(m.code) + return m + + + #FIXME: For safety, the "source_module" parameter should default to the + #root node of the current graph if unpassed. This parameter currently + #defaults to None, thus disconnected modules imported in this manner (e.g., + #hidden imports imported by depend.analysis.initialize_modgraph()). + def import_hook( + self, + target_module_partname, + source_module=None, + target_attr_names=None, + level=DEFAULT_IMPORT_LEVEL, + edge_attr=None, + ): + """ + Import the module with the passed name, all parent packages of this + module, _and_ all submodules and attributes in this module with the + passed names from the previously imported caller module signified by + the passed graph node. + + Unlike most import methods (e.g., `_safe_import_hook()`), this method + is designed to be publicly called by both external and internal + callers and hence is public. + + Parameters + ---------- + target_module_partname : str + Partially-qualified name of the target module to be imported. See + `_safe_import_hook()` for further details. + source_module : Node + Graph node for the previously imported **source module** (i.e., + module containing the `import` statement triggering the call to + this method) _or_ `None` if this module is to be imported in a + "disconnected" manner. **Passing `None` is _not_ recommended.** + Doing so produces a disconnected graph in which the graph node + created for the module to be imported will be disconnected and + hence unreachable from all other nodes -- which frequently causes + subtle issues in external callers (namely PyInstaller, which + silently ignores unreachable nodes). + target_attr_names : list + List of the unqualified names of all submodules and attributes to + be imported from the module to be imported if this is a "from"- + style import (e.g., `[encode_base64, encode_noop]` for the import + `from email.encoders import encode_base64, encode_noop`) _or_ + `None` otherwise. + level : int + Whether to perform an absolute or relative import. See + `_safe_import_hook()` for further details. + + Returns + ---------- + list + List of the graph nodes created for all modules explicitly imported + by this call, including the passed module and all submodules listed + in `target_attr_names` _but_ excluding all parent packages + implicitly imported by this call. If `target_attr_names` is `None` + or the empty list, this is guaranteed to be a list of one element: + the graph node created for the passed module. + + Raises + ---------- + ImportError + If the target module to be imported is unimportable. + """ + self.msg(3, "_import_hook", target_module_partname, source_module, source_module, level) + + source_package = self._determine_parent(source_module) + target_package, target_module_partname = self._find_head_package( + source_package, target_module_partname, level) + + self.msgin(4, "load_tail", target_package, target_module_partname) + + submodule = target_package + while target_module_partname: + i = target_module_partname.find('.') + if i < 0: + i = len(target_module_partname) + head, target_module_partname = target_module_partname[ + :i], target_module_partname[i+1:] + mname = "%s.%s" % (submodule.identifier, head) + submodule = self._safe_import_module(head, mname, submodule) + + if submodule is None: + # FIXME: Why do we no longer return a MissingModule instance? + # result = self.createNode(MissingModule, mname) + self.msgout(4, "raise ImportError: No module named", mname) + raise ImportError("No module named " + repr(mname)) + + self.msgout(4, "load_tail ->", submodule) + + target_module = submodule + target_modules = [target_module] + + # If this is a "from"-style import *AND* this target module is + # actually a package, import all submodules of this package specified + # by the "import" half of this import (e.g., the submodules "bar" and + # "car" of the target package "foo" in "from foo import bar, car"). + # + # If this target module is a non-package, it could still contain + # importable submodules (e.g., the non-package `os` module containing + # the `os.path` submodule). In this case, these submodules are already + # imported by this target module's pure-Python code. Since our import + # scanner already detects such imports, these submodules need *NOT* be + # reimported here. + if target_attr_names and isinstance(target_module, + (Package, AliasNode)): + for target_submodule in self._import_importable_package_submodules( + target_module, target_attr_names): + if target_submodule not in target_modules: + target_modules.append(target_submodule) + + # Add an edge from this source module to each target module. + for target_module in target_modules: + self._updateReference( + source_module, target_module, edge_data=edge_attr) + + return target_modules + + + def _determine_parent(self, caller): + """ + Determine the package containing a node. + """ + self.msgin(4, "determine_parent", caller) + + parent = None + if caller: + pname = caller.identifier + + if isinstance(caller, Package): + parent = caller + + elif '.' in pname: + pname = pname[:pname.rfind('.')] + parent = self.find_node(pname) + + elif caller.packagepath: + # XXX: I have no idea why this line + # is necessary. + parent = self.find_node(pname) + + self.msgout(4, "determine_parent ->", parent) + return parent + + + def _find_head_package( + self, + source_package, + target_module_partname, + level=DEFAULT_IMPORT_LEVEL): + """ + Import the target package providing the target module with the passed + name to be subsequently imported from the previously imported source + package corresponding to the passed graph node. + + Parameters + ---------- + source_package : Package + Graph node for the previously imported **source package** (i.e., + package containing the module containing the `import` statement + triggering the call to this method) _or_ `None` if this module is + to be imported in a "disconnected" manner. **Passing `None` is + _not_ recommended.** See the `_import_hook()` method for further + details. + target_module_partname : str + Partially-qualified name of the target module to be imported. See + `_safe_import_hook()` for further details. + level : int + Whether to perform absolute or relative imports. See the + `_safe_import_hook()` method for further details. + + Returns + ---------- + (target_package, target_module_tailname) + 2-tuple describing the imported target package, where: + * `target_package` is the graph node created for this package. + * `target_module_tailname` is the unqualified name of the target + module to be subsequently imported (e.g., `text` when passed a + `target_module_partname` of `email.mime.text`). + + Raises + ---------- + ImportError + If the package to be imported is unimportable. + """ + self.msgin(4, "find_head_package", source_package, target_module_partname, level) + + #FIXME: Rename all local variable names to something sensible. No, + #"p_fqdn" is not a sensible name. + + # If this target module is a submodule... + if '.' in target_module_partname: + target_module_headname, target_module_tailname = ( + target_module_partname.split('.', 1)) + # Else, this target module is a top-level module. + else: + target_module_headname = target_module_partname + target_module_tailname = '' + + # If attempting both absolute and relative imports... + if level == ABSOLUTE_OR_RELATIVE_IMPORT_LEVEL: + if source_package: + target_package_name = source_package.identifier + '.' + target_module_headname + else: + target_package_name = target_module_headname + # Else if attempting only absolute imports... + elif level == ABSOLUTE_IMPORT_LEVEL: + target_package_name = target_module_headname + + # Absolute import, ignore the parent + source_package = None + # Else if attempting only relative imports... + else: + if source_package is None: + self.msg(2, "Relative import outside of package") + raise InvalidRelativeImportError( + "Relative import outside of package (name=%r, parent=%r, level=%r)" % ( + target_module_partname, source_package, level)) + + for i in range(level - 1): + if '.' not in source_package.identifier: + self.msg(2, "Relative import outside of package") + raise InvalidRelativeImportError( + "Relative import outside of package (name=%r, parent=%r, level=%r)" % ( + target_module_partname, source_package, level)) + + p_fqdn = source_package.identifier.rsplit('.', 1)[0] + new_parent = self.find_node(p_fqdn) + if new_parent is None: + #FIXME: Repetition detected. Exterminate. Exterminate. + self.msg(2, "Relative import outside of package") + raise InvalidRelativeImportError( + "Relative import outside of package (name=%r, parent=%r, level=%r)" % ( + target_module_partname, source_package, level)) + + assert new_parent is not source_package, ( + new_parent, source_package) + source_package = new_parent + + if target_module_headname: + target_package_name = ( + source_package.identifier + '.' + target_module_headname) + else: + target_package_name = source_package.identifier + + # Graph node of this target package. + target_package = self._safe_import_module( + target_module_headname, target_package_name, source_package) + + #FIXME: Why exactly is this necessary again? This doesn't quite seem + #right but maybe it is. Shouldn't absolute imports only be performed if + #the passed "level" is either "ABSOLUTE_IMPORT_LEVEL" or + #"ABSOLUTE_OR_RELATIVE_IMPORT_LEVEL" -- or, more succinctly: + # + # if level < 1: + + # If this target package is *NOT* importable and a source package was + # passed, attempt to import this target package as an absolute import. + if target_package is None and source_package is not None: + target_package_name = target_module_headname + source_package = None + + # Graph node for the target package, again. + target_package = self._safe_import_module( + target_module_headname, target_package_name, source_package) + + # If this target package is importable, return this package. + if target_package is not None: + self.msgout(4, "find_head_package ->", (target_package, target_module_tailname)) + return target_package, target_module_tailname + + # Else, raise an exception. + self.msgout(4, "raise ImportError: No module named", target_package_name) + raise ImportError("No module named " + target_package_name) + + + + + #FIXME: Refactor from a generator yielding graph nodes into a non-generator + #returning a list or tuple of all yielded graph nodes. This method is only + #called once above and the return value of that call is only iterated over + #as a list or tuple. There's no demonstrable reason for this to be a + #generator. Generators are great for their intended purposes (e.g., as + #continuations). This isn't one of those purposes. + def _import_importable_package_submodules(self, package, attr_names): + """ + Generator importing and yielding each importable submodule (of the + previously imported package corresponding to the passed graph node) + whose unqualified name is in the passed list. + + Elements of this list that are _not_ importable submodules of this + package are either: + + * Ignorable attributes (e.g., classes, globals) defined at the top + level of this package's `__init__` submodule, which will be ignored. + * Else, unignorable unimportable submodules, in which case an + exception is raised. + + Parameters + ---------- + package : Package + Graph node of the previously imported package containing the + modules to be imported and yielded. + + attr_names : list + List of the unqualified names of all attributes of this package to + attempt to import as submodules. This list will be internally + converted into a set, safely ignoring any duplicates in this list + (e.g., reducing the "from"-style import + `from foo import bar, car, far, bar, car, far` to merely + `from foo import bar, car, far`). + + Yields + ---------- + Node + Graph node created for the currently imported submodule. + + Raises + ---------- + ImportError + If any attribute whose name is in `attr_names` is neither: + * An importable submodule of this package. + * An ignorable global attribute (e.g., class, variable) defined at + the top level of this package's `__init__` submodule. + In this case, this attribute _must_ be an unimportable submodule of + this package. + """ + + # Ignore duplicate submodule names in the passed list. + attr_names = set(attr_names) + self.msgin(4, "_import_importable_package_submodules", package, attr_names) + + #FIXME: This test *SHOULD* be superfluous and hence safely removable. + #The higher-level _scan_bytecode() and _collect_import() methods + #already guarantee "*" characters to be removed from fromlists. + if '*' in attr_names: + attr_names.update(self._find_all_submodules(package)) + attr_names.remove('*') + + # self.msg(4, '_import_importable_package_submodules (global attrs)', package.identifier, package._global_attr_names) + + # For the name of each attribute to be imported from this package... + for attr_name in attr_names: + # self.msg(4, '_import_importable_package_submodules (fromlist attr)', package.identifier, attr_name) + + # Graph node of this attribute if this attribute is a previously + # imported module or None otherwise. + submodule = package.get_submodule_or_none(attr_name) + + # If this attribute is *NOT* a previously imported module, attempt + # to import this attribute as a submodule of this package. + if submodule is None: + # Fully-qualified name of this submodule. + submodule_name = package.identifier + '.' + attr_name + + # Graph node of this submodule if importable or None otherwise. + submodule = self._safe_import_module( + attr_name, submodule_name, package) + + # If this submodule is unimportable... + if submodule is None: + # If this attribute is a global (e.g., class, variable) + # defined at the top level of this package's "__init__" + # submodule, this importation is safely ignorable. Do so + # and skip to the next attribute. + # + # This behaviour is non-conformant with Python behaviour, + # which is bad, but is required to sanely handle all + # possible edge cases, which is good. In Python, a global + # attribute defined at the top level of a package's + # "__init__" submodule shadows a submodule of the same name + # in that package. Attempting to import that submodule + # instead imports that attribute; thus, that submodule is + # effectively unimportable. In this method and elsewhere, + # that submodule is tested for first and hence shadows that + # attribute -- the opposite logic. Attempts to import that + # attribute are mistakenly seen as attempts to import that + # submodule! Why? + # + # Edge cases. PyInstaller (and by extension ModuleGraph) + # only cares about module imports. Global attribute imports + # are parsed only as the means to this ends and are + # otherwise ignorable. The cost of erroneously shadowing: + # + # * Submodules by attributes is significant. Doing so + # prevents such submodules from being frozen and hence + # imported at application runtime. + # * Attributes by submodules is insignificant. Doing so + # could erroneously freeze such submodules despite their + # never being imported at application runtime. However, + # ModuleGraph is incapable of determining with certainty + # that Python logic in another module other than the + # "__init__" submodule containing these attributes does + # *NOT* delete these attributes and hence unshadow these + # submodules, which would then become importable at + # runtime and require freezing. Hence, ModuleGraph *MUST* + # permissively assume submodules of the same name as + # attributes to be unshadowed elsewhere and require + # freezing -- even if they do not. + # + # It is practically difficult (albeit technically feasible) + # for ModuleGraph to determine whether or not the target + # attribute names of "from"-style import statements (e.g., + # "bar" and "car" in "from foo import bar, car") refer to + # non-ignorable submodules or ignorable non-module globals + # during opcode scanning. Distinguishing these two cases + # during opcode scanning would require a costly call to the + # _find_module() method, which would subsequently be + # repeated during import-graph construction. This could be + # ameliorated with caching, which itself would require + # costly space consumption and developer time. + # + # Since opcode scanning fails to distinguish these two + # cases, this and other methods subsequently called at + # import-graph construction time (e.g., + # _safe_import_hook()) must do so. Since submodules of the + # same name as attributes must assume to be unshadowed + # elsewhere and require freezing, the only solution is to + # attempt to import an attribute as a non-ignorable module + # *BEFORE* assuming an attribute to be an ignorable + # non-module. Which is what this and other methods do. + # + # See Package.is_global_attr() for similar discussion. + if package.is_global_attr(attr_name): + self.msg(4, '_import_importable_package_submodules: ignoring from-imported global', package.identifier, attr_name) + continue + # Else, this attribute is an unimportable submodule. Since + # this is *NOT* safely ignorable, raise an exception. + else: + raise ImportError("No module named " + submodule_name) + + # Yield this submodule's graph node to the caller. + yield submodule + + self.msgin(4, "_import_importable_package_submodules ->") + + + def _find_all_submodules(self, m): + if not m.packagepath: + return + # 'suffixes' used to be a list hardcoded to [".py", ".pyc", ".pyo"]. + # But we must also collect Python extension modules - although + # we cannot separate normal dlls from Python extensions. + for path in m.packagepath: + try: + names = zipio.listdir(path) + except (os.error, IOError): + self.msg(2, "can't list directory", path) + continue + for name in names: + for suffix in importlib.machinery.all_suffixes(): + if path.endswith(suffix): + name = os.path.basename(path)[:-len(suffix)] + break + else: + continue + if name != '__init__': + yield name + + + def alias_module(self, src_module_name, trg_module_name): + """ + Alias the source module to the target module with the passed names. + + This method ensures that the next call to findNode() given the target + module name will resolve this alias. This includes importing and adding + a graph node for the source module if needed as well as adding a + reference from the target to source module. + + Parameters + ---------- + src_module_name : str + Fully-qualified name of the existing **source module** (i.e., the + module being aliased). + trg_module_name : str + Fully-qualified name of the non-existent **target module** (i.e., + the alias to be created). + """ + self.msg(3, 'alias_module "%s" -> "%s"' % (src_module_name, trg_module_name)) + # print('alias_module "%s" -> "%s"' % (src_module_name, trg_module_name)) + assert isinstance(src_module_name, str), '"%s" not a module name.' % str(src_module_name) + assert isinstance(trg_module_name, str), '"%s" not a module name.' % str(trg_module_name) + + # If the target module has already been added to the graph as either a + # non-alias or as a different alias, raise an exception. + trg_module = self.find_node(trg_module_name) + if trg_module is not None and not ( + isinstance(trg_module, AliasNode) and + trg_module.identifier == src_module_name): + raise ValueError( + 'Target module "%s" already imported as "%s".' % ( + trg_module_name, trg_module)) + + # See findNode() for details. + self.lazynodes[trg_module_name] = Alias(src_module_name) + + + def add_module(self, module): + """ + Add the passed module node to the graph if not already added. + + If that module has a parent module or package with a previously added + node, this method also adds a reference from this module node to its + parent node and adds this module node to its parent node's namespace. + + This high-level method wraps the low-level `addNode()` method, but is + typically _only_ called by graph hooks adding runtime module nodes. For + all other node types, the `import_module()` method should be called. + + Parameters + ---------- + module : BaseModule + Graph node of the module to be added. + """ + self.msg(3, 'add_module', module) + + # If no node exists for this module, add such a node. + module_added = self.find_node(module.identifier) + if module_added is None: + self.addNode(module) + else: + assert module == module_added, 'New module %r != previous %r.' % (module, module_added) + + # If this module has a previously added parent, reference this module to + # its parent and add this module to its parent's namespace. + parent_name, _, module_basename = module.identifier.rpartition('.') + if parent_name: + parent = self.find_node(parent_name) + if parent is None: + self.msg(4, 'add_module parent not found:', parent_name) + else: + self.add_edge(module, parent) + parent.add_submodule(module_basename, module) + + + def append_package_path(self, package_name, directory): + """ + Modulegraph does a good job at simulating Python's, but it can not + handle packagepath '__path__' modifications packages make at runtime. + + Therefore there is a mechanism whereby you can register extra paths + in this map for a package, and it will be honored. + + NOTE: This method has to be called before a package is resolved by + modulegraph. + + Parameters + ---------- + module : str + Fully-qualified module name. + directory : str + Absolute or relative path of the directory to append to the + '__path__' attribute. + """ + + paths = self._package_path_map.setdefault(package_name, []) + paths.append(directory) + + + def _safe_import_module( + self, module_partname, module_name, parent_module): + """ + Create a new graph node for the module with the passed name under the + parent package signified by the passed graph node _without_ raising + `ImportError` exceptions. + + If this module has already been imported, this module's existing graph + node will be returned; else if this module is importable, a new graph + node will be added for this module and returned; else this module is + unimportable, in which case `None` will be returned. Like the + `_safe_import_hook()` method, this method does _not_ raise + `ImportError` exceptions when this module is unimportable. + + Parameters + ---------- + module_partname : str + Unqualified name of the module to be imported (e.g., `text`). + module_name : str + Fully-qualified name of this module (e.g., `email.mime.text`). + parent_module : Package + Graph node of the previously imported parent module containing this + submodule _or_ `None` if this is a top-level module (i.e., + `module_name` contains no `.` delimiters). This parent module is + typically but _not_ always a package (e.g., the `os.path` submodule + contained by the `os` module). + + Returns + ---------- + Node + Graph node created for this module _or_ `None` if this module is + unimportable. + """ + self.msgin(3, "safe_import_module", module_partname, module_name, parent_module) + + # If this module has *NOT* already been imported, do so. + module = self.find_node(module_name) + if module is None: + # List of the absolute paths of all directories to be searched for + # this module. This effectively defaults to "sys.path". + search_dirs = None + + # If this module has a parent package... + if parent_module is not None: + # ...with a list of the absolute paths of all directories + # comprising this package, prefer that to "sys.path". + if parent_module.packagepath is not None: + search_dirs = parent_module.packagepath + # Else, something is horribly wrong. Return emptiness. + else: + self.msgout(3, "safe_import_module -> None (parent_parent.packagepath is None)") + return None + + try: + pathname, loader = self._find_module( + module_partname, search_dirs, parent_module) + except ImportError as exc: + self.msgout(3, "safe_import_module -> None (%r)" % exc) + return None + + (module, co) = self._load_module(module_name, pathname, loader) + if co is not None: + try: + if isinstance(co, ast.AST): + co_ast = co + co = compile(co_ast, pathname, 'exec', 0, True) + else: + co_ast = None + n = self._scan_code(module, co, co_ast) + self._process_imports(n) + + if self.replace_paths: + co = self._replace_paths_in_code(co) + module.code = co + except SyntaxError: + self.msg( + 1, "safe_import_module: SyntaxError in ", pathname, + ) + cls = InvalidSourceModule + module = self.createNode(cls, module_name) + + # If this is a submodule rather than top-level module... + if parent_module is not None: + self.msg(4, "safe_import_module create reference", module, "->", parent_module) + + # Add an edge from this submodule to its parent module. + self._updateReference( + module, parent_module, edge_data=DependencyInfo( + conditional=False, + fromlist=False, + function=False, + tryexcept=False, + )) + + # Add this submodule to its parent module. + parent_module.add_submodule(module_partname, module) + + # Return this module. + self.msgout(3, "safe_import_module ->", module) + return module + + def _load_module(self, fqname, pathname, loader): + from importlib._bootstrap_external import ExtensionFileLoader + self.msgin(2, "load_module", fqname, pathname, + loader.__class__.__name__) + partname = fqname.rpartition(".")[-1] + + if loader.is_package(partname): + is_nspkg = isinstance(loader, NAMESPACE_PACKAGE) + if is_nspkg: + pkgpath = loader.namespace_dirs[:] # copy for safety + else: + pkgpath = [] + + newname = _replacePackageMap.get(fqname) + if newname: + fqname = newname + ns_pkgpath = _namespace_package_path( + fqname, pkgpath or [], self.path) + + if (ns_pkgpath or pkgpath) and is_nspkg: + # this is a PEP-420 namespace package + m = self.createNode(NamespacePackage, fqname) + m.filename = '-' + m.packagepath = ns_pkgpath + else: + if isinstance(loader, ExtensionFileLoader): + m = self.createNode(ExtensionPackage, fqname) + else: + m = self.createNode(Package, fqname) + m.filename = pathname + # PEP-302-compliant loaders return the pathname of the + # `__init__`-file, not the packge directory. + assert os.path.basename(pathname).startswith('__init__.') + m.packagepath = [os.path.dirname(pathname)] + ns_pkgpath + + # As per comment at top of file, simulate runtime packagepath + # additions + m.packagepath = m.packagepath + self._package_path_map.get( + fqname, []) + + if isinstance(m, NamespacePackage): + return (m, None) + + co = None + if loader is BUILTIN_MODULE: + cls = BuiltinModule + elif isinstance(loader, ExtensionFileLoader): + cls = Extension + else: + try: + src = loader.get_source(partname) + except (UnicodeDecodeError, SyntaxError) as e: + # The `UnicodeDecodeError` is typically raised here when the + # source file contains non-ASCII characters in some local + # encoding that is different from UTF-8, but fails to + # declare it via PEP361 encoding header. Python seems to + # be able to load and run such module, but we cannot retrieve + # the source for it via the `loader.get_source()`. + # + # The `UnicodeDecoreError` in turn triggers a `SyntaxError` + # when such invalid character appears on the first line of + # the source file (and interrupts the scan for PEP361 + # encoding header). + # + # In such cases, we try to fall back to reading the source + # as raw data file. + + # If `SyntaxError` was not raised during handling of + # a `UnicodeDecodeError`, it was likely a genuine syntax + # error, so re-raise it. + if isinstance(e, SyntaxError): + if not isinstance(e.__context__, UnicodeDecodeError): + raise + + self.msg(2, "load_module: failed to obtain source for " + f"{partname}: {e}! Falling back to reading as " + "raw data!") + + path = loader.get_filename(partname) + src = loader.get_data(path) + + if src is not None: + try: + co = compile(src, pathname, 'exec', ast.PyCF_ONLY_AST, + True) + cls = SourceModule + if sys.version_info[:2] == (3, 5): + # In Python 3.5 some syntax problems with async + # functions are only reported when compiling to + # bytecode + compile(co, '-', 'exec', 0, True) + except SyntaxError: + co = None + cls = InvalidSourceModule + except Exception as exc: # FIXME: more specific? + cls = InvalidSourceModule + self.msg(2, "load_module: InvalidSourceModule", pathname, + exc) + else: + # no src available + try: + co = loader.get_code(partname) + cls = (CompiledModule if co is not None + else InvalidCompiledModule) + except Exception as exc: # FIXME: more specific? + self.msg(2, "load_module: InvalidCompiledModule, " + "Cannot load code", pathname, exc) + cls = InvalidCompiledModule + + m = self.createNode(cls, fqname) + m.filename = pathname + + self.msgout(2, "load_module ->", m) + return (m, co) + + def _safe_import_hook( + self, target_module_partname, source_module, target_attr_names, + level=DEFAULT_IMPORT_LEVEL, edge_attr=None): + """ + Import the module with the passed name and all parent packages of this + module from the previously imported caller module signified by the + passed graph node _without_ raising `ImportError` exceptions. + + This method wraps the lowel-level `_import_hook()` method. On catching + an `ImportError` exception raised by that method, this method creates + and adds a `MissingNode` instance describing the unimportable module to + the graph instead. + + Parameters + ---------- + target_module_partname : str + Partially-qualified name of the module to be imported. If `level` + is: + * `ABSOLUTE_OR_RELATIVE_IMPORT_LEVEL` (e.g., the Python 2 default) + or a positive integer (e.g., an explicit relative import), the + fully-qualified name of this module is the concatenation of the + fully-qualified name of the caller module's package and this + parameter. + * `ABSOLUTE_IMPORT_LEVEL` (e.g., the Python 3 default), this name + is already fully-qualified. + * A non-negative integer (e.g., `1`), this name is typically the + empty string. In this case, this is a "from"-style relative + import (e.g., "from . import bar") and the fully-qualified name + of this module is dynamically resolved by import machinery. + source_module : Node + Graph node for the previously imported **caller module** (i.e., + module containing the `import` statement triggering the call to + this method) _or_ `None` if this module is to be imported in a + "disconnected" manner. **Passing `None` is _not_ recommended.** + Doing so produces a disconnected graph in which the graph node + created for the module to be imported will be disconnected and + hence unreachable from all other nodes -- which frequently causes + subtle issues in external callers (e.g., PyInstaller, which + silently ignores unreachable nodes). + target_attr_names : list + List of the unqualified names of all submodules and attributes to + be imported via a `from`-style import statement from this target + module if any (e.g., the list `[encode_base64, encode_noop]` for + the import `from email.encoders import encode_base64, encode_noop`) + _or_ `None` otherwise. Ignored unless `source_module` is the graph + node of a package (i.e., is an instance of the `Package` class). + Why? Because: + * Consistency. The `_import_importable_package_submodules()` + method accepts a similar list applicable only to packages. + * Efficiency. Unlike packages, modules cannot physically contain + submodules. Hence, any target module imported via a `from`-style + import statement as an attribute from another target parent + module must itself have been imported in that target parent + module. The import statement responsible for that import must + already have been previously parsed by `ModuleGraph`, in which + case that target module will already be frozen by PyInstaller. + These imports are safely ignorable here. + level : int + Whether to perform an absolute or relative import. This parameter + corresponds exactly to the parameter of the same name accepted by + the `__import__()` built-in: "The default is -1 which indicates + both absolute and relative imports will be attempted. 0 means only + perform absolute imports. Positive values for level indicate the + number of parent directories to search relative to the directory of + the module calling `__import__()`." Defaults to -1 under Python 2 + and 0 under Python 3. Since this default depends on the major + version of the current Python interpreter, depending on this + default can result in unpredictable and non-portable behaviour. + Callers are strongly recommended to explicitly pass this parameter + rather than implicitly accept this default. + + Returns + ---------- + list + List of the graph nodes created for all modules explicitly imported + by this call, including the passed module and all submodules listed + in `target_attr_names` _but_ excluding all parent packages + implicitly imported by this call. If `target_attr_names` is either + `None` or the empty list, this is guaranteed to be a list of one + element: the graph node created for the passed module. As above, + `MissingNode` instances are created for all unimportable modules. + """ + self.msg(3, "_safe_import_hook", target_module_partname, source_module, target_attr_names, level) + + def is_swig_candidate(): + return (source_module is not None and + target_attr_names is None and + level == ABSOLUTE_IMPORT_LEVEL and + type(source_module) is SourceModule and + target_module_partname == + '_' + source_module.identifier.rpartition('.')[2] and + sys.version_info[0] == 3) + + def is_swig_wrapper(source_module): + # TODO Define a new function util.open_text_file() performing + # this logic, which is repeated numerous times in this module. + # FIXME: Actually, can't we just use the new compat.open() + # function to reliably open text files in a portable manner? + with open(source_module.filename, 'rb') as source_module_file: + encoding = util.guess_encoding(source_module_file) + with open(source_module.filename, _READ_MODE, encoding=encoding) \ + as source_module_file: + first_line = source_module_file.readline() + self.msg(5, 'SWIG wrapper candidate first line: %r' % (first_line)) + return "automatically generated by SWIG" in first_line + + + # List of the graph nodes created for all target modules both + # imported by and returned from this call, whose: + # + # * First element is the graph node for the core target module + # specified by the "target_module_partname" parameter. + # * Remaining elements are the graph nodes for all target submodules + # specified by the "target_attr_names" parameter. + target_modules = None + + # True if this is a Python 2-style implicit relative import of a + # SWIG-generated C extension. False if we checked and it is not SWIG. + # None if we haven't checked yet. + is_swig_import = None + + # Attempt to import this target module in the customary way. + try: + target_modules = self.import_hook( + target_module_partname, source_module, + target_attr_names=None, level=level, edge_attr=edge_attr) + # Failing that, defer to custom module importers handling non-standard + # import schemes (namely, SWIG). + except InvalidRelativeImportError: + self.msgout(2, "Invalid relative import", level, + target_module_partname, target_attr_names) + result = [] + for sub in target_attr_names or '*': + m = self.createNode(InvalidRelativeImport, + '.' * level + target_module_partname, sub) + self._updateReference(source_module, m, edge_data=edge_attr) + result.append(m) + return result + except ImportError as msg: + # If this is an absolute top-level import under Python 3 and if the + # name to be imported is the caller's name prefixed by "_", this + # could be a SWIG-generated Python 2-style implicit relative import. + # SWIG-generated files contain functions named swig_import_helper() + # importing dynamic libraries residing in the same directory. For + # example, a SWIG-generated caller module "csr.py" might resemble: + # + # # This file was automatically generated by SWIG (http://www.swig.org). + # ... + # def swig_import_helper(): + # ... + # try: + # fp, pathname, description = imp.find_module('_csr', + # [dirname(__file__)]) + # except ImportError: + # import _csr + # return _csr + # + # While there exists no reasonable means for modulegraph to parse + # the call to imp.find_module(), the subsequent implicit relative + # import is trivially parsable. This import is prohibited under + # Python 3, however, and thus parsed only if the caller's file is + # parsable plaintext (as indicated by a filetype of ".py") and the + # first line of this file is the above SWIG header comment. + # + # The constraint that this library's name be the caller's name + # prefixed by '_' is explicitly mandated by SWIG and thus a + # reliable indicator of "SWIG-ness". The SWIG documentation states: + # "When linking the module, the name of the output file has to match + # the name of the module prefixed by an underscore." + # + # Only source modules (e.g., ".py"-suffixed files) are SWIG import + # candidates. All other node types are safely ignorable. + if is_swig_candidate(): + self.msg( + 4, + 'SWIG import candidate (name=%r, caller=%r, level=%r)' % ( + target_module_partname, source_module, level)) + is_swig_import = is_swig_wrapper(source_module) + if is_swig_import: + # Convert this Python 2-compliant implicit relative + # import prohibited by Python 3 into a Python + # 3-compliant explicit relative "from"-style import for + # the duration of this function call by overwriting the + # original parameters passed to this call. + target_attr_names = [target_module_partname] + target_module_partname = '' + level = 1 + self.msg(2, + 'SWIG import (caller=%r, fromlist=%r, level=%r)' + % (source_module, target_attr_names, level)) + # Import this target SWIG C extension's package. + try: + target_modules = self.import_hook( + target_module_partname, source_module, + target_attr_names=None, + level=level, + edge_attr=edge_attr) + except ImportError as msg: + self.msg(2, "SWIG ImportError:", str(msg)) + + # If this module remains unimportable... + if target_modules is None: + self.msg(2, "ImportError:", str(msg)) + + # Add this module as a MissingModule node. + target_module = self.createNode( + MissingModule, + _path_from_importerror(msg, target_module_partname)) + self._updateReference( + source_module, target_module, edge_data=edge_attr) + + # Initialize this list to this node. + target_modules = [target_module] + + # Ensure that the above logic imported exactly one target module. + assert len(target_modules) == 1, ( + 'Expected import_hook() to' + 'return only one module but received: {}'.format(target_modules)) + + # Target module imported above. + target_module = target_modules[0] + + if isinstance(target_module, MissingModule) \ + and is_swig_import is None and is_swig_candidate() \ + and is_swig_wrapper(source_module): + # if this possible swig C module was previously imported from + # a python module other than its corresponding swig python + # module, then it may have been considered a MissingModule. + # Try to reimport it now. For details see pull-request #2578 + # and issue #1522. + # + # If this module was takes as a SWIG candidate above, but failed + # to import, this would be a MissingModule, too. Thus check if + # this was the case (is_swig_import would be not None) to avoid + # recursion error. If `is_swig_import` is None and we are still a + # swig candidate then that means we haven't properly imported this + # swig module yet so do that below. + # + # Remove the MissingModule node from the graph so that we can + # attempt a reimport and avoid collisions. This node should be + # fine to remove because the proper module will be imported and + # added to the graph in the next line (call to _safe_import_hook). + self.removeNode(target_module) + # Reimport the SWIG C module relative to the wrapper + target_modules = self._safe_import_hook( + target_module_partname, source_module, + target_attr_names=None, level=1, edge_attr=edge_attr) + # return the output regardless because it would just be + # duplicating the processing below + return target_modules + + if isinstance(edge_attr, DependencyInfo): + edge_attr = edge_attr._replace(fromlist=True) + + # If this is a "from"-style import *AND* this target module is a + # package, import all attributes listed by the "import" clause of this + # import that are submodules of this package. If this target module is + # *NOT* a package, these attributes are always ignorable globals (e.g., + # classes, variables) defined at the top level of this module. + # + # If this target module is a non-package, it could still contain + # importable submodules (e.g., the non-package `os` module containing + # the `os.path` submodule). In this case, these submodules are already + # imported by this target module's pure-Python code. Since our import + # scanner already detects these imports, these submodules need *NOT* be + # reimported here. (Doing so would be harmless but inefficient.) + if target_attr_names and isinstance(target_module, + (Package, AliasNode)): + # For the name of each attribute imported from this target package + # into this source module... + for target_submodule_partname in target_attr_names: + #FIXME: Is this optimization *REALLY* an optimization or at all + #necessary? The findNode() method called below should already + #be heavily optimized, in which case this optimization here is + #premature, senseless, and should be eliminated. + + # If this attribute is a previously imported submodule of this + # target module, optimize this edge case. + if target_module.is_submodule(target_submodule_partname): + # Graph node for this submodule. + target_submodule = target_module.get_submodule( + target_submodule_partname) + + #FIXME: What? Shouldn't "target_submodule" *ALWAYS* be + #non-None here? Assert this to be non-None instead. + if target_submodule is not None: + #FIXME: Why does duplication matter? List searches are + #mildly expensive. + + # If this submodule has not already been added to the + # list of submodules to be returned, do so. + if target_submodule not in target_modules: + self._updateReference( + source_module, + target_submodule, + edge_data=edge_attr) + target_modules.append(target_submodule) + continue + + # Fully-qualified name of this submodule. + target_submodule_name = ( + target_module.identifier + '.' + target_submodule_partname) + + # Graph node of this submodule if previously imported or None. + target_submodule = self.find_node(target_submodule_name) + + # If this submodule has not been imported, do so as if this + # submodule were the only attribute listed by the "import" + # clause of this import (e.g., as "from foo import bar" rather + # than "from foo import car, far, bar"). + if target_submodule is None: + # Attempt to import this submodule. + try: + # Ignore the list of graph nodes returned by this + # method. If both this submodule's package and this + # submodule are importable, this method returns a + # 2-element list whose second element is this + # submodule's graph node. However, if this submodule's + # package is importable but this submodule is not, + # this submodule is either: + # + # * An ignorable global attribute defined at the top + # level of this package's "__init__" submodule. In + # this case, this method returns a 1-element list + # without raising an exception. + # * A non-ignorable unimportable submodule. In this + # case, this method raises an "ImportError". + # + # While the first two cases are disambiguatable by the + # length of this list, doing so would render this code + # dependent on import_hook() details subject to change. + # Instead, call findNode() to decide the truthiness. + self.import_hook( + target_module_partname, source_module, + target_attr_names=[target_submodule_partname], + level=level, + edge_attr=edge_attr) + + # Graph node of this submodule imported by the prior + # call if importable or None otherwise. + target_submodule = self.find_node(target_submodule_name) + + # If this submodule does not exist, this *MUST* be an + # ignorable global attribute defined at the top level + # of this package's "__init__" submodule. + if target_submodule is None: + # Assert this to actually be the case. + assert target_module.is_global_attr( + target_submodule_partname), ( + 'No global named {} in {}.__init__'.format( + target_submodule_partname, + target_module.identifier)) + + # Skip this safely ignorable importation to the + # next attribute. See similar logic in the body of + # _import_importable_package_submodules(). + self.msg(4, '_safe_import_hook', 'ignoring imported non-module global', target_module.identifier, target_submodule_partname) + continue + + # If this is a SWIG C extension, instruct PyInstaller + # to freeze this extension under its unqualified rather + # than qualified name (e.g., as "_csr" rather than + # "scipy.sparse.sparsetools._csr"), permitting the + # implicit relative import in its parent SWIG module to + # successfully find this extension. + if is_swig_import: + # If a graph node with this name already exists, + # avoid collisions by emitting an error instead. + if self.find_node(target_submodule_partname): + self.msg( + 2, + 'SWIG import error: %r basename %r ' + 'already exists' % ( + target_submodule_name, + target_submodule_partname)) + else: + self.msg( + 4, + 'SWIG import renamed from %r to %r' % ( + target_submodule_name, + target_submodule_partname)) + target_submodule.identifier = ( + target_submodule_partname) + # If this submodule is unimportable, add a MissingModule. + except ImportError as msg: + self.msg(2, "ImportError:", str(msg)) + target_submodule = self.createNode( + MissingModule, target_submodule_name) + + # Add this submodule to its package. + target_module.add_submodule( + target_submodule_partname, target_submodule) + if target_submodule is not None: + self._updateReference( + target_module, target_submodule, edge_data=edge_attr) + self._updateReference( + source_module, target_submodule, edge_data=edge_attr) + + if target_submodule not in target_modules: + target_modules.append(target_submodule) + + # Return the list of all target modules imported by this call. + return target_modules + + + def _scan_code( + self, + module, + module_code_object, + module_code_object_ast=None): + """ + Parse and add all import statements from the passed code object of the + passed source module to this graph, recursively. + + **This method is at the root of all `ModuleGraph` recursion.** + Recursion begins here and ends when all import statements in all code + objects of all modules transitively imported by the source module + passed to the first call to this method have been added to the graph. + Specifically, this method: + + 1. If the passed `module_code_object_ast` parameter is non-`None`, + parses all import statements from this object. + 2. Else, parses all import statements from the passed + `module_code_object` parameter. + 1. For each such import statement: + 1. Adds to this `ModuleGraph` instance: + 1. Nodes for all target modules of these imports. + 1. Directed edges from this source module to these target + modules. + 2. Recursively calls this method with these target modules. + + Parameters + ---------- + module : Node + Graph node of the module to be parsed. + module_code_object : PyCodeObject + Code object providing this module's disassembled Python bytecode. + Ignored unless `module_code_object_ast` is `None`. + module_code_object_ast : optional[ast.AST] + Optional abstract syntax tree (AST) of this module if any or `None` + otherwise. Defaults to `None`, in which case the passed + `module_code_object` is parsed instead. + Returns + ---------- + module : Node + Graph node of the module to be parsed. + """ + + # For safety, guard against multiple scans of the same module by + # resetting this module's list of deferred target imports. While + # uncommon, this edge case can occur due to: + # + # * Dynamic package replacement via the replacePackage() function. For + # example, the real "_xmlplus" package dynamically replaces itself + # with the fake "xml" package into the "sys.modules" cache of all + # currently loaded modules at runtime. + module._deferred_imports = [] + + # Parse all imports from this module *BEFORE* adding these imports to + # the graph. If an AST is provided, parse that rather than this + # module's code object. + if module_code_object_ast is not None: + # Parse this module's AST for imports. + self._scan_ast(module, module_code_object_ast) + + # Parse this module's code object for all relevant non-imports + # (e.g., global variable declarations and undeclarations). + self._scan_bytecode( + module, module_code_object, is_scanning_imports=False) + # Else, parse this module's code object for imports. + else: + self._scan_bytecode( + module, module_code_object, is_scanning_imports=True) + + return module + + def _scan_ast(self, module, module_code_object_ast): + """ + Parse and add all import statements from the passed abstract syntax + tree (AST) of the passed source module to this graph, non-recursively. + + Parameters + ---------- + module : Node + Graph node of the module to be parsed. + module_code_object_ast : ast.AST + Abstract syntax tree (AST) of this module to be parsed. + """ + + visitor = _Visitor(self, module) + visitor.visit(module_code_object_ast) + + #FIXME: Optimize. Global attributes added by this method are tested by + #other methods *ONLY* for packages, implying this method should scan and + #handle opcodes pertaining to global attributes (e.g., + #"STORE_NAME", "DELETE_GLOBAL") only if the passed "module" + #object is an instance of the "Package" class. For all other module types, + #these opcodes should simply be ignored. + # + #After doing so, the "Node._global_attr_names" attribute and all methods + #using this attribute (e.g., Node.is_global()) should be moved from the + #"Node" superclass to the "Package" subclass. + def _scan_bytecode( + self, module, module_code_object, is_scanning_imports): + """ + Parse and add all import statements from the passed code object of the + passed source module to this graph, non-recursively. + + This method parses all reasonably parsable operations (i.e., operations + that are both syntactically and semantically parsable _without_ + requiring Turing-complete interpretation) directly or indirectly + involving module importation from this code object. This includes: + + * `IMPORT_NAME`, denoting an import statement. Ignored unless + the passed `is_scanning_imports` parameter is `True`. + * `STORE_NAME` and `STORE_GLOBAL`, denoting the + declaration of a global attribute (e.g., class, variable) in this + module. This method stores each such declaration for subsequent + lookup. While global attributes are usually irrelevant to import + parsing, they remain the only means of distinguishing erroneous + non-ignorable attempts to import non-existent submodules of a package + from successful ignorable attempts to import existing global + attributes of a package's `__init__` submodule (e.g., the `bar` in + `from foo import bar`, which is either a non-ignorable submodule of + `foo` or an ignorable global attribute of `foo.__init__`). + * `DELETE_NAME` and `DELETE_GLOBAL`, denoting the + undeclaration of a previously declared global attribute in this + module. + + Since `ModuleGraph` is _not_ intended to replicate the behaviour of a + full-featured Turing-complete Python interpreter, this method ignores + operations that are _not_ reasonably parsable from this code object -- + even those directly or indirectly involving module importation. This + includes: + + * `STORE_ATTR(namei)`, implementing `TOS.name = TOS1`. If `TOS` is the + name of a target module currently imported into the namespace of the + passed source module, this opcode would ideally be parsed to add that + global attribute to that target module. Since this addition only + conditionally occurs on the importation of this source module and + execution of the code branch in this module performing this addition, + however, that global _cannot_ be unconditionally added to that target + module. In short, only Turing-complete behaviour suffices. + * `DELETE_ATTR(namei)`, implementing `del TOS.name`. If `TOS` is the + name of a target module currently imported into the namespace of the + passed source module, this opcode would ideally be parsed to remove + that global attribute from that target module. Again, however, only + Turing-complete behaviour suffices. + + Parameters + ---------- + module : Node + Graph node of the module to be parsed. + module_code_object : PyCodeObject + Code object of the module to be parsed. + is_scanning_imports : bool + `True` only if this method is parsing import statements from + `IMPORT_NAME` opcodes. If `False`, no import statements will be + parsed. This parameter is typically: + * `True` when parsing this module's code object for such imports. + * `False` when parsing this module's abstract syntax tree (AST) + (rather than code object) for such imports. In this case, that + parsing will have already parsed import statements, which this + parsing must avoid repeating. + """ + level = None + fromlist = None + + # 'deque' is a list-like container with fast appends, pops on + # either end, and automatically discarding elements too much. + prev_insts = deque(maxlen=2) + for inst in util.iterate_instructions(module_code_object): + if not inst: + continue + # If this is an import statement originating from this module, + # parse this import. + # + # Note that the related "IMPORT_FROM" opcode need *NOT* be parsed. + # "IMPORT_NAME" suffices. For further details, see + # http://probablyprogramming.com/2008/04/14/python-import_name + if inst.opname == 'IMPORT_NAME': + # If this method is ignoring import statements, skip to the + # next opcode. + if not is_scanning_imports: + continue + + assert prev_insts[-2].opname == 'LOAD_CONST' + assert prev_insts[-1].opname == 'LOAD_CONST' + + # Python >=2.5: LOAD_CONST flags, LOAD_CONST names, IMPORT_NAME name + level = prev_insts[-2].argval + fromlist = prev_insts[-1].argval + + assert fromlist is None or type(fromlist) is tuple + target_module_partname = inst.argval + + #FIXME: The exact same logic appears in _collect_import(), + #which isn't particularly helpful. Instead, defer this logic + #until later by: + # + #* Refactor the "_deferred_imports" list to contain 2-tuples + # "(_safe_import_hook_args, _safe_import_hook_kwargs)" rather + # than 3-tuples "(have_star, _safe_import_hook_args, + # _safe_import_hook_kwargs)". + #* Stop prepending these tuples by a "have_star" boolean both + # here, in _collect_import(), and in _process_imports(). + #* Shift the logic below to _process_imports(). + #* Remove the same logic from _collect_import(). + have_star = False + if fromlist is not None: + fromlist = uniq(fromlist) + if '*' in fromlist: + fromlist.remove('*') + have_star = True + + # Record this import as originating from this module for + # subsequent handling by the _process_imports() method. + module._deferred_imports.append(( + have_star, + (target_module_partname, module, fromlist, level), + {} + )) + + elif inst.opname in ('STORE_NAME', 'STORE_GLOBAL'): + # If this is the declaration of a global attribute (e.g., + # class, variable) in this module, store this declaration for + # subsequent lookup. See method docstring for further details. + # + # Global attributes are usually irrelevant to import parsing, but + # remain the only means of distinguishing erroneous non-ignorable + # attempts to import non-existent submodules of a package from + # successful ignorable attempts to import existing global + # attributes of a package's "__init__" submodule (e.g., the "bar" + # in "from foo import bar", which is either a non-ignorable + # submodule of "foo" or an ignorable global attribute of + # "foo.__init__"). + name = inst.argval + module.add_global_attr(name) + + elif inst.opname in ('DELETE_NAME', 'DELETE_GLOBAL'): + # If this is the undeclaration of a previously declared global + # attribute (e.g., class, variable) in this module, remove that + # declaration to prevent subsequent lookup. See method docstring + # for further details. + name = inst.argval + module.remove_global_attr_if_found(name) + + prev_insts.append(inst) + + + def _process_imports(self, source_module): + """ + Graph all target modules whose importations were previously parsed from + the passed source module by a prior call to the `_scan_code()` method + and methods call by that method (e.g., `_scan_ast()`, + `_scan_bytecode()`, `_scan_bytecode_stores()`). + + Parameters + ---------- + source_module : Node + Graph node of the source module to graph target imports for. + """ + + # If this source module imported no target modules, noop. + if not source_module._deferred_imports: + return + + # For each target module imported by this source module... + for have_star, import_info, kwargs in source_module._deferred_imports: + # Graph node of the target module specified by the "from" portion + # of this "from"-style star import (e.g., an import resembling + # "from {target_module_name} import *") or ignored otherwise. + target_modules = self._safe_import_hook(*import_info, **kwargs) + if not target_modules: + # If _safe_import_hook suppressed the module, quietly drop it. + # Do not create an ExcludedModule instance, because that might + # completely suppress the module whereas it might need to be + # included due to reference from another module (that does + # not exclude it via hook). + continue + target_module = target_modules[0] + + # If this is a "from"-style star import, process this import. + if have_star: + #FIXME: Sadly, the current approach to importing attributes + #from "from"-style star imports is... simplistic. This should + #be revised as follows. If this target module is: + # + #* A package: + # * Whose "__init__" submodule defines the "__all__" global + # attribute, only attributes listed by this attribute should + # be imported. + # * Else, *NO* attributes should be imported. + #* A non-package: + # * Defining the "__all__" global attribute, only attributes + # listed by this attribute should be imported. + # * Else, only public attributes whose names are *NOT* + # prefixed by "_" should be imported. + source_module.add_global_attrs_from_module(target_module) + + source_module._starimported_ignored_module_names.update( + target_module._starimported_ignored_module_names) + + # If this target module has no code object and hence is + # unparsable, record its name for posterity. + if target_module.code is None: + target_module_name = import_info[0] + source_module._starimported_ignored_module_names.add( + target_module_name) + + # For safety, prevent these imports from being reprocessed. + source_module._deferred_imports = None + + + def _find_module(self, name, path, parent=None): + """ + 3-tuple describing the physical location of the module with the passed + name if this module is physically findable _or_ raise `ImportError`. + + This high-level method wraps the low-level `modulegraph.find_module()` + function with additional support for graph-based module caching. + + Parameters + ---------- + name : str + Fully-qualified name of the Python module to be found. + path : list + List of the absolute paths of all directories to search for this + module _or_ `None` if the default path list `self.path` is to be + searched. + parent : Node + Package containing this module if this module is a submodule of a + package _or_ `None` if this is a top-level module. + + Returns + ---------- + (filename, loader) + See `modulegraph._find_module()` for details. + + Raises + ---------- + ImportError + If this module is _not_ found. + """ + + if parent is not None: + # assert path is not None + fullname = parent.identifier + '.' + name + else: + fullname = name + + node = self.find_node(fullname) + if node is not None: + self.msg(3, "find_module: already included?", node) + raise ImportError(name) + + if path is None: + if name in sys.builtin_module_names: + return (None, BUILTIN_MODULE) + + path = self.path + + return self._find_module_path(fullname, name, path) + + + def _find_module_path(self, fullname, module_name, search_dirs): + """ + 3-tuple describing the physical location of the module with the passed + name if this module is physically findable _or_ raise `ImportError`. + + This low-level function is a variant on the standard `imp.find_module()` + function with additional support for: + + * Multiple search paths. The passed list of absolute paths will be + iteratively searched for the first directory containing a file + corresponding to this module. + * Compressed (e.g., zipped) packages. + + For efficiency, the higher level `ModuleGraph._find_module()` method + wraps this function with support for module caching. + + Parameters + ---------- + module_name : str + Fully-qualified name of the module to be found. + search_dirs : list + List of the absolute paths of all directories to search for this + module (in order). Searching will halt at the first directory + containing this module. + + Returns + ---------- + (filename, loader) + 2-tuple describing the physical location of this module, where: + * `filename` is the absolute path of this file. + * `loader` is the import loader. + In case of a namespace package, this is a NAMESPACE_PACKAGE + instance + + Raises + ---------- + ImportError + If this module is _not_ found. + """ + self.msgin(4, "_find_module_path <-", fullname, search_dirs) + + # Top-level 2-tuple to be returned. + path_data = None + + # List of the absolute paths of all directories comprising the + # namespace package to which this module belongs if any. + namespace_dirs = [] + + try: + for search_dir in search_dirs: + # PEP 302-compliant importer making loaders for this directory. + importer = pkgutil.get_importer(search_dir) + + # If this directory is not importable, continue. + if importer is None: + # self.msg(4, "_find_module_path importer not found", search_dir) + continue + + # Get the PEP 302-compliant loader object loading this module. + # + # If this importer defines the PEP 451-compliant find_spec() + # method, use that, and obtain loader from spec. This should + # be available on python >= 3.4. + if hasattr(importer, 'find_spec'): + loader = None + spec = importer.find_spec(module_name) + if spec is not None: + loader = spec.loader + namespace_dirs.extend(spec.submodule_search_locations or []) + # Else if this importer defines the PEP 302-compliant find_loader() + # method, use that. + elif hasattr(importer, 'find_loader'): + loader, loader_namespace_dirs = importer.find_loader( + module_name) + namespace_dirs.extend(loader_namespace_dirs) + # Else if this importer defines the Python 2-specific + # find_module() method, fall back to that. Despite the method + # name, this method returns a loader rather than a module. + elif hasattr(importer, 'find_module'): + loader = importer.find_module(module_name) + # Else, raise an exception. + else: + raise ImportError( + "Module %r importer %r loader unobtainable" % (module_name, importer)) + + # If this module is not loadable from this directory, continue. + if loader is None: + # self.msg(4, "_find_module_path loader not found", search_dir) + continue + + # Absolute path of this module. If this module resides in a + # compressed archive, this is the absolute path of this module + # after extracting this module from that archive and hence + # should not exist; else, this path should typically exist. + pathname = None + + # If this loader defines the PEP 302-compliant get_filename() + # method, preferably call that method first. Most if not all + # loaders (including zipimporter objects) define this method. + if hasattr(loader, 'get_filename'): + pathname = loader.get_filename(module_name) + # Else if this loader provides a "path" attribute, defer to that. + elif hasattr(loader, 'path'): + pathname = loader.path + # Else, raise an exception. + else: + raise ImportError( + "Module %r loader %r path unobtainable" % (module_name, loader)) + + # If no path was found, this is probably a namespace package. In + # such case, continue collecting namespace directories. + if pathname is None: + self.msg(4, "_find_module_path path not found", pathname) + continue + + # Return such metadata. + path_data = (pathname, loader) + break + # Else if this is a namespace package, return such metadata. + else: + if namespace_dirs: + path_data = (namespace_dirs[0], + NAMESPACE_PACKAGE(namespace_dirs)) + except UnicodeDecodeError as exc: + self.msgout(1, "_find_module_path -> unicode error", exc) + # Ensure that exceptions are logged, as this function is typically + # called by the import_module() method which squelches ImportErrors. + except Exception as exc: + self.msgout(4, "_find_module_path -> exception", exc) + raise + + # If this module was not found, raise an exception. + self.msgout(4, "_find_module_path ->", path_data) + if path_data is None: + raise ImportError("No module named " + repr(module_name)) + + return path_data + + + def create_xref(self, out=None): + global header, footer, entry, contpl, contpl_linked, imports + if out is None: + out = sys.stdout + scripts = [] + mods = [] + for mod in self.iter_graph(): + name = os.path.basename(mod.identifier) + if isinstance(mod, Script): + scripts.append((name, mod)) + else: + mods.append((name, mod)) + scripts.sort() + mods.sort() + scriptnames = [sn for sn, m in scripts] + scripts.extend(mods) + mods = scripts + + title = "modulegraph cross reference for " + ', '.join(scriptnames) + print(header % {"TITLE": title}, file=out) + + def sorted_namelist(mods): + lst = [os.path.basename(mod.identifier) for mod in mods if mod] + lst.sort() + return lst + for name, m in mods: + content = "" + if isinstance(m, BuiltinModule): + content = contpl % {"NAME": name, + "TYPE": "(builtin module)"} + elif isinstance(m, Extension): + content = contpl % {"NAME": name, + "TYPE": "%s" % m.filename} + else: + url = pathname2url(m.filename or "") + content = contpl_linked % {"NAME": name, "URL": url, + 'TYPE': m.__class__.__name__} + oute, ince = map(sorted_namelist, self.get_edges(m)) + if oute: + links = [] + for n in oute: + links.append(""" %s\n""" % (n, n)) + # #8226 = bullet-point; can't use html-entities since the + # test-suite uses xml.etree.ElementTree.XMLParser, which + # does't supprot them. + links = " • ".join(links) + content += imports % {"HEAD": "imports", "LINKS": links} + if ince: + links = [] + for n in ince: + links.append(""" %s\n""" % (n, n)) + # #8226 = bullet-point; can't use html-entities since the + # test-suite uses xml.etree.ElementTree.XMLParser, which + # does't supprot them. + links = " • ".join(links) + content += imports % {"HEAD": "imported by", "LINKS": links} + print(entry % {"NAME": name, "CONTENT": content}, file=out) + print(footer, file=out) + + def itergraphreport(self, name='G', flatpackages=()): + # XXX: Can this be implemented using Dot()? + nodes = list(map(self.graph.describe_node, self.graph.iterdfs(self))) + describe_edge = self.graph.describe_edge + edges = deque() + packagenodes = set() + packageidents = {} + nodetoident = {} + inpackages = {} + mainedges = set() + + # XXX - implement + flatpackages = dict(flatpackages) + + def nodevisitor(node, data, outgoing, incoming): + if not isinstance(data, Node): + return {'label': str(node)} + #if isinstance(d, (ExcludedModule, MissingModule, BadModule)): + # return None + s = ' ' + type(data).__name__ + for i, v in enumerate(data.infoTuple()[:1], 1): + s += '| %s' % (i, v) + return {'label': s, 'shape': 'record'} + + + def edgevisitor(edge, data, head, tail): + # XXX: This method nonsense, the edge + # data is never initialized. + if data == 'orphan': + return {'style': 'dashed'} + elif data == 'pkgref': + return {'style': 'dotted'} + return {} + + yield 'digraph %s {\ncharset="UTF-8";\n' % (name,) + attr = dict(rankdir='LR', concentrate='true') + cpatt = '%s="%s"' + for item in attr.items(): + yield '\t%s;\n' % (cpatt % item,) + + # find all packages (subgraphs) + for (node, data, outgoing, incoming) in nodes: + nodetoident[node] = getattr(data, 'identifier', None) + if isinstance(data, Package): + packageidents[data.identifier] = node + inpackages[node] = set([node]) + packagenodes.add(node) + + # create sets for subgraph, write out descriptions + for (node, data, outgoing, incoming) in nodes: + # update edges + for edge in (describe_edge(e) for e in outgoing): + edges.append(edge) + + # describe node + yield '\t"%s" [%s];\n' % ( + node, + ','.join([ + (cpatt % item) for item in + nodevisitor(node, data, outgoing, incoming).items() + ]), + ) + + inside = inpackages.get(node) + if inside is None: + inside = inpackages[node] = set() + ident = nodetoident[node] + if ident is None: + continue + pkgnode = packageidents.get(ident[:ident.rfind('.')]) + if pkgnode is not None: + inside.add(pkgnode) + + graph = [] + subgraphs = {} + for key in packagenodes: + subgraphs[key] = [] + + while edges: + edge, data, head, tail = edges.popleft() + if ((head, tail)) in mainedges: + continue + mainedges.add((head, tail)) + tailpkgs = inpackages[tail] + common = inpackages[head] & tailpkgs + if not common and tailpkgs: + usepkgs = sorted(tailpkgs) + if len(usepkgs) != 1 or usepkgs[0] != tail: + edges.append((edge, data, head, usepkgs[0])) + edges.append((edge, 'pkgref', usepkgs[-1], tail)) + continue + if common: + common = common.pop() + if tail == common: + edges.append((edge, data, tail, head)) + elif head == common: + subgraphs[common].append((edge, 'pkgref', head, tail)) + else: + edges.append((edge, data, common, head)) + edges.append((edge, data, common, tail)) + + else: + graph.append((edge, data, head, tail)) + + def do_graph(edges, tabs): + edgestr = tabs + '"%s" -> "%s" [%s];\n' + # describe edge + for (edge, data, head, tail) in edges: + attribs = edgevisitor(edge, data, head, tail) + yield edgestr % ( + head, + tail, + ','.join([(cpatt % item) for item in attribs.items()]), + ) + + for g, edges in subgraphs.items(): + yield '\tsubgraph "cluster_%s" {\n' % (g,) + yield '\t\tlabel="%s";\n' % (nodetoident[g],) + for s in do_graph(edges, '\t\t'): + yield s + yield '\t}\n' + + for s in do_graph(graph, '\t'): + yield s + + yield '}\n' + + def graphreport(self, fileobj=None, flatpackages=()): + if fileobj is None: + fileobj = sys.stdout + fileobj.writelines(self.itergraphreport(flatpackages=flatpackages)) + + def report(self): + """Print a report to stdout, listing the found modules with their + paths, as well as modules that are missing, or seem to be missing. + """ + print() + print("%-15s %-25s %s" % ("Class", "Name", "File")) + print("%-15s %-25s %s" % ("-----", "----", "----")) + for m in sorted(self.iter_graph(), key=lambda n: n.identifier): + print("%-15s %-25s %s" % (type(m).__name__, m.identifier, m.filename or "")) + + def _replace_paths_in_code(self, co): + new_filename = original_filename = os.path.normpath(co.co_filename) + for f, r in self.replace_paths: + f = os.path.join(f, '') + r = os.path.join(r, '') + if original_filename.startswith(f): + new_filename = r + original_filename[len(f):] + break + + else: + return co + + consts = list(co.co_consts) + for i in range(len(consts)): + if isinstance(consts[i], type(co)): + consts[i] = self._replace_paths_in_code(consts[i]) + + code_func = type(co) + + if hasattr(co, 'replace'): # is_py38 + return co.replace(co_consts=tuple(consts), + co_filename=new_filename) + elif hasattr(co, 'co_kwonlyargcount'): + return code_func( + co.co_argcount, co.co_kwonlyargcount, co.co_nlocals, + co.co_stacksize, co.co_flags, co.co_code, + tuple(consts), co.co_names, co.co_varnames, + new_filename, co.co_name, co.co_firstlineno, + co.co_lnotab, co.co_freevars, co.co_cellvars) + else: + return code_func( + co.co_argcount, co.co_nlocals, co.co_stacksize, + co.co_flags, co.co_code, tuple(consts), co.co_names, + co.co_varnames, new_filename, co.co_name, + co.co_firstlineno, co.co_lnotab, + co.co_freevars, co.co_cellvars) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/util.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/util.py new file mode 100755 index 000000000..8b5f75428 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/util.py @@ -0,0 +1,44 @@ +import sys +import re +import inspect +import importlib.util + +from ._compat import get_instructions + + +cookie_re = re.compile(br"coding[:=]\s*([-\w.]+)") +if sys.version_info[0] == 2: + default_encoding = 'ascii' +else: + default_encoding = 'utf-8' + + +def guess_encoding(fp): + + for i in range(2): + ln = fp.readline() + + m = cookie_re.search(ln) + if m is not None: + return m.group(1).decode('ascii') + + return default_encoding + + +def iterate_instructions(code_object): + """Delivers the byte-code instructions as a continuous stream. + + Yields `dis.Instruction`. After each code-block (`co_code`), `None` is + yielded to mark the end of the block and to interrupt the steam. + """ + # The arg extension the EXTENDED_ARG opcode represents is automatically handled by get_instructions() but the + # instruction is left in. Get rid of it to make subsequent parsing easier/safer. + yield from (i for i in get_instructions(code_object) if i.opname != "EXTENDED_ARG") + + yield None + + # For each constant in this code object that is itself a code object, + # parse this constant in the same manner. + for constant in code_object.co_consts: + if inspect.iscode(constant): + yield from iterate_instructions(constant) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/zipio.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/zipio.py new file mode 100755 index 000000000..d5b76b18d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/lib/modulegraph/zipio.py @@ -0,0 +1,418 @@ +""" +A helper module that can work with paths +that can refer to data inside a zipfile + +XXX: Need to determine if isdir("zipfile.zip") +should return True or False. Currently returns +True, but that might do the wrong thing with +data-files that are zipfiles. +""" +import os as _os +import zipfile as _zipfile +import errno as _errno +import time as _time +import sys as _sys +import stat as _stat + +_DFLT_DIR_MODE = ( + _stat.S_IXOTH + | _stat.S_IXGRP + | _stat.S_IXUSR + | _stat.S_IROTH + | _stat.S_IRGRP + | _stat.S_IRUSR) + +_DFLT_FILE_MODE = ( + _stat.S_IROTH + | _stat.S_IRGRP + | _stat.S_IRUSR) + + +if _sys.version_info[0] == 2: + from StringIO import StringIO as _BaseStringIO + from StringIO import StringIO as _BaseBytesIO + + class _StringIO (_BaseStringIO): + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.close() + return False + + class _BytesIO (_BaseBytesIO): + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.close() + return False + +else: + from io import StringIO as _StringIO + from io import BytesIO as _BytesIO + + +def _locate(path): + full_path = path + if _os.path.exists(path): + return path, None + + else: + rest = [] + root = _os.path.splitdrive(path) + while path and path != root: + path, bn = _os.path.split(path) + rest.append(bn) + if _os.path.exists(path): + break + + if path == root: + raise IOError( + _errno.ENOENT, full_path, + "No such file or directory") + + if not _os.path.isfile(path): + raise IOError( + _errno.ENOENT, full_path, + "No such file or directory") + + rest.reverse() + return path, '/'.join(rest).strip('/') + + +_open = open + + +def open(path, mode='r'): + if 'w' in mode or 'a' in mode: + raise IOError( + _errno.EINVAL, path, "Write access not supported") + elif 'r+' in mode: + raise IOError( + _errno.EINVAL, path, "Write access not supported") + + full_path = path + path, rest = _locate(path) + if not rest: + return _open(path, mode) + + else: + try: + zf = _zipfile.ZipFile(path, 'r') + + except _zipfile.BadZipFile: + raise IOError( + _errno.ENOENT, full_path, + "No such file or directory") + + try: + data = zf.read(rest) + except (_zipfile.BadZipFile, KeyError): + zf.close() + raise IOError( + _errno.ENOENT, full_path, + "No such file or directory") + zf.close() + + if mode == 'rb': + return _BytesIO(data) + + else: + if _sys.version_info[0] == 3: + data = data.decode('ascii') + + return _StringIO(data) + + +def listdir(path): + full_path = path + path, rest = _locate(path) + if not rest and not _os.path.isfile(path): + return _os.listdir(path) + + else: + try: + zf = _zipfile.ZipFile(path, 'r') + + except _zipfile.BadZipFile: + raise IOError( + _errno.ENOENT, full_path, + "No such file or directory") + + result = set() + seen = False + try: + for nm in zf.namelist(): + if rest is None: + seen = True + value = nm.split('/')[0] + if value: + result.add(value) + + elif nm.startswith(rest): + if nm == rest: + seen = True + value = '' + pass + elif nm[len(rest)] == '/': + seen = True + value = nm[len(rest)+1:].split('/')[0] + else: + value = None + + if value: + result.add(value) + except _zipfile.BadZipFile: + zf.close() + raise IOError( + _errno.ENOENT, full_path, + "No such file or directory") + + zf.close() + + if not seen: + raise IOError( + _errno.ENOENT, full_path, + "No such file or directory") + + return list(result) + + +def isfile(path): + full_path = path + path, rest = _locate(path) + if not rest: + ok = _os.path.isfile(path) + if ok: + try: + zf = _zipfile.ZipFile(path, 'r') + return False + except (_zipfile.BadZipFile, IOError): + return True + return False + + zf = None + try: + zf = _zipfile.ZipFile(path, 'r') + zf.getinfo(rest) + zf.close() + return True + except (KeyError, _zipfile.BadZipFile): + if zf is not None: + zf.close() + + # Check if this is a directory + try: + zf.getinfo(rest + '/') + except KeyError: + pass + else: + return False + + rest = rest + '/' + for nm in zf.namelist(): + if nm.startswith(rest): + # Directory + return False + + # No trace in zipfile + raise IOError( + _errno.ENOENT, full_path, + "No such file or directory") + + +def isdir(path): + full_path = path + path, rest = _locate(path) + if not rest: + ok = _os.path.isdir(path) + if not ok: + try: + zf = _zipfile.ZipFile(path, 'r') + except (_zipfile.BadZipFile, IOError): + return False + return True + return True + + zf = None + try: + try: + zf = _zipfile.ZipFile(path) + except _zipfile.BadZipFile: + raise IOError( + _errno.ENOENT, full_path, + "No such file or directory") + + try: + zf.getinfo(rest) + except KeyError: + pass + else: + # File found + return False + + rest = rest + '/' + try: + zf.getinfo(rest) + except KeyError: + pass + else: + # Directory entry found + return True + + for nm in zf.namelist(): + if nm.startswith(rest): + return True + + raise IOError( + _errno.ENOENT, full_path, + "No such file or directory") + finally: + if zf is not None: + zf.close() + + +def islink(path): + full_path = path + path, rest = _locate(path) + if not rest: + return _os.path.islink(path) + + try: + zf = _zipfile.ZipFile(path) + except _zipfile.BadZipFile: + raise IOError( + _errno.ENOENT, full_path, + "No such file or directory") + try: + try: + zf.getinfo(rest) + except KeyError: + pass + else: + # File + return False + + rest += '/' + try: + zf.getinfo(rest) + except KeyError: + pass + else: + # Directory + return False + + for nm in zf.namelist(): + if nm.startswith(rest): + # Directory without listing + return False + + raise IOError( + _errno.ENOENT, full_path, + "No such file or directory") + + finally: + zf.close() + + +def readlink(path): + full_path = path + path, rest = _locate(path) + if rest: + # No symlinks inside zipfiles + raise OSError( + _errno.ENOENT, full_path, + "No such file or directory") + + return _os.readlink(path) + + +def getmode(path): + full_path = path + path, rest = _locate(path) + if not rest: + return _stat.S_IMODE(_os.stat(path).st_mode) + + zf = None + try: + zf = _zipfile.ZipFile(path) + info = None + + try: + info = zf.getinfo(rest) + except KeyError: + pass + + if info is None: + try: + info = zf.getinfo(rest + '/') + except KeyError: + pass + + if info is None: + rest = rest + '/' + for nm in zf.namelist(): + if nm.startswith(rest): + break + else: + raise IOError( + _errno.ENOENT, full_path, + "No such file or directory") + + # Directory exists, but has no entry of its own. + return _DFLT_DIR_MODE + + # The mode is stored without file-type in external_attr. + if (info.external_attr >> 16) != 0: + return _stat.S_IMODE(info.external_attr >> 16) + else: + return _DFLT_FILE_MODE + + finally: + if zf is not None: + zf.close() + + +def getmtime(path): + full_path = path + path, rest = _locate(path) + if not rest: + return _os.path.getmtime(path) + + zf = None + try: + zf = _zipfile.ZipFile(path) + info = None + + try: + info = zf.getinfo(rest) + except KeyError: + pass + + if info is None: + try: + info = zf.getinfo(rest + '/') + except KeyError: + pass + + if info is None: + rest = rest + '/' + for nm in zf.namelist(): + if nm.startswith(rest): + break + else: + raise IOError( + _errno.ENOENT, full_path, + "No such file or directory") + + # Directory exists, but has no entry of its + # own, fake mtime by using the timestamp of + # the zipfile itself. + return _os.path.getmtime(path) + + return _time.mktime(info.date_time + (0, 0, -1)) + + finally: + if zf is not None: + zf.close() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/loader/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/loader/__init__.py new file mode 100755 index 000000000..792d60054 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/loader/__init__.py @@ -0,0 +1 @@ +# diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/loader/pyiboot01_bootstrap.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/loader/pyiboot01_bootstrap.py new file mode 100755 index 000000000..778e89197 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/loader/pyiboot01_bootstrap.py @@ -0,0 +1,92 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +#-- Start bootstrap process +# Only python built-in modules can be used. + +import sys + +import pyimod02_importers + +# Extend Python import machinery by adding PEP302 importers to sys.meta_path. +pyimod02_importers.install() + +#-- Bootstrap process is complete. +# We can use other python modules (e.g. os) + +import os # noqa: E402 + +# Let other python modules know that the code is running in frozen mode. +if not hasattr(sys, 'frozen'): + sys.frozen = True + +# sys._MEIPASS is now set in the bootloader. Hooray. + +# Python 3 C-API function Py_SetPath() resets sys.prefix to empty string. Python 2 was using PYTHONHOME for sys.prefix. +# Let's do the same for Python 3. +sys.prefix = sys._MEIPASS +sys.exec_prefix = sys.prefix + +# Python 3.3+ defines also sys.base_prefix. Let's set them too. +sys.base_prefix = sys.prefix +sys.base_exec_prefix = sys.exec_prefix + +# Some packages behave differently when running inside virtual environment. E.g., IPython tries to append path +# VIRTUAL_ENV to sys.path. For the frozen app we want to prevent this behavior. +VIRTENV = 'VIRTUAL_ENV' +if VIRTENV in os.environ: + # On some platforms (e.g., AIX) 'os.unsetenv()' is unavailable and deleting the var from os.environ does not + # delete it from the environment. + os.environ[VIRTENV] = '' + del os.environ[VIRTENV] + +# Ensure sys.path contains absolute paths. Otherwise, import of other python modules will fail when current working +# directory is changed by the frozen application. +python_path = [] +for pth in sys.path: + python_path.append(os.path.abspath(pth)) + sys.path = python_path + +# At least on Windows, Python seems to hook up the codecs on this import, so it is not enough to just package up all +# the encodings. +# +# It was also reported that without 'encodings' module, the frozen executable fails to load in some configurations: +# http://www.pyinstaller.org/ticket/651 +# +# Importing 'encodings' module in a run-time hook is not enough, since some run-time hooks require this module, and the +# order of running the code from the run-time hooks is not defined. +try: + import encodings # noqa: F401 +except ImportError: + pass + +# In the Python interpreter 'warnings' module is imported when 'sys.warnoptions' is not empty. Mimic this behavior. +if sys.warnoptions: + import warnings # noqa: F401 + +# Install the hooks for ctypes +import pyimod03_ctypes # noqa: E402 + +pyimod03_ctypes.install() + +# Install the hooks for pywin32 (Windows only) +if sys.platform.startswith('win'): + import pyimod04_pywin32 + pyimod04_pywin32.install() + +# Make .eggs and zipfiles available at runtime +d = "eggs" +d = os.path.join(sys._MEIPASS, d) +# Test if the 'eggs' directory exists. This allows us to opportunistically include this script into the packaged exe, +# even if no eggs were found when packaging the program. (Which may be a use-case, see issue #653). +if os.path.isdir(d): + for fn in os.listdir(d): + sys.path.append(os.path.join(d, fn)) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/loader/pyimod01_archive.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/loader/pyimod01_archive.py new file mode 100755 index 000000000..f3ceea3c1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/loader/pyimod01_archive.py @@ -0,0 +1,203 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# **NOTE** This module is used during bootstrap. +# Import *ONLY* builtin modules or modules that are collected into the base_library.zip archive. +# List of built-in modules: sys.builtin_module_names +# List of modules collected into base_library.zip: PyInstaller.compat.PY3_BASE_MODULES + +import sys +import os +import struct +import marshal +import zlib + +# In Python3, the MAGIC_NUMBER value is available in the importlib module. However, in the bootstrap phase we cannot use +# importlib directly, but rather its frozen variant. +import _frozen_importlib + +PYTHON_MAGIC_NUMBER = _frozen_importlib._bootstrap_external.MAGIC_NUMBER + +# For decrypting Python modules. +CRYPT_BLOCK_SIZE = 16 + +# Type codes for PYZ PYZ entries +PYZ_ITEM_MODULE = 0 +PYZ_ITEM_PKG = 1 +PYZ_ITEM_DATA = 2 +PYZ_ITEM_NSPKG = 3 # PEP-420 namespace package + + +class ArchiveReadError(RuntimeError): + pass + + +class Cipher: + """ + This class is used only to decrypt Python modules. + """ + def __init__(self): + # At build-time the key is given to us from inside the spec file. At bootstrap-time, we must look for it + # ourselves, by trying to import the generated 'pyi_crypto_key' module. + import pyimod00_crypto_key + key = pyimod00_crypto_key.key + + assert type(key) is str + if len(key) > CRYPT_BLOCK_SIZE: + self.key = key[0:CRYPT_BLOCK_SIZE] + else: + self.key = key.zfill(CRYPT_BLOCK_SIZE) + assert len(self.key) == CRYPT_BLOCK_SIZE + + import tinyaes + self._aesmod = tinyaes + # Issue #1663: Remove the AES module from sys.modules list. Otherwise it interferes with using 'tinyaes' module + # in users' code. + del sys.modules['tinyaes'] + + def __create_cipher(self, iv): + # The 'AES' class is stateful, and this factory method is used to re-initialize the block cipher class with + # each call to xcrypt(). + return self._aesmod.AES(self.key.encode(), iv) + + def decrypt(self, data): + cipher = self.__create_cipher(data[:CRYPT_BLOCK_SIZE]) + return cipher.CTR_xcrypt_buffer(data[CRYPT_BLOCK_SIZE:]) + + +class ZlibArchiveReader: + """ + Reader for PyInstaller's PYZ (ZlibArchive) archive. The archive is used to store collected byte-compiled Python + modules, as individually-compressed entries. + """ + _PYZ_MAGIC_PATTERN = b'PYZ\0' + + def __init__(self, filename, start_offset=None, check_pymagic=False): + self._filename = filename + self._start_offset = start_offset + + self.toc = {} + + self.cipher = None + + # Try to create Cipher() instance; if encryption is not enabled, pyimod00_crypto_key is not available, and + # instantiation fails with ImportError. + try: + self.cipher = Cipher() + except ImportError: + pass + + # If no offset is given, try inferring it from filename + if start_offset is None: + self._filename, self._start_offset = self._parse_offset_from_filename(filename) + + # Parse header and load TOC. Standard header contains 12 bytes: PYZ magic pattern, python bytecode magic + # pattern, and offset to TOC (32-bit integer). It might be followed by additional fields, depending on + # implementation version. + with open(self._filename, "rb") as fp: + # Read PYZ magic pattern, located at the start of the file + fp.seek(self._start_offset, os.SEEK_SET) + + magic = fp.read(len(self._PYZ_MAGIC_PATTERN)) + if magic != self._PYZ_MAGIC_PATTERN: + raise ArchiveReadError("PYZ magic pattern mismatch!") + + # Read python magic/version number + pymagic = fp.read(len(PYTHON_MAGIC_NUMBER)) + if check_pymagic and pymagic != PYTHON_MAGIC_NUMBER: + raise ArchiveReadError("Python magic pattern mismatch!") + + # Read TOC offset + toc_offset, *_ = struct.unpack('!i', fp.read(4)) + + # Load TOC + fp.seek(self._start_offset + toc_offset, os.SEEK_SET) + self.toc = dict(marshal.load(fp)) + + @staticmethod + def _parse_offset_from_filename(filename): + """ + Parse the numeric offset from filename, stored as: `/path/to/file?offset`. + """ + offset = 0 + + idx = filename.rfind('?') + if idx == -1: + return filename, offset + + try: + offset = int(filename[idx + 1:]) + filename = filename[:idx] # Remove the offset from filename + except ValueError: + # Ignore spurious "?" in the path (for example, like in Windows UNC \\?\). + pass + + return filename, offset + + def is_package(self, name): + """ + Check if the given name refers to a package entry. Used by PyiFrozenImporter at runtime. + """ + entry = self.toc.get(name) + if entry is None: + return False + typecode, entry_offset, entry_length = entry + return typecode in (PYZ_ITEM_PKG, PYZ_ITEM_NSPKG) + + def is_pep420_namespace_package(self, name): + """ + Check if the given name refers to a namespace package entry. Used by PyiFrozenImporter at runtime. + """ + entry = self.toc.get(name) + if entry is None: + return False + typecode, entry_offset, entry_length = entry + return typecode == PYZ_ITEM_NSPKG + + def extract(self, name, raw=False): + """ + Extract data from entry with the given name. + + If the entry belongs to a module or a package, the data is loaded (unmarshaled) into code object. To retrieve + raw data, set `raw` flag to True. + """ + # Look up entry + entry = self.toc.get(name) + if entry is None: + return None + typecode, entry_offset, entry_length = entry + + # Read data blob + try: + with open(self._filename, "rb") as fp: + fp.seek(self._start_offset + entry_offset) + obj = fp.read(entry_length) + except FileNotFoundError: + # We open the archive file each time we need to read from it, to avoid locking the file by keeping it open. + # This allows executable to be deleted or moved (renamed) while it is running, which is useful in certain + # scenarios (e.g., automatic update that replaces the executable). The caveat is that once the executable is + # renamed, we cannot read from its embedded PYZ archive anymore. In such case, exit with informative + # message. + raise SystemExit( + f"{self._filename} appears to have been moved or deleted since this application was launched. " + "Continouation from this state is impossible. Exiting now." + ) + + try: + if self.cipher: + obj = self.cipher.decrypt(obj) + obj = zlib.decompress(obj) + if typecode in (PYZ_ITEM_MODULE, PYZ_ITEM_PKG, PYZ_ITEM_NSPKG) and not raw: + obj = marshal.loads(obj) + except EOFError as e: + raise ImportError(f"Failed to unmarshal PYZ entry {name!r}!") from e + + return obj diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/loader/pyimod02_importers.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/loader/pyimod02_importers.py new file mode 100755 index 000000000..f35a166ad --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/loader/pyimod02_importers.py @@ -0,0 +1,541 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +PEP-302 and PEP-451 importers for frozen applications. +""" + +# **NOTE** This module is used during bootstrap. +# Import *ONLY* builtin modules or modules that are collected into the base_library.zip archive. +# List of built-in modules: sys.builtin_module_names +# List of modules collected into base_library.zip: PyInstaller.compat.PY3_BASE_MODULES + +import sys +import os +import pathlib +import io +import tokenize + +import _frozen_importlib + +from pyimod01_archive import ArchiveReadError, ZlibArchiveReader + +SYS_PREFIX = sys._MEIPASS + os.sep +SYS_PREFIXLEN = len(SYS_PREFIX) + +# In Python 3, it is recommended to use class 'types.ModuleType' to create a new module. However, 'types' module is +# not a built-in module. The 'types' module uses this trick with using type() function: +imp_new_module = type(sys) + +if sys.flags.verbose and sys.stderr: + + def trace(msg, *a): + sys.stderr.write(msg % a) + sys.stderr.write("\n") +else: + + def trace(msg, *a): + pass + + +def _decode_source(source_bytes): + """ + Decode bytes representing source code and return the string. Universal newline support is used in the decoding. + Based on CPython's implementation of the same functionality: + https://github.com/python/cpython/blob/3.9/Lib/importlib/_bootstrap_external.py#L679-L688 + """ + source_bytes_readline = io.BytesIO(source_bytes).readline + encoding = tokenize.detect_encoding(source_bytes_readline) + newline_decoder = io.IncrementalNewlineDecoder(decoder=None, translate=True) + return newline_decoder.decode(source_bytes.decode(encoding[0])) + + +class PyiFrozenImporterState: + """ + An object encapsulating extra information for PyiFrozenImporter, to be stored in `ModuleSpec.loader_state`. Having + a custom type allows us to verify that module spec indeed contains the original loader state data, as set by + `PyiFrozenImporter.find_spec`. + """ + def __init__(self, entry_name): + # Module name, as recorded in the PYZ archive. + self.pyz_entry_name = entry_name + + +class PyiFrozenImporter: + """ + Load bytecode of Python modules from the executable created by PyInstaller. + + Python bytecode is zipped and appended to the executable. + + NOTE: PYZ format cannot be replaced by zipimport module. + + The problem is that we have no control over zipimport; for instance, it does not work if the zip file is embedded + into a PKG that is appended to an executable, like we create in one-file mode. + + This used to be PEP-302 finder and loader class for the ``sys.meta_path`` hook. A PEP-302 finder requires method + find_module() to return loader class with method load_module(). However, both of these methods were deprecated in + python 3.4 by PEP-451 (see below). Therefore, this class now provides only optional extensions to the PEP-302 + importer protocol. + + This is also a PEP-451 finder and loader class for the ModuleSpec type import system. A PEP-451 finder requires + method find_spec(), a PEP-451 loader requires methods exec_module(), load_module() and (optionally) create_module(). + All these methods are implemented in this one class. + """ + def __init__(self): + """ + Load, unzip and initialize the Zip archive bundled with the executable. + """ + # Examine all items in sys.path and the one like /path/executable_name?117568 is the correct executable with + # the bundled zip archive. Use this value for the ZlibArchiveReader class, and remove this item from sys.path. + # It was needed only for PyiFrozenImporter class. Wrong path from sys.path raises an ArchiveReadError exception. + for pyz_filepath in sys.path: + try: + # Unzip zip archive bundled with the executable. + self._pyz_archive = ZlibArchiveReader(pyz_filepath, check_pymagic=True) + # Verify the integrity of the zip archive with Python modules. + # This is already done when creating the ZlibArchiveReader instance. + #self._pyz_archive.checkmagic() + + # As no Exception was raised, we can assume that ZlibArchiveReader was successfully loaded. + # Let's remove 'pyz_filepath' from sys.path. + sys.path.remove(pyz_filepath) + # Some runtime hook might need access to the list of available frozen modules. Let's make them + # accessible as a set(). + self.toc = set(self._pyz_archive.toc.keys()) + # Return - no error was raised. + trace("# PyInstaller: PyiFrozenImporter(%s)", pyz_filepath) + return + except IOError: + # Item from sys.path is not ZlibArchiveReader; let's try next one. + continue + except ArchiveReadError: + # Item from sys.path is not ZlibArchiveReader; let's try next one. + continue + # sys.path does not contain the filename of the executable with the bundled zip archive. Raise import error. + raise ImportError("Cannot load frozen modules.") + + # Private helper + def _is_pep420_namespace_package(self, fullname): + if fullname in self.toc: + try: + return self._pyz_archive.is_pep420_namespace_package(fullname) + except Exception as e: + raise ImportError(f'PyiFrozenImporter cannot handle module {fullname!r}') from e + else: + raise ImportError(f'PyiFrozenImporter cannot handle module {fullname!r}') + + #-- Optional Extensions to the PEP-302 Importer Protocol -- + + def is_package(self, fullname): + if fullname in self.toc: + try: + return self._pyz_archive.is_package(fullname) + except Exception as e: + raise ImportError(f'PyiFrozenImporter cannot handle module {fullname!r}') from e + else: + raise ImportError(f'PyiFrozenImporter cannot handle module {fullname!r}') + + def get_code(self, fullname): + """ + Get the code object associated with the module. + + ImportError should be raised if module not found. + """ + try: + if fullname == '__main__': + # Special handling for __main__ module; the bootloader should store code object to _pyi_main_co + # attribute of the module. + return sys.modules['__main__']._pyi_main_co + + # extract() returns None if fullname is not in the archive, and the subsequent subscription attempt raises + # exception, which is turned into ImportError. + return self._pyz_archive.extract(fullname) + except Exception as e: + raise ImportError(f'PyiFrozenImporter cannot handle module {fullname!r}') from e + + def get_source(self, fullname): + """ + Method should return the source code for the module as a string. + But frozen modules does not contain source code. + + Return None, unless the corresponding source file was explicitly collected to the filesystem. + """ + if fullname in self.toc: + # Try loading the .py file from the filesystem (only for collected modules) + if self.is_package(fullname): + fullname += '.__init__' + filename = os.path.join(SYS_PREFIX, fullname.replace('.', os.sep) + '.py') + try: + # Read in binary mode, then decode + with open(filename, 'rb') as fp: + source_bytes = fp.read() + return _decode_source(source_bytes) + except FileNotFoundError: + pass + return None + else: + # ImportError should be raised if module not found. + raise ImportError('No module named ' + fullname) + + def get_data(self, path): + """ + Returns the data as a string, or raises IOError if the "file" was not found. The data is always returned as if + "binary" mode was used. + + This method is useful for getting resources with 'pkg_resources' that are bundled with Python modules in the + PYZ archive. + + The 'path' argument is a path that can be constructed by munging module.__file__ (or pkg.__path__ items). + """ + assert path.startswith(SYS_PREFIX) + fullname = path[SYS_PREFIXLEN:] + if fullname in self.toc: + # If the file is in the archive, return this + return self._pyz_archive.extract(fullname) + else: + # Otherwise try to fetch it from the filesystem. Since __file__ attribute works properly, just try to open + # and read it. + with open(path, 'rb') as fp: + return fp.read() + + def get_filename(self, fullname): + """ + This method should return the value that __file__ would be set to if the named module was loaded. If the module + is not found, an ImportError should be raised. + """ + # The absolute absolute path to the executable is taken from sys.prefix. In onefile mode it points to the temp + # directory where files are unpacked by PyInstaller. Then, append the appropriate suffix (__init__.pyc for a + # package, or just .pyc for a module). + # Method is_package() will raise ImportError if module not found. + if self.is_package(fullname): + filename = os.path.join(SYS_PREFIX, fullname.replace('.', os.path.sep), '__init__.pyc') + else: + filename = os.path.join(SYS_PREFIX, fullname.replace('.', os.path.sep) + '.pyc') + return filename + + def find_spec(self, fullname, path=None, target=None): + """ + PEP-451 finder.find_spec() method for the ``sys.meta_path`` hook. + + fullname fully qualified name of the module + path None for a top-level module, or package.__path__ for + submodules or subpackages. + target unused by this Finder + + Finders are still responsible for identifying, and typically creating, the loader that should be used to load a + module. That loader will now be stored in the module spec returned by find_spec() rather than returned directly. + As is currently the case without the PEP-452, if a loader would be costly to create, that loader can be designed + to defer the cost until later. + + Finders must return ModuleSpec objects when find_spec() is called. This new method replaces find_module() and + find_loader() (in the PathEntryFinder case). If a loader does not have find_spec(), find_module() and + find_loader() are used instead, for backward-compatibility. + """ + entry_name = None # None means - no module found in this importer. + + # Try to handle module.__path__ modifications by the modules themselves. This needs to be done first in + # order to support module overrides in alternative locations while we also have the original module + # available at non-override location. + if path is not None: + # Reverse the fake __path__ we added to the package module into a dotted module name, and add the tail + # module from fullname onto that to synthesize a new fullname. + modname = fullname.rsplit('.')[-1] + + for p in path: + if not p.startswith(SYS_PREFIX): + continue + p = p[SYS_PREFIXLEN:] + parts = p.split(os.sep) + if not parts: + continue + if not parts[0]: + parts = parts[1:] + parts.append(modname) + entry_name = ".".join(parts) + if entry_name in self.toc: + trace("import %s as %s # PyInstaller PYZ (__path__ override: %s)", entry_name, fullname, p) + break + else: + entry_name = None + + if entry_name is None: + # Either there was no path override, or the module was not available there. Check the fully qualified name + # of the module directly. + if fullname in self.toc: + entry_name = fullname + trace("import %s # PyInstaller PYZ", fullname) + + if entry_name is None: + trace("# %s not found in PYZ", fullname) + return None + + if self._is_pep420_namespace_package(entry_name): + # PEP-420 namespace package; as per PEP 451, we need to return a spec with "loader" set to None + # (a.k.a. not set) + spec = _frozen_importlib.ModuleSpec(fullname, None, is_package=True) + # Set submodule_search_locations, which seems to fill the __path__ attribute. + spec.submodule_search_locations = [os.path.dirname(self.get_filename(entry_name))] + return spec + + # origin has to be the filename + origin = self.get_filename(entry_name) + is_pkg = self.is_package(entry_name) + + spec = _frozen_importlib.ModuleSpec( + fullname, + self, + is_package=is_pkg, + origin=origin, + # Provide the entry_name (name of module entry in the PYZ) for the loader to use during loading. + loader_state=PyiFrozenImporterState(entry_name) + ) + + # Make the import machinery set __file__. + # PEP 451 says: "has_location" is true if the module is locatable. In that case the spec's origin is used + # as the location and __file__ is set to spec.origin. If additional location information is required + # (e.g., zipimport), that information may be stored in spec.loader_state. + spec.has_location = True + + # Set submodule_search_locations for packages. Seems to be required for importlib_resources from 3.2.0; + # see issue #5395. + if is_pkg: + spec.submodule_search_locations = [os.path.dirname(self.get_filename(entry_name))] + + return spec + + def create_module(self, spec): + """ + PEP-451 loader.create_module() method for the ``sys.meta_path`` hook. + + Loaders may also implement create_module() that will return a new module to exec. It may return None to indicate + that the default module creation code should be used. One use case, though atypical, for create_module() is to + provide a module that is a subclass of the builtin module type. Most loaders will not need to implement + create_module(). + + create_module() should properly handle the case where it is called more than once for the same spec/module. This + may include returning None or raising ImportError. + """ + # Contrary to what is defined in PEP-451, this method is not optional. We want the default results, so we simply + # return None (which is handled for su my the import machinery). + # See https://bugs.python.org/issue23014 for more information. + return None + + def exec_module(self, module): + """ + PEP-451 loader.exec_module() method for the ``sys.meta_path`` hook. + + Loaders will have a new method, exec_module(). Its only job is to "exec" the module and consequently populate + the module's namespace. It is not responsible for creating or preparing the module object, nor for any cleanup + afterward. It has no return value. exec_module() will be used during both loading and reloading. + + exec_module() should properly handle the case where it is called more than once. For some kinds of modules this + may mean raising ImportError every time after the first time the method is called. This is particularly relevant + for reloading, where some kinds of modules do not support in-place reloading. + """ + spec = module.__spec__ + + if isinstance(spec.loader_state, PyiFrozenImporterState): + # Use the module name stored in the `loader_state`, which was set by our `find_spec()` implementation. + # This is necessary to properly resolve aliased modules; for example, `module.__spec__.name` contains + # `pkg_resources.extern.jaraco.text`, but the original name stored in `loader_state`, which we need + # to use for code look-up, is `pkg_resources._vendor.jaraco.text`. + module_name = spec.loader_state.pyz_entry_name + elif isinstance(spec.loader_state, dict): + # This seems to happen when `importlib.util.LazyLoader` is used, and our original `loader_state` is lost. + # We could use `spec.name` and hope for the best, but that will likely fail with aliased modules (see + # the comment in the branch above for an example). + # + # So try to reconstruct the original module name from the `origin` - which is essentially the reverse of + # our `get_filename()` implementation. + assert spec.origin.startswith(SYS_PREFIX) + module_name = spec.origin[SYS_PREFIXLEN:].replace(os.sep, '.') + if module_name.endswith('.pyc'): + module_name = module_name[:-4] + if module_name.endswith('.__init__'): + module_name = module_name[:-9] + else: + raise RuntimeError(f"Module's spec contains loader_state of incompatible type: {type(spec.loader_state)}") + + bytecode = self.get_code(module_name) + if bytecode is None: + raise RuntimeError(f"Failed to retrieve bytecode for {spec.name!r}!") + + # Set by the import machinery + assert hasattr(module, '__file__') + + # If `submodule_search_locations` is not None, this is a package; set __path__. + if spec.submodule_search_locations is not None: + # Since PYTHONHOME is set in bootloader, 'sys.prefix' points to the correct path where PyInstaller should + # find bundled dynamic libraries. In one-file mode it points to the tmp directory where bundled files are + # extracted at execution time. + # + # __path__ cannot be empty list because 'wx' module prepends something to it. It cannot contain value + # 'sys.prefix' because 'xml.etree.cElementTree' fails otherwise. + # + # Set __path__ to point to 'sys.prefix/package/subpackage'. + module.__path__ = [os.path.dirname(module.__file__)] + + exec(bytecode, module.__dict__) + + def get_resource_reader(self, fullname): + """ + Return importlib.resource-compatible resource reader. + """ + return PyiFrozenResourceReader(self, fullname) + + +class PyiFrozenResourceReader: + """ + Resource reader for importlib.resources / importlib_resources support. + + Currently supports only on-disk resources (support for resources from the embedded archive is missing). + However, this should cover the typical use cases (access to data files), as PyInstaller collects data files onto + filesystem, and only .pyc modules are collected into embedded archive. One exception are resources collected from + zipped eggs (which end up collected into embedded archive), but those should be rare anyway. + + When listing resources, source .py files will not be listed as they are not collected by default. Similarly, + sub-directories that contained only .py files are not reconstructed on filesystem, so they will not be listed, + either. If access to .py files is required for whatever reason, they need to be explicitly collected as data files + anyway, which will place them on filesystem and make them appear as resources. + + For on-disk resources, we *must* return path compatible with pathlib.Path() in order to avoid copy to a temporary + file, which might break under some circumstances, e.g., metpy with importlib_resources back-port, due to: + https://github.com/Unidata/MetPy/blob/a3424de66a44bf3a92b0dcacf4dff82ad7b86712/src/metpy/plots/wx_symbols.py#L24-L25 + (importlib_resources tries to use 'fonts/wx_symbols.ttf' as a temporary filename suffix, which fails as it contains + a separator). + + Furthermore, some packages expect files() to return either pathlib.Path or zipfile.Path, e.g., + https://github.com/tensorflow/datasets/blob/master/tensorflow_datasets/core/utils/resource_utils.py#L81-L97 + This makes implementation of mixed support for on-disk and embedded resources using importlib.abc.Traversable + protocol rather difficult. + + So in order to maximize compatibility with unfrozen behavior, the below implementation is basically equivalent of + importlib.readers.FileReader from python 3.10: + https://github.com/python/cpython/blob/839d7893943782ee803536a47f1d4de160314f85/Lib/importlib/readers.py#L11 + and its underlying classes, importlib.abc.TraversableResources and importlib.abc.ResourceReader: + https://github.com/python/cpython/blob/839d7893943782ee803536a47f1d4de160314f85/Lib/importlib/abc.py#L422 + https://github.com/python/cpython/blob/839d7893943782ee803536a47f1d4de160314f85/Lib/importlib/abc.py#L312 + """ + def __init__(self, importer, name): + self.importer = importer + self.path = pathlib.Path(sys._MEIPASS).joinpath(*name.split('.')) + + def open_resource(self, resource): + return self.files().joinpath(resource).open('rb') + + def resource_path(self, resource): + return str(self.path.joinpath(resource)) + + def is_resource(self, path): + return self.files().joinpath(path).is_file() + + def contents(self): + return (item.name for item in self.files().iterdir()) + + def files(self): + return self.path + + +def install(): + """ + Install PyiFrozenImporter class into the import machinery. + + This function installs the PyiFrozenImporter class into the import machinery of the running process. The importer + is added to sys.meta_path. It could be added to sys.path_hooks, but sys.meta_path is processed by Python before + looking at sys.path! + + The order of processing import hooks in sys.meta_path: + + 1. built-in modules + 2. modules from the bundled ZIP archive + 3. C extension modules + 4. Modules from sys.path + """ + # Ensure Python looks in the bundled zip archive for modules before any other places. + importer = PyiFrozenImporter() + sys.meta_path.append(importer) + + # On Windows there is importer _frozen_importlib.WindowsRegistryFinder that looks for Python modules in Windows + # registry. The frozen executable should not look for anything in the Windows registry. Remove this importer + # from sys.meta_path. + for item in sys.meta_path: + if hasattr(item, '__name__') and item.__name__ == 'WindowsRegistryFinder': + sys.meta_path.remove(item) + break + # _frozen_importlib.PathFinder is also able to handle Python C extensions. However, PyInstaller needs its own + # importer as it uses extension names like 'module.submodle.so' (instead of paths). As of Python 3.7.0b2, there + # are several PathFinder instances (and duplicate ones) on sys.meta_path. This propobly is a bug, see + # https://bugs.python.org/issue33128. Thus we need to move all of them to the end, and eliminate the duplicates. + path_finders = [] + for item in reversed(sys.meta_path): + if getattr(item, '__name__', None) == 'PathFinder': + sys.meta_path.remove(item) + if item not in path_finders: + path_finders.append(item) + sys.meta_path.extend(reversed(path_finders)) + # TODO: do we need _frozen_importlib.FrozenImporter in Python 3? Could it be also removed? + + # Set the FrozenImporter as loader for __main__, in order for python to treat __main__ as a module instead of + # a built-in. + try: + sys.modules['__main__'].__loader__ = importer + except Exception: + pass + + # Apply hack for python >= 3.11 and its frozen stdlib modules. + if sys.version_info >= (3, 11): + _fixup_frozen_stdlib() + + +# A hack for python >= 3.11 and its frozen stdlib modules. Unless `sys._stdlib_dir` is set, these modules end up +# missing __file__ attribute, which causes problems with 3rd party code. At the time of writing, python interpreter +# configuration API does not allow us to influence `sys._stdlib_dir` - it always resets it to `None`. Therefore, +# we manually set the path, and fix __file__ attribute on modules. +def _fixup_frozen_stdlib(): + import _imp # built-in + + # If sys._stdlib_dir is None or empty, override it with sys._MEIPASS + if not sys._stdlib_dir: + try: + sys._stdlib_dir = sys._MEIPASS + except AttributeError: + pass + + # The sys._stdlib_dir set above should affect newly-imported python-frozen modules. However, most of them have + # been already imported during python initialization and our bootstrap, so we need to retroactively fix their + # __file__ attribute. + for module_name, module in sys.modules.items(): + if not _imp.is_frozen(module_name): + continue + + is_pkg = _imp.is_frozen_package(module_name) + + # Determine "real" name from __spec__.loader_state. + loader_state = module.__spec__.loader_state + + orig_name = loader_state.origname + if is_pkg: + orig_name += '.__init__' + + # We set suffix to .pyc to be consistent with out PyiFrozenImporter. + filename = os.path.join(sys._MEIPASS, *orig_name.split('.')) + '.pyc' + + # Fixup the __file__ attribute + if not hasattr(module, '__file__'): + try: + module.__file__ = filename + except AttributeError: + pass + + # Fixup the loader_state.filename + # Except for _frozen_importlib (importlib._bootstrap), whose loader_state.filename appears to be left at + # None in python. + if loader_state.filename is None and orig_name != 'importlib._bootstrap': + loader_state.filename = filename diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/loader/pyimod03_ctypes.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/loader/pyimod03_ctypes.py new file mode 100755 index 000000000..3ade7ddb0 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/loader/pyimod03_ctypes.py @@ -0,0 +1,131 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- +""" +Hooks to make ctypes.CDLL, .PyDLL, etc. look in sys._MEIPASS first. +""" + +import sys + + +def install(): + """ + Install the hooks. + + This must be done from a function as opposed to at module-level, because when the module is imported/executed, + the import machinery is not completely set up yet. + """ + + import os + + try: + import ctypes + except ImportError: + # ctypes is not included in the frozen application + return + + def _frozen_name(name): + # If the given (file)name does not exist, fall back to searching for its basename in sys._MEIPASS, where + # PyInstaller usually collects shared libraries. + if name and not os.path.isfile(name): + frozen_name = os.path.join(sys._MEIPASS, os.path.basename(name)) + if os.path.isfile(frozen_name): + name = frozen_name + return name + + class PyInstallerImportError(OSError): + def __init__(self, name): + self.msg = ( + "Failed to load dynlib/dll %r. Most likely this dynlib/dll was not found when the application " + "was frozen." % name + ) + self.args = (self.msg,) + + class PyInstallerCDLL(ctypes.CDLL): + def __init__(self, name, *args, **kwargs): + name = _frozen_name(name) + try: + super().__init__(name, *args, **kwargs) + except Exception as base_error: + raise PyInstallerImportError(name) from base_error + + ctypes.CDLL = PyInstallerCDLL + ctypes.cdll = ctypes.LibraryLoader(PyInstallerCDLL) + + class PyInstallerPyDLL(ctypes.PyDLL): + def __init__(self, name, *args, **kwargs): + name = _frozen_name(name) + try: + super().__init__(name, *args, **kwargs) + except Exception as base_error: + raise PyInstallerImportError(name) from base_error + + ctypes.PyDLL = PyInstallerPyDLL + ctypes.pydll = ctypes.LibraryLoader(PyInstallerPyDLL) + + if sys.platform.startswith('win'): + + class PyInstallerWinDLL(ctypes.WinDLL): + def __init__(self, name, *args, **kwargs): + name = _frozen_name(name) + try: + super().__init__(name, *args, **kwargs) + except Exception as base_error: + raise PyInstallerImportError(name) from base_error + + ctypes.WinDLL = PyInstallerWinDLL + ctypes.windll = ctypes.LibraryLoader(PyInstallerWinDLL) + + class PyInstallerOleDLL(ctypes.OleDLL): + def __init__(self, name, *args, **kwargs): + name = _frozen_name(name) + try: + super().__init__(name, *args, **kwargs) + except Exception as base_error: + raise PyInstallerImportError(name) from base_error + + ctypes.OleDLL = PyInstallerOleDLL + ctypes.oledll = ctypes.LibraryLoader(PyInstallerOleDLL) + + try: + import ctypes.util + except ImportError: + # ctypes.util is not included in the frozen application + return + + # Same implementation as ctypes.util.find_library, except it prepends sys._MEIPASS to the search directories. + def pyinstaller_find_library(name): + if name in ('c', 'm'): + return ctypes.util.find_msvcrt() + # See MSDN for the REAL search order. + search_dirs = [sys._MEIPASS] + os.environ['PATH'].split(os.pathsep) + for directory in search_dirs: + fname = os.path.join(directory, name) + if os.path.isfile(fname): + return fname + if fname.lower().endswith(".dll"): + continue + fname = fname + ".dll" + if os.path.isfile(fname): + return fname + return None + + ctypes.util.find_library = pyinstaller_find_library + + +# On Mac OS insert sys._MEIPASS in the first position of the list of paths that ctypes uses to search for libraries. +# +# Note: 'ctypes' module will NOT be bundled with every app because code in this module is not scanned for module +# dependencies. It is safe to wrap 'ctypes' module into 'try/except ImportError' block. +if sys.platform.startswith('darwin'): + try: + from ctypes.macholib import dyld + dyld.DEFAULT_LIBRARY_FALLBACK.insert(0, sys._MEIPASS) + except ImportError: + # Do nothing when module 'ctypes' is not available. + pass diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/loader/pyimod04_pywin32.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/loader/pyimod04_pywin32.py new file mode 100755 index 000000000..ff73c5213 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/loader/pyimod04_pywin32.py @@ -0,0 +1,58 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +#----------------------------------------------------------------------------- +""" +Set search path for pywin32 DLLs. Due to the large number of pywin32 modules, we use a single loader-level script +instead of per-module runtime hook scripts. +""" + +import os +import sys + + +def install(): + # Sub-directories containing extensions. In original python environment, these are added to `sys.path` by the + # `pywin32.pth` so the extensions end up treated as top-level modules. We attempt to preserve the directory + # layout, so we need to add these directories to `sys.path` ourselves. + pywin32_ext_paths = ('win32', 'pythonwin') + pywin32_ext_paths = [os.path.join(sys._MEIPASS, pywin32_ext_path) for pywin32_ext_path in pywin32_ext_paths] + pywin32_ext_paths = [path for path in pywin32_ext_paths if os.path.isdir(path)] + sys.path.extend(pywin32_ext_paths) + + # Additional handling of `pywin32_system32` DLL directory + pywin32_system32_path = os.path.join(sys._MEIPASS, 'pywin32_system32') + + if not os.path.isdir(pywin32_system32_path): + # Either pywin32 is not collected, or we are dealing with version that does not use the pywin32_system32 + # sub-directory. In the latter case, the pywin32 DLLs should be in `sys._MEIPASS`, and nothing + # else needs to be done here. + return + + # Add the DLL directory to `sys.path`. + # This is necessary because `__import_pywin32_system_module__` from `pywintypes` module assumes that in a frozen + # application, the pywin32 DLLs (`pythoncom3X.dll` and `pywintypes3X.dll`) that are normally found in + # `pywin32_system32` sub-directory in `sys.path` (site-packages, really) are located directly in `sys.path`. + # This obviously runs afoul of our attempts at preserving the directory layout and placing them in the + # `pywin32_system32` sub-directory instead of the top-level application directory. + sys.path.append(pywin32_system32_path) + + # Add the DLL directory to DLL search path using os.add_dll_directory(), if available (python >= 3.8). + # This allows extensions from win32 directory (e.g., win32api, win32crypt) to be loaded on their own without + # importing pywintypes first. The extensions are linked against pywintypes3X.dll. + if hasattr(os, 'add_dll_directory'): + os.add_dll_directory(pywin32_system32_path) + + # Add the DLL directory to PATH. + # This is necessary on python 3.7 that lacks `os.add_dll_directory`, and under certain versions of Anaconda python, + # where `os.add_dll_directory` does not work. + path = os.environ.get('PATH', None) + if not path: + path = pywin32_system32_path + else: + path = pywin32_system32_path + os.pathsep + path + os.environ['PATH'] = path diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/log.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/log.py new file mode 100755 index 000000000..7eb8f8efc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/log.py @@ -0,0 +1,64 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Logging module for PyInstaller. +""" + +__all__ = ['getLogger', 'INFO', 'WARN', 'DEBUG', 'TRACE', 'ERROR', 'FATAL', 'DEPRECATION'] + +import os +import logging +from logging import DEBUG, ERROR, FATAL, INFO, WARN, getLogger + +TRACE = DEBUG - 5 +logging.addLevelName(TRACE, 'TRACE') +DEPRECATION = WARN + 5 +logging.addLevelName(DEPRECATION, 'DEPRECATION') +LEVELS = { + 'TRACE': TRACE, + 'DEBUG': DEBUG, + 'INFO': INFO, + 'WARN': WARN, + 'DEPRECATION': DEPRECATION, + 'ERROR': ERROR, + 'FATAL': FATAL, +} + +FORMAT = '%(relativeCreated)d %(levelname)s: %(message)s' +_env_level = os.environ.get("PYI_LOG_LEVEL", "INFO") +try: + level = LEVELS[_env_level.upper()] +except KeyError: + raise SystemExit(f"Invalid PYI_LOG_LEVEL value '{_env_level}'. Should be one of {list(LEVELS)}.") +logging.basicConfig(format=FORMAT, level=level) +logger = getLogger('PyInstaller') + + +def __add_options(parser): + parser.add_argument( + '--log-level', + choices=LEVELS, + metavar="LEVEL", + dest='loglevel', + help='Amount of detail in build-time console messages. LEVEL may be one of %s (default: INFO). ' + 'Also settable via and overrides the PYI_LOG_LEVEL environment variable.' % ', '.join(LEVELS), + ) + + +def __process_options(parser, opts): + if opts.loglevel: + try: + level = opts.loglevel.upper() + _level = LEVELS[level] + except KeyError: + parser.error('Unknown log level `%s`' % opts.loglevel) + logger.setLevel(_level) + os.environ["PYI_LOG_LEVEL"] = level diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/__init__.py new file mode 100755 index 000000000..792d60054 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/__init__.py @@ -0,0 +1 @@ +# diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/_gitrevision.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/_gitrevision.py new file mode 100755 index 000000000..db3e5a7b5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/_gitrevision.py @@ -0,0 +1,10 @@ +# +# The content of this file will be filled in with meaningful data when creating an archive using `git archive` or by +# downloading an archive from github, e.g., from github.com/.../archive/develop.zip +# +rev = "$Format:%h$" # abbreviated commit hash +commit = "$Format:%H$" # commit hash +date = "$Format:%ci$" # commit date +author = "$Format:%an$ <$Format:%ae$>" +ref_names = "$Format:%D$" # incl. current branch +commit_message = """$Format:%B$""" diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/cliutils/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/cliutils/__init__.py new file mode 100755 index 000000000..792d60054 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/cliutils/__init__.py @@ -0,0 +1 @@ +# diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/cliutils/archive_viewer.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/cliutils/archive_viewer.py new file mode 100755 index 000000000..80f3eeff6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/cliutils/archive_viewer.py @@ -0,0 +1,256 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Viewer for PyInstaller-generated archives. +""" + +import argparse +import os +import sys + +import PyInstaller.log +from PyInstaller.archive.readers import CArchiveReader, ZlibArchiveReader + + +class ArchiveViewer: + def __init__(self, filename, interactive_mode, recursive_mode, brief_mode): + self.filename = filename + self.interactive_mode = interactive_mode + self.recursive_mode = recursive_mode + self.brief_mode = brief_mode + + self.stack = [] + + # Recursive mode implies non-interactive mode + if self.recursive_mode: + self.interactive_mode = False + + def main(self): + # Open top-level (initial) archive + archive = self._open_toplevel_archive(self.filename) + archive_name = os.path.basename(self.filename) + self.stack.append((archive_name, archive)) + + # Not-interactive mode + if not self.interactive_mode: + return self._non_interactive_processing() + + # Interactive mode; show top-level archive + self._show_archive_contents(archive_name, archive) + + # Interactive command processing + while True: + # Read command + try: + tokens = input('? ').split(None, 1) + except EOFError: + # Ctrl-D + print(file=sys.stderr) # Clear line. + break + + # Print usage? + if not tokens: + self._print_usage() + continue + + # Process + command = tokens[0].upper() + if command == 'Q': + break + elif command == 'U': + self._move_up_the_stack() + elif command == 'O': + self._open_embedded_archive(*tokens[1:]) + elif command == 'X': + self._extract_file(*tokens[1:]) + elif command == 'S': + archive_name, archive = self.stack[-1] + self._show_archive_contents(archive_name, archive) + else: + self._print_usage() + + def _non_interactive_processing(self): + archive_count = 0 + + while self.stack: + archive_name, archive = self.stack.pop() + archive_count += 1 + + if archive_count > 1: + print("") + self._show_archive_contents(archive_name, archive) + + if not self.recursive_mode: + continue + + # Scan for embedded archives + if isinstance(archive, CArchiveReader): + for name, (*_, typecode) in archive.toc.items(): + if typecode == 'z': + try: + embedded_archive = archive.open_embedded_archive(name) + except Exception as e: + print(f"Could not open embedded archive {name!r}: {e}", file=sys.stderr) + self.stack.append((name, embedded_archive)) + + def _print_usage(self): + print("U: go up one level", file=sys.stderr) + print("O : open embedded archive with given name", file=sys.stderr) + print("X : extract file with given name", file=sys.stderr) + print("S: list the contents of current archive again", file=sys.stderr) + print("Q: quit", file=sys.stderr) + + def _move_up_the_stack(self): + if len(self.stack) > 1: + self.stack.pop() + archive_name, archive = self.stack[-1] + self._show_archive_contents(archive_name, archive) + else: + print("Already in the top archive!", file=sys.stderr) + + def _open_toplevel_archive(self, filename): + if not os.path.isfile(filename): + print(f"Archive {filename} does not exist!", file=sys.stderr) + sys.exit(1) + + if filename[-4:].lower() == '.pyz': + return ZlibArchiveReader(filename) + return CArchiveReader(filename) + + def _open_embedded_archive(self, archive_name=None): + # Ask for name if not provided + if not archive_name: + archive_name = input('Open name? ') + archive_name = archive_name.strip() + + # No name given; abort + if not archive_name: + return + + # Open the embedded archive + _, parent_archive = self.stack[-1] + + if not hasattr(parent_archive, 'open_embedded_archive'): + print("Archive does not support embedded archives!", file=sys.stderr) + return + + try: + archive = parent_archive.open_embedded_archive(archive_name) + except Exception as e: + print(f"Could not open embedded archive {archive_name!r}: {e}", file=sys.stderr) + return + + # Add to stack and display contents + self.stack.append((archive_name, archive)) + self._show_archive_contents(archive_name, archive) + + def _extract_file(self, name=None): + # Ask for name if not provided + if not name: + name = input('Extract name? ') + name = name.strip() + + # Archive + archive_name, archive = self.stack[-1] + + # Retrieve data + try: + if isinstance(archive, CArchiveReader): + data = archive.extract(name) + elif isinstance(archive, ZlibArchiveReader): + data = archive.extract(name, raw=True) + else: + raise NotImplementedError(f"Extraction from archive type {type(archive)} not implemented!") + except Exception as e: + print(f"Failed to extract data for entry {name!r} from {archive_name!r}: {e}", file=sys.stderr) + + # Write to file + filename = input('Output filename? ') + if not filename: + print(repr(data)) + else: + with open(filename, 'wb') as fp: + fp.write(data) + + def _show_archive_contents(self, archive_name, archive): + if isinstance(archive, CArchiveReader): + print(f"Contents of {archive_name!r} (PKG/CArchive):") + if self.brief_mode: + for name in archive.toc.keys(): + print(f" {name}") + else: + print(" position, length, uncompressed_length, is_compressed, typecode, name") + for name, (position, length, uncompressed_length, is_compressed, typecode) in archive.toc.items(): + print(f" {position}, {length}, {uncompressed_length}, {is_compressed}, {typecode!r}, {name!r}") + elif isinstance(archive, ZlibArchiveReader): + print(f"Contents of {archive_name!r} (PYZ):") + if self.brief_mode: + for name in archive.toc.keys(): + print(f" {name}") + else: + print(" is_package, position, length, name") + for name, (is_package, position, length) in archive.toc.items(): + print(f" {is_package}, {position}, {length}, {name!r}") + else: + print(f"Contents of {name} (unknown)") + print(f"FIXME: implement content listing for archive type {type(archive)}!") + + +def run(): + parser = argparse.ArgumentParser() + parser.add_argument( + '-l', + '--list', + default=False, + action='store_true', + dest='listing_mode', + help='List the archive contents and exit (default: %(default)s).', + ) + parser.add_argument( + '-r', + '--recursive', + default=False, + action='store_true', + dest='recursive', + help='Recursively print an archive log (default: %(default)s). Implies --list.', + ) + parser.add_argument( + '-b', + '--brief', + default=False, + action='store_true', + dest='brief', + help='When displaying archive contents, show only file names. (default: %(default)s).', + ) + PyInstaller.log.__add_options(parser) + parser.add_argument( + 'filename', + metavar='pyi_archive', + help="PyInstaller archive to process.", + ) + + args = parser.parse_args() + PyInstaller.log.__process_options(parser, args) + + try: + viewer = ArchiveViewer( + filename=args.filename, + interactive_mode=not args.listing_mode, + recursive_mode=args.recursive, + brief_mode=args.brief, + ) + viewer.main() + except KeyboardInterrupt: + raise SystemExit("Aborted by user.") + + +if __name__ == '__main__': + run() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/cliutils/bindepend.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/cliutils/bindepend.py new file mode 100755 index 000000000..7a122ada2 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/cliutils/bindepend.py @@ -0,0 +1,52 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Show dll dependencies of executable files or other dynamic libraries. +""" + +import argparse +import glob + +import PyInstaller.depend.bindepend +import PyInstaller.log +from PyInstaller.compat import is_win + + +def run(): + parser = argparse.ArgumentParser() + PyInstaller.log.__add_options(parser) + parser.add_argument( + 'filenames', + nargs='+', + metavar='executable-or-dynamic-library', + help="executables or dynamic libraries for which the dependencies should be shown", + ) + + args = parser.parse_args() + PyInstaller.log.__process_options(parser, args) + + # Suppress all informative messages from the dependency code. + PyInstaller.log.getLogger('PyInstaller.build.bindepend').setLevel(PyInstaller.log.WARN) + + try: + for a in args.filenames: + for fn in glob.glob(a): + imports = PyInstaller.depend.bindepend.getImports(fn) + if is_win: + assemblies = PyInstaller.depend.bindepend.getAssemblies(fn) + imports.update([a.getid() for a in assemblies]) + print(fn, imports) + except KeyboardInterrupt: + raise SystemExit("Aborted by user request.") + + +if __name__ == '__main__': + run() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/cliutils/grab_version.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/cliutils/grab_version.py new file mode 100755 index 000000000..cd798648b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/cliutils/grab_version.py @@ -0,0 +1,51 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +import argparse +import codecs + + +def run(): + parser = argparse.ArgumentParser( + epilog=( + 'The printed output may be saved to a file, edited and used as the input for a version resource on any of ' + 'the executable targets in a PyInstaller .spec file.' + ) + ) + parser.add_argument( + 'exe_file', + metavar='exe-file', + help="full pathname of a Windows executable", + ) + parser.add_argument( + 'out_filename', + metavar='out-filename', + nargs='?', + default='file_version_info.txt', + help="filename where the grabbed version info will be saved", + ) + + args = parser.parse_args() + + try: + from PyInstaller.utils.win32 import versioninfo + info = versioninfo.read_version_info_from_executable(args.exe_file) + if not info: + raise SystemExit("Error: VersionInfo resource not found in exe") + with codecs.open(args.out_filename, 'w', 'utf-8') as fp: + fp.write(str(info)) + print(f"Version info written to: {args.out_filename!r}") + except KeyboardInterrupt: + raise SystemExit("Aborted by user request.") + + +if __name__ == '__main__': + run() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/cliutils/makespec.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/cliutils/makespec.py new file mode 100755 index 000000000..52edc7c13 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/cliutils/makespec.py @@ -0,0 +1,53 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Automatically build a spec file containing the description of the project. +""" + +import argparse +import os + +import PyInstaller.building.makespec +import PyInstaller.log + + +def generate_parser(): + p = argparse.ArgumentParser() + PyInstaller.building.makespec.__add_options(p) + PyInstaller.log.__add_options(p) + p.add_argument( + 'scriptname', + nargs='+', + ) + return p + + +def run(): + p = generate_parser() + args = p.parse_args() + PyInstaller.log.__process_options(p, args) + + # Split pathex by using the path separator. + temppaths = args.pathex[:] + args.pathex = [] + for p in temppaths: + args.pathex.extend(p.split(os.pathsep)) + + try: + name = PyInstaller.building.makespec.main(args.scriptname, **vars(args)) + print('Wrote %s.' % name) + print('Now run pyinstaller.py to build the executable.') + except KeyboardInterrupt: + raise SystemExit("Aborted by user request.") + + +if __name__ == '__main__': + run() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/cliutils/set_version.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/cliutils/set_version.py new file mode 100755 index 000000000..5574ece38 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/cliutils/set_version.py @@ -0,0 +1,43 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +import argparse +import os + + +def run(): + parser = argparse.ArgumentParser() + parser.add_argument( + 'info_file', + metavar='info-file', + help="text file containing version info", + ) + parser.add_argument( + 'exe_file', + metavar='exe-file', + help="full pathname of a Windows executable", + ) + args = parser.parse_args() + + info_file = os.path.abspath(args.info_file) + exe_file = os.path.abspath(args.exe_file) + + try: + from PyInstaller.utils.win32 import versioninfo + info = versioninfo.load_version_info_from_text_file(info_file) + versioninfo.write_version_info_to_executable(exe_file, info) + print(f"Version info written to: {exe_file!r}") + except KeyboardInterrupt: + raise SystemExit("Aborted by user request.") + + +if __name__ == '__main__': + run() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/conftest.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/conftest.py new file mode 100755 index 000000000..b6acb9be8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/conftest.py @@ -0,0 +1,575 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +import copy +import glob +import logging +import os +import re +import shutil +import subprocess +from contextlib import suppress + +# Set a handler for the root-logger to inhibit 'basicConfig()' (called in PyInstaller.log) is setting up a stream +# handler writing to stderr. This avoids log messages to be written (and captured) twice: once on stderr and +# once by pytests's caplog. +logging.getLogger().addHandler(logging.NullHandler()) + +# Manages subprocess timeout. +import psutil # noqa: E402 +import py # noqa: E402 +import pytest # noqa: E402 +import sys # noqa: E402 + +# Expand sys.path with PyInstaller source. +_ROOT_DIR = os.path.normpath(os.path.join(os.path.dirname(os.path.abspath(__file__)), '..', '..')) +sys.path.append(_ROOT_DIR) + +from PyInstaller import __main__ as pyi_main # noqa: E402 +from PyInstaller import configure # noqa: E402 +from PyInstaller.compat import architecture, is_darwin, is_win # noqa: E402 +from PyInstaller.depend.analysis import initialize_modgraph # noqa: E402 +from PyInstaller.archive.readers import pkg_archive_contents # noqa: E402 +from PyInstaller.utils.tests import gen_sourcefile # noqa: E402 +from PyInstaller.utils.win32 import winutils # noqa: E402 + +# Timeout for running the executable. If executable does not exit in this time, it is interpreted as a test failure. +_EXE_TIMEOUT = 3 * 60 # In sec. +# All currently supported platforms +SUPPORTED_OSES = {"darwin", "linux", "win32"} +# Have pyi_builder fixure clean-up the temporary directories of successful tests. Controlled by environment variable. +_PYI_BUILDER_CLEANUP = os.environ.get("PYI_BUILDER_CLEANUP", "1") == "1" + +# Fixtures +# -------- + + +@pytest.fixture +def SPEC_DIR(request): + """ + Return the directory where the test spec-files reside. + """ + return py.path.local(_get_spec_dir(request)) + + +@pytest.fixture +def SCRIPT_DIR(request): + """ + Return the directory where the test scripts reside. + """ + return py.path.local(_get_script_dir(request)) + + +def pytest_runtest_setup(item): + """ + Markers to skip tests based on the current platform. + https://pytest.org/en/stable/example/markers.html#marking-platform-specific-tests-with-pytest + + Available markers: see setup.cfg [tool:pytest] markers + - @pytest.mark.darwin (macOS) + - @pytest.mark.linux (GNU/Linux) + - @pytest.mark.win32 (Windows) + """ + supported_platforms = SUPPORTED_OSES.intersection(mark.name for mark in item.iter_markers()) + plat = sys.platform + if supported_platforms and plat not in supported_platforms: + pytest.skip("does not run on %s" % plat) + + +@pytest.hookimpl(tryfirst=True, hookwrapper=True) +def pytest_runtest_makereport(item, call): + # Execute all other hooks to obtain the report object. + outcome = yield + rep = outcome.get_result() + + # Set a report attribute for each phase of a call, which can be "setup", "call", "teardown". + setattr(item, "rep_" + rep.when, rep) + + +# Return the base directory which contains the current test module. +def _get_base_dir(request): + return os.path.dirname(os.path.abspath(request.fspath.strpath)) + + +# Directory with Python scripts for functional tests. +def _get_script_dir(request): + return os.path.join(_get_base_dir(request), 'scripts') + + +# Directory with testing modules used in some tests. +def _get_modules_dir(request): + return os.path.join(_get_base_dir(request), 'modules') + + +# Directory with .toc log files. +def _get_logs_dir(request): + return os.path.join(_get_base_dir(request), 'logs') + + +# Return the directory where data for tests is located. +def _get_data_dir(request): + return os.path.join(_get_base_dir(request), 'data') + + +# Directory with .spec files used in some tests. +def _get_spec_dir(request): + return os.path.join(_get_base_dir(request), 'specs') + + +@pytest.fixture +def script_dir(request): + return py.path.local(_get_script_dir(request)) + + +# A helper function to copy from data/dir to tmpdir/data. +def _data_dir_copy( + # The pytest request object. + request, + # The name of the subdirectory located in data/name to copy. + subdir_name, + # The tmpdir object for this test. See: https://pytest.org/latest/tmpdir.html. + tmpdir +): + + # Form the source and tmp paths. + source_data_dir = py.path.local(_get_data_dir(request)).join(subdir_name) + tmp_data_dir = tmpdir.join('data', subdir_name) + # Copy the data. + shutil.copytree(source_data_dir.strpath, tmp_data_dir.strpath) + # Return the temporary data directory, so that the copied data can now be used. + return tmp_data_dir + + +# Define a fixure for the DataDir object. +@pytest.fixture +def data_dir( + # The request object for this test. See + # https://pytest.org/latest/builtin.html#_pytest.python.FixtureRequest + # and + # https://pytest.org/latest/fixture.html#fixtures-can-introspect-the-requesting-test-context. + request, + # The tmpdir object for this test. See https://pytest.org/latest/tmpdir.html. + tmpdir +): + + # Strip the leading 'test_' from the test's name. + name = request.function.__name__[5:] + # Copy to tmpdir and return the path. + return _data_dir_copy(request, name, tmpdir) + + +class AppBuilder: + def __init__(self, tmpdir, request, bundle_mode): + self._tmpdir = tmpdir + self._request = request + self._mode = bundle_mode + self._specdir = str(tmpdir) + self._distdir = str(tmpdir / 'dist') + self._builddir = str(tmpdir / 'build') + self._is_spec = False + + def test_spec(self, specfile, *args, **kwargs): + """ + Test a Python script that is referenced in the supplied .spec file. + """ + __tracebackhide__ = True + specfile = os.path.join(_get_spec_dir(self._request), specfile) + # 'test_script' should handle .spec properly as script. + self._is_spec = True + return self.test_script(specfile, *args, **kwargs) + + def test_source(self, source, *args, **kwargs): + """ + Test a Python script given as source code. + + The source will be written into a file named like the test-function. This file will then be passed to + `test_script`. If you need other related file, e.g., as `.toc`-file for testing the content, put it at at the + normal place. Just mind to take the basnename from the test-function's name. + + :param script: Source code to create executable from. This will be saved into a temporary file which is then + passed on to `test_script`. + + :param test_id: Test-id for parametrized tests. If given, it will be appended to the script filename, separated + by two underscores. + + All other arguments are passed straight on to `test_script`. + + Ensure that the caller of `test_source` is in a UTF-8 encoded file with the correct '# -*- coding: utf-8 -*-' + marker. + + """ + __tracebackhide__ = True + # For parametrized test append the test-id. + scriptfile = gen_sourcefile(self._tmpdir, source, kwargs.setdefault('test_id')) + del kwargs['test_id'] + return self.test_script(str(scriptfile), *args, **kwargs) + + def test_script( + self, script, pyi_args=None, app_name=None, app_args=None, runtime=None, run_from_path=False, **kwargs + ): + """ + Main method to wrap all phases of testing a Python script. + + :param script: Name of script to create executable from. + :param pyi_args: Additional arguments to pass to PyInstaller when creating executable. + :param app_name: Name of the executable. This is equivalent to argument --name=APPNAME. + :param app_args: Additional arguments to pass to + :param runtime: Time in seconds how long to keep executable running. + :param toc_log: List of modules that are expected to be bundled with the executable. + """ + __tracebackhide__ = True + + def marker(line): + # Print some marker to stdout and stderr to make it easier to distinguish the phases in the CI test output. + print('-------', line, '-------') + print('-------', line, '-------', file=sys.stderr) + + if pyi_args is None: + pyi_args = [] + if app_args is None: + app_args = [] + + if app_name: + if not self._is_spec: + pyi_args.extend(['--name', app_name]) + else: + # Derive name from script name. + app_name = os.path.splitext(os.path.basename(script))[0] + + # Relative path means that a script from _script_dir is referenced. + if not os.path.isabs(script): + script = os.path.join(_get_script_dir(self._request), script) + self.script = script + assert os.path.exists(self.script), 'Script %s not found.' % script + + marker('Starting build.') + if not self._test_building(args=pyi_args): + pytest.fail('Building of %s failed.' % script) + + marker('Build finished, now running executable.') + self._test_executables(app_name, args=app_args, runtime=runtime, run_from_path=run_from_path, **kwargs) + marker('Running executable finished.') + + def _test_executables(self, name, args, runtime, run_from_path, **kwargs): + """ + Run created executable to make sure it works. + + Multipackage-tests generate more than one exe-file and all of them have to be run. + + :param args: CLI options to pass to the created executable. + :param runtime: Time in seconds how long to keep the executable running. + + :return: Exit code of the executable. + """ + __tracebackhide__ = True + exes = self._find_executables(name) + # Empty list means that PyInstaller probably failed to create any executable. + assert exes != [], 'No executable file was found.' + for exe in exes: + # Try to find .toc log file. .toc log file has the same basename as exe file. + toc_log = os.path.join(_get_logs_dir(self._request), os.path.splitext(os.path.basename(exe))[0] + '.toc') + if os.path.exists(toc_log): + if not self._examine_executable(exe, toc_log): + pytest.fail('Matching .toc of %s failed.' % exe) + retcode = self._run_executable(exe, args, run_from_path, runtime) + if retcode != kwargs.get('retcode', 0): + pytest.fail('Running exe %s failed with return-code %s.' % (exe, retcode)) + + def _find_executables(self, name): + """ + Search for all executables generated by the testcase. + + If the test-case is called e.g. 'test_multipackage1', this is searching for each of 'test_multipackage1.exe' + and 'multipackage1_?.exe' in both one-file- and one-dir-mode. + + :param name: Name of the executable to look for. + + :return: List of executables + """ + exes = [] + onedir_pt = os.path.join(self._distdir, name, name) + onefile_pt = os.path.join(self._distdir, name) + patterns = [ + onedir_pt, + onefile_pt, + # Multipackage one-dir + onedir_pt + '_?', + # Multipackage one-file + onefile_pt + '_?' + ] + # For Windows append .exe extension to patterns. + if is_win: + patterns = [pt + '.exe' for pt in patterns] + # For Mac OS append pattern for .app bundles. + if is_darwin: + # e.g: ./dist/name.app/Contents/MacOS/name + pt = os.path.join(self._distdir, name + '.app', 'Contents', 'MacOS', name) + patterns.append(pt) + # Apply file patterns. + for pattern in patterns: + for prog in glob.glob(pattern): + if os.path.isfile(prog): + exes.append(prog) + return exes + + def _run_executable(self, prog, args, run_from_path, runtime): + """ + Run executable created by PyInstaller. + + :param args: CLI options to pass to the created executable. + """ + # Run the test in a clean environment to make sure they're really self-contained. + prog_env = copy.deepcopy(os.environ) + prog_env['PATH'] = '' + del prog_env['PATH'] + # For Windows we need to keep minimal PATH for successful running of some tests. + if is_win: + # Minimum Windows PATH is in most cases: C:\Windows\system32;C:\Windows + prog_env['PATH'] = os.pathsep.join(winutils.get_system_path()) + + exe_path = prog + if run_from_path: + # Run executable in the temp directory. Add the directory containing the executable to $PATH. Basically, + # pretend we are a shell executing the program from $PATH. + prog_cwd = str(self._tmpdir) + prog_name = os.path.basename(prog) + prog_env['PATH'] = os.pathsep.join([prog_env.get('PATH', ''), os.path.dirname(prog)]) + + else: + # Run executable in the directory where it is. + prog_cwd = os.path.dirname(prog) + # The executable will be called with argv[0] as relative not absolute path. + prog_name = os.path.join(os.curdir, os.path.basename(prog)) + + args = [prog_name] + args + # Using sys.stdout/sys.stderr for subprocess fixes printing messages in Windows command prompt. Py.test is then + # able to collect stdout/sterr messages and display them if a test fails. + return self._run_executable_(args, exe_path, prog_env, prog_cwd, runtime) + + def _run_executable_(self, args, exe_path, prog_env, prog_cwd, runtime): + process = psutil.Popen( + args, executable=exe_path, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=prog_env, cwd=prog_cwd + ) + + def _msg(*text): + print('[' + str(process.pid) + '] ', *text) + + # Run executable. stderr is redirected to stdout. + _msg('RUNNING: ', repr(exe_path), ', args: ', repr(args)) + # 'psutil' allows to use timeout in waiting for a subprocess. If not timeout was specified then it is 'None' - + # no timeout, just waiting. Runtime is useful mostly for interactive tests. + try: + timeout = runtime if runtime else _EXE_TIMEOUT + stdout, stderr = process.communicate(timeout=timeout) + retcode = process.returncode + except (psutil.TimeoutExpired, subprocess.TimeoutExpired): + if runtime: + # When 'runtime' is set, the expired timeout is a good sign that the executable was running successfully + # for a specified time. + # TODO: is there a better way return success than 'retcode = 0'? + retcode = 0 + else: + # Exe is running and it is not interactive. Fail the test. + retcode = 1 + _msg(f'TIMED OUT while running executable (timeout: {timeout} sec)!') + # Kill the subprocess and its child processes. + for p in list(process.children(recursive=True)) + [process]: + with suppress(psutil.NoSuchProcess): + p.kill() + stdout, stderr = process.communicate() + + sys.stdout.buffer.write(stdout) + sys.stderr.buffer.write(stderr) + + return retcode + + def _test_building(self, args): + """ + Run building of test script. + + :param args: additional CLI options for PyInstaller. + + Return True if build succeeded False otherwise. + """ + if self._is_spec: + default_args = [ + '--distpath', self._distdir, + '--workpath', self._builddir, + '--log-level=INFO', + ] # yapf: disable + else: + default_args = [ + '--debug=bootloader', + '--noupx', + '--specpath', self._specdir, + '--distpath', self._distdir, + '--workpath', self._builddir, + '--path', _get_modules_dir(self._request), + '--log-level=INFO', + ] # yapf: disable + + # Choose bundle mode. + if self._mode == 'onedir': + default_args.append('--onedir') + elif self._mode == 'onefile': + default_args.append('--onefile') + # if self._mode is None then just the spec file was supplied. + + pyi_args = [self.script] + default_args + args + # TODO: fix return code in running PyInstaller programmatically. + PYI_CONFIG = configure.get_config() + # Override CACHEDIR for PyInstaller and put it into self.tmpdir + PYI_CONFIG['cachedir'] = str(self._tmpdir) + + pyi_main.run(pyi_args, PYI_CONFIG) + retcode = 0 + + return retcode == 0 + + def _examine_executable(self, exe, toc_log): + """ + Compare log files (now used mostly by multipackage test_name). + + :return: True if .toc files match + """ + print('EXECUTING MATCHING:', toc_log) + fname_list = pkg_archive_contents(exe) + with open(toc_log, 'r') as f: + pattern_list = eval(f.read()) + # Alphabetical order of patterns. + pattern_list.sort() + missing = [] + for pattern in pattern_list: + for fname in fname_list: + if re.match(pattern, fname): + print('MATCH:', pattern, '-->', fname) + break + else: + # No matching entry found + missing.append(pattern) + print('MISSING:', pattern) + + # Not all modules matched. Stop comparing other .toc files and fail the test. + if missing: + for m in missing: + print('Missing', m, 'in', exe) + return False + # All patterns matched. + return True + + +# Scope 'session' should keep the object unchanged for whole tests. This fixture caches basic module graph dependencies +# that are same for every executable. +@pytest.fixture(scope='session') +def pyi_modgraph(): + # Explicitly set the log level since the plugin `pytest-catchlog` (un-) sets the root logger's level to NOTSET for + # the setup phase, which will lead to TRACE messages been written out. + import PyInstaller.log as logging + logging.logger.setLevel(logging.DEBUG) + initialize_modgraph() + + +# Run by default test as onedir and onefile. +@pytest.fixture(params=['onedir', 'onefile']) +def pyi_builder(tmpdir, monkeypatch, request, pyi_modgraph): + # Save/restore environment variable PATH. + monkeypatch.setenv('PATH', os.environ['PATH']) + # PyInstaller or a test case might manipulate 'sys.path'. Reset it for every test. + monkeypatch.syspath_prepend(None) + # Set current working directory to + monkeypatch.chdir(tmpdir) + # Clean up configuration and force PyInstaller to do a clean configuration for another app/test. The value is same + # as the original value. + monkeypatch.setattr('PyInstaller.config.CONF', {'pathex': []}) + + yield AppBuilder(tmpdir, request, request.param) + + # Clean up the temporary directory of a successful test + if _PYI_BUILDER_CLEANUP and request.node.rep_setup.passed and request.node.rep_call.passed: + if tmpdir.exists(): + tmpdir.remove(rec=1, ignore_errors=True) + + +# Fixture for .spec based tests. With .spec it does not make sense to differentiate onefile/onedir mode. +@pytest.fixture +def pyi_builder_spec(tmpdir, request, monkeypatch, pyi_modgraph): + # Save/restore environment variable PATH. + monkeypatch.setenv('PATH', os.environ['PATH']) + # Set current working directory to + monkeypatch.chdir(tmpdir) + # PyInstaller or a test case might manipulate 'sys.path'. Reset it for every test. + monkeypatch.syspath_prepend(None) + # Clean up configuration and force PyInstaller to do a clean configuration for another app/test. The value is same + # as the original value. + monkeypatch.setattr('PyInstaller.config.CONF', {'pathex': []}) + + return AppBuilder(tmpdir, request, None) + + +# Define a fixture which compiles the data/load_dll_using_ctypes/ctypes_dylib.c program in the tmpdir, returning the +# tmpdir object. +@pytest.fixture() +def compiled_dylib(tmpdir, request): + tmp_data_dir = _data_dir_copy(request, 'ctypes_dylib', tmpdir) + + # Compile the ctypes_dylib in the tmpdir: Make tmpdir/data the CWD. Do NOT use monkeypatch.chdir() to change and + # monkeypatch.undo() to restore the CWD, since this will undo ALL monkeypatches (such as the pyi_builder's additions + # to sys.path), breaking the test. + old_wd = tmp_data_dir.chdir() + try: + if is_win: + tmp_data_dir = tmp_data_dir.join('ctypes_dylib.dll') + # For Mingw-x64 we must pass '-m32' to build 32-bit binaries + march = '-m32' if architecture == '32bit' else '-m64' + ret = subprocess.call('gcc -shared ' + march + ' ctypes_dylib.c -o ctypes_dylib.dll', shell=True) + if ret != 0: + # Find path to cl.exe file. + from distutils.msvccompiler import MSVCCompiler + comp = MSVCCompiler() + comp.initialize() + cl_path = comp.cc + # Fallback to msvc. + ret = subprocess.call([cl_path, '/LD', 'ctypes_dylib.c'], shell=False) + elif is_darwin: + tmp_data_dir = tmp_data_dir.join('ctypes_dylib.dylib') + # On Mac OS X we need to detect architecture - 32 bit or 64 bit. + arch = 'i386' if architecture == '32bit' else 'x86_64' + cmd = ( + 'gcc -arch ' + arch + ' -Wall -dynamiclib ' + 'ctypes_dylib.c -o ctypes_dylib.dylib -headerpad_max_install_names' + ) + ret = subprocess.call(cmd, shell=True) + id_dylib = os.path.abspath('ctypes_dylib.dylib') + ret = subprocess.call('install_name_tool -id %s ctypes_dylib.dylib' % (id_dylib,), shell=True) + else: + tmp_data_dir = tmp_data_dir.join('ctypes_dylib.so') + ret = subprocess.call('gcc -fPIC -shared ctypes_dylib.c -o ctypes_dylib.so', shell=True) + assert ret == 0, 'Compile ctypes_dylib failed.' + finally: + # Reset the CWD directory. + old_wd.chdir() + + return tmp_data_dir + + +@pytest.fixture +def pyi_windowed_builder(pyi_builder: AppBuilder): + """A pyi_builder equivalent for testing --windowed applications.""" + + # psutil.Popen() somehow bypasses an application's windowed/console mode so that any application built in + # --windowed mode but invoked with psutil still receives valid std{in,out,err} handles and behaves exactly like + # a console application. In short, testing windowed mode with psutil is a null test. We must instead use subprocess. + + def _run_executable_(args, exe_path, prog_env, prog_cwd, runtime): + return subprocess.run([exe_path, *args], env=prog_env, cwd=prog_cwd, timeout=runtime).returncode + + pyi_builder._run_executable_ = _run_executable_ + yield pyi_builder diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/git.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/git.py new file mode 100755 index 000000000..c69865d20 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/git.py @@ -0,0 +1,59 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +This module contains various helper functions for git DVCS. +""" + +import os + +from PyInstaller.compat import exec_command, exec_command_rc + +try: + WindowsError +except NameError: + # Not running on Windows + WindowsError = FileNotFoundError + + +def get_repo_revision(): + path = os.path # shortcut + gitdir = path.normpath(path.join(path.dirname(os.path.abspath(__file__)), '..', '..', '.git')) + cwd = os.path.dirname(gitdir) + if not path.exists(gitdir): + try: + from PyInstaller.utils._gitrevision import rev + if not rev.startswith('$'): + # the format specifier has been substituted + return '+' + rev + except ImportError: + pass + return '' + try: + # need to update index first to get reliable state + exec_command_rc('git', 'update-index', '-q', '--refresh', cwd=cwd) + recent = exec_command('git', 'describe', '--long', '--dirty', '--tag', cwd=cwd).strip() + if recent.endswith('-dirty'): + tag, changes, rev, dirty = recent.rsplit('-', 3) + rev = rev + '.mod' + else: + tag, changes, rev = recent.rsplit('-', 2) + if changes == '0': + return '' + # According to PEP440, local version identifier starts with '+'. + return '+' + rev + except (FileNotFoundError, WindowsError): + # Be silent when git command is not found. + pass + return '' + + +if __name__ == '__main__': + print(get_repo_revision()) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/__init__.py new file mode 100755 index 000000000..654af1f7c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/__init__.py @@ -0,0 +1,1399 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from __future__ import annotations + +import copy +import os +import sys +import textwrap +import fnmatch +from pathlib import Path +from collections import deque +from typing import Callable + +import pkg_resources + +from PyInstaller import HOMEPATH, compat +from PyInstaller import log as logging +from PyInstaller.depend.imphookapi import PostGraphAPI +from PyInstaller.exceptions import ExecCommandFailed +from PyInstaller.utils.hooks.win32 import \ + get_pywin32_module_file_attribute # noqa: F401 +from PyInstaller import isolated + +logger = logging.getLogger(__name__) + +# These extensions represent Python executables and should therefore be ignored when collecting data files. +# NOTE: .dylib files are not Python executable and should not be in this list. +PY_IGNORE_EXTENSIONS = set(compat.ALL_SUFFIXES) + +# Some hooks need to save some values. This is the dict that can be used for that. +# +# When running tests this variable should be reset before every test. +# +# For example the 'wx' module needs variable 'wxpubsub'. This tells PyInstaller which protocol of the wx module +# should be bundled. +hook_variables = {} + + +def __exec_python_cmd(cmd, env=None, capture_stdout=True): + """ + Executes an externally spawned Python interpreter. If capture_stdout is set to True, returns anything that was + emitted in the standard output as a single string. Otherwise, returns the exit code. + """ + # 'PyInstaller.config' cannot be imported as other top-level modules. + from PyInstaller.config import CONF + if env is None: + env = {} + # Update environment. Defaults to 'os.environ' + pp_env = copy.deepcopy(os.environ) + pp_env.update(env) + # Prepend PYTHONPATH with pathex. + # Some functions use some PyInstaller code in subprocess, so add PyInstaller HOMEPATH to sys.path as well. + pp = os.pathsep.join(CONF['pathex'] + [HOMEPATH]) + + # PYTHONPATH might be already defined in the 'env' argument or in the original 'os.environ'. Prepend it. + if 'PYTHONPATH' in pp_env: + pp = os.pathsep.join([pp_env.get('PYTHONPATH'), pp]) + pp_env['PYTHONPATH'] = pp + + if capture_stdout: + txt = compat.exec_python(*cmd, env=pp_env) + return txt.strip() + else: + return compat.exec_python_rc(*cmd, env=pp_env) + + +def __exec_statement(statement, capture_stdout=True): + statement = textwrap.dedent(statement) + cmd = ['-c', statement] + return __exec_python_cmd(cmd, capture_stdout=capture_stdout) + + +def exec_statement(statement: str): + """ + Execute a single Python statement in an externally-spawned interpreter, and return the resulting standard output + as a string. + + Examples:: + + tk_version = exec_statement("from _tkinter import TK_VERSION; print(TK_VERSION)") + + mpl_data_dir = exec_statement("import matplotlib; print(matplotlib.get_data_path())") + datas = [ (mpl_data_dir, "") ] + + Notes: + As of v5.0, usage of this function is discouraged in favour of the + new :mod:`PyInstaller.isolated` module. + + """ + return __exec_statement(statement, capture_stdout=True) + + +def exec_statement_rc(statement: str): + """ + Executes a Python statement in an externally spawned interpreter, and returns the exit code. + """ + return __exec_statement(statement, capture_stdout=False) + + +def eval_statement(statement: str): + """ + Execute a single Python statement in an externally-spawned interpreter, and :func:`eval` its output (if any). + + Example:: + + databases = eval_statement(''' + import sqlalchemy.databases + print(sqlalchemy.databases.__all__) + ''') + for db in databases: + hiddenimports.append("sqlalchemy.databases." + db) + + Notes: + As of v5.0, usage of this function is discouraged in favour of the + new :mod:`PyInstaller.isolated` module. + + """ + txt = exec_statement(statement).strip() + if not txt: + # Return an empty string, which is "not true" but is iterable. + return '' + return eval(txt) + + +@isolated.decorate +def get_pyextension_imports(module_name: str): + """ + Return list of modules required by binary (C/C++) Python extension. + + Python extension files ends with .so (Unix) or .pyd (Windows). It is almost impossible to analyze binary extension + and its dependencies. + + Module cannot be imported directly. + + Let's at least try import it in a subprocess and observe the difference in module list from sys.modules. + + This function could be used for 'hiddenimports' in PyInstaller hooks files. + """ + import sys + import importlib + + original = set(sys.modules.keys()) + + # When importing this module - sys.modules gets updated. + importlib.import_module(module_name) + + # Find and return which new modules have been loaded. + return list(set(sys.modules.keys()) - original - {module_name}) + + +def get_homebrew_path(formula: str = ''): + """ + Return the homebrew path to the requested formula, or the global prefix when called with no argument. + + Returns the path as a string or None if not found. + """ + import subprocess + brewcmd = ['brew', '--prefix'] + path = None + if formula: + brewcmd.append(formula) + dbgstr = 'homebrew formula "%s"' % formula + else: + dbgstr = 'homebrew prefix' + try: + path = subprocess.check_output(brewcmd).strip() + logger.debug('Found %s at "%s"' % (dbgstr, path)) + except OSError: + logger.debug('Detected homebrew not installed') + except subprocess.CalledProcessError: + logger.debug('homebrew formula "%s" not installed' % formula) + if path: + return path.decode('utf8') # Mac OS filenames are UTF-8 + else: + return None + + +def remove_prefix(string: str, prefix: str): + """ + This function removes the given prefix from a string, if the string does indeed begin with the prefix; otherwise, + it returns the original string. + """ + if string.startswith(prefix): + return string[len(prefix):] + else: + return string + + +def remove_suffix(string: str, suffix: str): + """ + This function removes the given suffix from a string, if the string does indeed end with the suffix; otherwise, + it returns the original string. + """ + # Special case: if suffix is empty, string[:0] returns ''. So, test for a non-empty suffix. + if suffix and string.endswith(suffix): + return string[:-len(suffix)] + else: + return string + + +# TODO: Do we really need a helper for this? This is pretty trivially obvious. +def remove_file_extension(filename: str): + """ + This function returns filename without its extension. + + For Python C modules it removes even whole '.cpython-34m.so' etc. + """ + for suff in compat.EXTENSION_SUFFIXES: + if filename.endswith(suff): + return filename[0:filename.rfind(suff)] + # Fallback to ordinary 'splitext'. + return os.path.splitext(filename)[0] + + +@isolated.decorate +def can_import_module(module_name: str): + """ + Check if the specified module can be imported. + + Intended as a silent module availability check, as it does not print ModuleNotFoundError traceback to stderr when + the module is unavailable. + + Parameters + ---------- + module_name : str + Fully-qualified name of the module. + + Returns + ---------- + bool + Boolean indicating whether the module can be imported or not. + """ + try: + __import__(module_name) + return True + except Exception: + return False + + +# TODO: Replace most calls to exec_statement() with calls to this function. +def get_module_attribute(module_name: str, attr_name: str): + """ + Get the string value of the passed attribute from the passed module if this attribute is defined by this module + _or_ raise `AttributeError` otherwise. + + Since modules cannot be directly imported during analysis, this function spawns a subprocess importing this module + and returning the string value of this attribute in this module. + + Parameters + ---------- + module_name : str + Fully-qualified name of this module. + attr_name : str + Name of the attribute in this module to be retrieved. + + Returns + ---------- + str + String value of this attribute. + + Raises + ---------- + AttributeError + If this attribute is undefined. + """ + @isolated.decorate + def _get_module_attribute(module_name, attr_name): + import importlib + module = importlib.import_module(module_name) + return getattr(module, attr_name) + + # Return AttributeError on any kind of errors, to preserve old behavior. + try: + return _get_module_attribute(module_name, attr_name) + except Exception as e: + raise AttributeError(f"Failed to retrieve attribute {attr_name} from module {module_name}") from e + + +def get_module_file_attribute(package: str): + """ + Get the absolute path to the specified module or package. + + Modules and packages *must not* be directly imported in the main process during the analysis. Therefore, to + avoid leaking the imports, this function uses an isolated subprocess when it needs to import the module and + obtain its ``__file__`` attribute. + + Parameters + ---------- + package : str + Fully-qualified name of module or package. + + Returns + ---------- + str + Absolute path of this module. + """ + # First, try to use 'pkgutil'. It is the fastest way, but does not work on certain modules in pywin32 that replace + # all module attributes with those of the .dll. In addition, we need to avoid it for submodules/subpackages, + # because it ends up importing their parent package, which would cause an import leak during the analysis. + filename: str | None = None + if '.' not in package: + try: + import pkgutil + loader = pkgutil.find_loader(package) + filename = loader.get_filename(package) + # Apparently in the past, ``None`` could be returned for built-in ``datetime`` module. Just in case this + # is still possible, return only if filename is valid. + if filename: + return filename + except (AttributeError, ImportError): + pass + + # Second attempt: try to obtain module/package's __file__ attribute in an isolated subprocess. + @isolated.decorate + def _get_module_file_attribute(package): + # First try to use 'pkgutil'; it returns the filename even if the module or package cannot be imported + # (e.g., C-extension module with missing dependencies). + try: + import pkgutil + loader = pkgutil.find_loader(package) + filename = loader.get_filename(package) + # Safe-guard against ``None`` being returned (see comment in the non-isolated codepath). + if filename: + return filename + except (AttributeError, ImportError): + pass + + # Fall back to import attempt + import importlib + p = importlib.import_module(package) + return p.__file__ + + # The old behavior was to return ImportError (and that is what the test are also expecting...). + try: + filename = _get_module_file_attribute(package) + except Exception as e: + raise ImportError(f"Failed to obtain the __file__ attribute of package/module {package}!") from e + + return filename + + +def is_module_satisfies( + requirements: list | pkg_resources.Requirement, + version: str | pkg_resources.Distribution | None = None, + version_attr: str = "__version__", +): + """ + Test if a :pep:`0440` requirement is installed. + + Parameters + ---------- + requirements : str + Requirements in `pkg_resources.Requirements.parse()` format. + version : str + Optional PEP 0440-compliant version (e.g., `3.14-rc5`) to be used _instead_ of the current version of this + module. If non-`None`, this function ignores all `setuptools` distributions for this module and instead + compares this version against the version embedded in the passed requirements. This ignores the module name + embedded in the passed requirements, permitting arbitrary versions to be compared in a robust manner. + See examples below. + version_attr : str + Optional name of the version attribute defined by this module, defaulting to `__version__`. If a + `setuptools` distribution exists for this module (it usually does) _and_ the `version` parameter is `None` + (it usually is), this parameter is ignored. + + Returns + ---------- + bool + Boolean result of the desired validation. + + Raises + ---------- + AttributeError + If no `setuptools` distribution exists for this module _and_ this module defines no attribute whose name is the + passed `version_attr` parameter. + ValueError + If the passed specification does _not_ comply with `pkg_resources.Requirements`_ syntax. + + Examples + -------- + + :: + + # Assume PIL 2.9.0, Sphinx 1.3.1, and SQLAlchemy 0.6 are all installed. + >>> from PyInstaller.utils.hooks import is_module_satisfies + >>> is_module_satisfies('sphinx >= 1.3.1') + True + >>> is_module_satisfies('sqlalchemy != 0.6') + False + + >>> is_module_satisfies('sphinx >= 1.3.1; sqlalchemy != 0.6') + False + + + # Compare two arbitrary versions. In this case, the module name "sqlalchemy" is simply ignored. + >>> is_module_satisfies('sqlalchemy != 0.6', version='0.5') + True + + # Since the "pillow" project providing PIL publishes its version via the custom "PILLOW_VERSION" attribute + # (rather than the standard "__version__" attribute), an attribute name is passed as a fallback to validate PIL + # when not installed by setuptools. As PIL is usually installed by setuptools, this optional parameter is + # usually ignored. + >>> is_module_satisfies('PIL == 2.9.0', version_attr='PILLOW_VERSION') + True + + .. seealso:: + + `pkg_resources.Requirements`_ for the syntax details. + + .. _`pkg_resources.Requirements`: + https://pythonhosted.org/setuptools/pkg_resources.html#id12 + """ + # If no version was explicitly passed... + if version is None: + # If a setuptools distribution exists for this module, this validation is a simple one-liner. This approach + # supports non-version validation (e.g., of "["- and "]"-delimited extras) and is hence preferable. + try: + pkg_resources.get_distribution(requirements) + # If no such distribution exists, fall back to the logic below. + except pkg_resources.DistributionNotFound: + pass + # If all existing distributions violate these requirements, fail. + except (pkg_resources.UnknownExtra, pkg_resources.VersionConflict): + return False + # Else, an existing distribution satisfies these requirements. Win! + else: + return True + + # Either a module version was explicitly passed or no setuptools distribution exists for this module. First, parse a + # setuptools "Requirements" object from this requirements string. + requirements_parsed = pkg_resources.Requirement.parse(requirements) + + # If no version was explicitly passed, query this module for it. + if version is None: + module_name = requirements_parsed.project_name + if can_import_module(module_name): + version = get_module_attribute(module_name, version_attr) + else: + version = None + + if not version: + # Module does not exist in the system. + return False + else: + # Compare this version against the one parsed from the requirements. + return version in requirements_parsed + + +def is_package(module_name: str): + """ + Check if a Python module is really a module or is a package containing other modules, without importing anything + in the main process. + + :param module_name: Module name to check. + :return: True if module is a package else otherwise. + """ + def _is_package(module_name: str): + """ + Determines whether the given name represents a package or not. If the name represents a top-level module or + a package, it is not imported. If the name represents a sub-module or a sub-package, its parent is imported. + In such cases, this function should be called from an isolated suprocess. + """ + try: + import importlib.util + spec = importlib.util.find_spec(module_name) + return bool(spec.submodule_search_locations) + except Exception: + return False + + # For top-level packages/modules, we can perform check in the main process; otherwise, we need to isolate the + # call to prevent import leaks in the main process. + if '.' not in module_name: + return _is_package(module_name) + else: + return isolated.call(_is_package, module_name) + + +def get_all_package_paths(package: str): + """ + Given a package name, return all paths associated with the package. Typically, packages have a single location + path, but PEP 420 namespace packages may be split across multiple locations. Returns an empty list if the specified + package is not found or is not a package. + """ + def _get_package_paths(package: str): + """ + Retrieve package path(s), as advertised by submodule_search_paths attribute of the spec obtained via + importlib.util.find_spec(package). If the name represents a top-level package, the package is not imported. + If the name represents a sub-module or a sub-package, its parent is imported. In such cases, this function + should be called from an isolated suprocess. Returns an empty list if specified package is not found or is not + a package. + """ + try: + import importlib.util + spec = importlib.util.find_spec(package) + if not spec or not spec.submodule_search_locations: + return [] + return [str(path) for path in spec.submodule_search_locations] + except Exception: + return [] + + # For top-level packages/modules, we can perform check in the main process; otherwise, we need to isolate the + # call to prevent import leaks in the main process. + if '.' not in package: + pkg_paths = _get_package_paths(package) + else: + pkg_paths = isolated.call(_get_package_paths, package) + + return pkg_paths + + +def package_base_path(package_path: str, package: str): + """ + Given a package location path and package name, return the package base path, i.e., the directory in which the + top-level package is located. For example, given the path ``/abs/path/to/python/libs/pkg/subpkg`` and + package name ``pkg.subpkg``, the function returns ``/abs/path/to/python/libs``. + """ + return remove_suffix(package_path, package.replace('.', os.sep)) # Base directory + + +def get_package_paths(package: str): + """ + Given a package, return the path to packages stored on this machine and also returns the path to this particular + package. For example, if pkg.subpkg lives in /abs/path/to/python/libs, then this function returns + ``(/abs/path/to/python/libs, /abs/path/to/python/libs/pkg/subpkg)``. + + NOTE: due to backwards compatibility, this function returns only one package path along with its base directory. + In case of PEP 420 namespace package with multiple location, only first location is returned. To obtain all + package paths, use the ``get_all_package_paths`` function and obtain corresponding base directories using the + ``package_base_path`` helper. + """ + pkg_paths = get_all_package_paths(package) + if not pkg_paths: + raise ValueError(f"Package '{package}' does not exist or is not a package!") + + if len(pkg_paths) > 1: + logger.warning( + "get_package_paths - package %s has multiple paths (%r); returning only first one!", package, pkg_paths + ) + + pkg_dir = pkg_paths[0] + pkg_base = package_base_path(pkg_dir, package) + + return pkg_base, pkg_dir + + +def collect_submodules( + package: str, + filter: Callable[[str], bool] = lambda name: True, + on_error: str = "warn once", +): + """ + List all submodules of a given package. + + Arguments: + package: + An ``import``-able package. + filter: + Filter the submodules found: A callable that takes a submodule name and returns True if it should be + included. + on_error: + The action to take when a submodule fails to import. May be any of: + + - raise: Errors are reraised and terminate the build. + - warn: Errors are downgraded to warnings. + - warn once: The first error issues a warning but all + subsequent errors are ignored to minimise *stderr pollution*. This + is the default. + - ignore: Skip all errors. Don't warn about anything. + Returns: + All submodules to be assigned to ``hiddenimports`` in a hook. + + This function is intended to be used by hook scripts, not by main PyInstaller code. + + Examples:: + + # Collect all submodules of Sphinx don't contain the word ``test``. + hiddenimports = collect_submodules( + "Sphinx", ``filter=lambda name: 'test' not in name) + + .. versionchanged:: 4.5 + Add the **on_error** parameter. + + """ + # Accept only strings as packages. + if not isinstance(package, str): + raise TypeError('package must be a str') + if on_error not in ("ignore", "warn once", "warn", "raise"): + raise ValueError( + f"Invalid on-error action '{on_error}': Must be one of ('ignore', 'warn once', 'warn', 'raise')" + ) + + logger.debug('Collecting submodules for %s', package) + + # Skip a module which is not a package. + if not is_package(package): + logger.debug('collect_submodules - %s is not a package.', package) + # If module is importable, return its name in the list, in order to keep behavior consistent with the + # one we have for packages (i.e., we include the package in the list of returned names) + if can_import_module(package): + return [package] + return [] + + # Determine the filesystem path(s) to the specified package. + package_submodules = [] + + todo = deque() + todo.append(package) + + with isolated.Python() as isolated_python: + while todo: + # Scan the given (sub)package + name = todo.pop() + modules, subpackages, on_error = isolated_python.call(_collect_submodules, name, on_error) + + # Add modules to the list of all submodules + package_submodules += [module for module in modules if filter(module)] + + # Add sub-packages to deque for subsequent recursion + for subpackage_name in subpackages: + if filter(subpackage_name): + todo.append(subpackage_name) + + package_submodules = sorted(package_submodules) + + logger.debug("collect_submodules - found submodules: %s", package_submodules) + return package_submodules + + +# This function is called in an isolated sub-process via `isolated.Python.call`. +def _collect_submodules(name, on_error): + import sys + import pkgutil + from traceback import format_exception_only + + from PyInstaller.utils.hooks import logger + + logger.debug("collect_submodules - scanning (sub)package %s", name) + + modules = [] + subpackages = [] + + # Resolve package location(s) + try: + __import__(name) + except Exception as ex: + # Catch all errors and either raise, warn, or ignore them as determined by the *on_error* parameter. + if on_error in ("warn", "warn once"): + from PyInstaller.log import logger + ex = "".join(format_exception_only(type(ex), ex)).strip() + logger.warning(f"Failed to collect submodules for '{name}' because importing '{name}' raised: {ex}") + if on_error == "warn once": + on_error = "ignore" + return modules, subpackages, on_error + elif on_error == "raise": + raise ImportError(f"Unable to load subpackage '{name}'.") from ex + + # Do not attempt to recurse into package if it did not make it into sys.modules. + if name not in sys.modules: + return modules, subpackages, on_error + + # Or if it does not have __path__ attribute. + paths = getattr(sys.modules[name], '__path__', None) or [] + if not paths: + return modules, subpackages, on_error + + # Package was successfully imported - include it in the list of modules. + modules.append(name) + + # Iterate package contents + logger.debug("collect_submodules - scanning (sub)package %s in location(s): %s", name, paths) + for importer, name, ispkg in pkgutil.iter_modules(paths, name + '.'): + if not ispkg: + modules.append(name) + else: + subpackages.append(name) + + return modules, subpackages, on_error + + +def is_module_or_submodule(name: str, mod_or_submod: str): + """ + This helper function is designed for use in the ``filter`` argument of :func:`collect_submodules`, by returning + ``True`` if the given ``name`` is a module or a submodule of ``mod_or_submod``. + + Examples: + + The following excludes ``foo.test`` and ``foo.test.one`` but not ``foo.testifier``. :: + + collect_submodules('foo', lambda name: not is_module_or_submodule(name, 'foo.test'))`` + """ + return name.startswith(mod_or_submod + '.') or name == mod_or_submod + + +# Patterns of dynamic library filenames that might be bundled with some installed Python packages. +PY_DYLIB_PATTERNS = [ + '*.dll', + '*.dylib', + 'lib*.so', +] + + +def collect_dynamic_libs(package: str, destdir: str | None = None, search_patterns: [str] = PY_DYLIB_PATTERNS): + """ + This function produces a list of (source, dest) of dynamic library files that reside in package. Its output can be + directly assigned to ``binaries`` in a hook script. The package parameter must be a string which names the package. + + :param destdir: Relative path to ./dist/APPNAME where the libraries should be put. + :param search_patterns: List of dynamic library filename patterns to collect. + """ + logger.debug('Collecting dynamic libraries for %s' % package) + + # Accept only strings as packages. + if not isinstance(package, str): + raise TypeError('package must be a str') + + # Skip a module which is not a package. + if not is_package(package): + logger.warning( + "collect_dynamic_libs - skipping library collection for module '%s' as it is not a package.", package + ) + return [] + + pkg_dirs = get_all_package_paths(package) + dylibs = [] + for pkg_dir in pkg_dirs: + pkg_base = package_base_path(pkg_dir, package) + # Recursively glob for all file patterns in the package directory + for pattern in search_patterns: + files = Path(pkg_dir).rglob(pattern) + for source in files: + # Produce the tuple ('/abs/path/to/source/mod/submod/file.pyd', 'mod/submod') + if destdir: + # Put libraries in the specified target directory. + dest = destdir + else: + # Preserve original directory hierarchy. + dest = source.parent.relative_to(pkg_base) + logger.debug(' %s, %s' % (source, dest)) + dylibs.append((str(source), str(dest))) + + return dylibs + + +def collect_data_files( + package: str, + include_py_files: bool = False, + subdir: str | os.PathLike | None = None, + excludes: list | None = None, + includes: list | None = None, +): + r""" + This function produces a list of ``(source, dest)`` non-Python (i.e., data) files that reside in ``package``. + Its output can be directly assigned to ``datas`` in a hook script; for example, see ``hook-sphinx.py``. + Parameters: + + - The ``package`` parameter is a string which names the package. + - By default, all Python executable files (those ending in ``.py``, ``.pyc``, and so on) will NOT be collected; + setting the ``include_py_files`` argument to ``True`` collects these files as well. This is typically used with + Python functions (such as those in ``pkgutil``) that search a given directory for Python executable files and + load them as extensions or plugins. + - The ``subdir`` argument gives a subdirectory relative to ``package`` to search, which is helpful when submodules + are imported at run-time from a directory lacking ``__init__.py``. + - The ``excludes`` argument contains a sequence of strings or Paths. These provide a list of + `globs `_ + to exclude from the collected data files; if a directory matches the provided glob, all files it contains will + be excluded as well. All elements must be relative paths, which are relative to the provided package's path + (/ ``subdir`` if provided). + + Therefore, ``*.txt`` will exclude only ``.txt`` files in ``package``\ 's path, while ``**/*.txt`` will exclude + all ``.txt`` files in ``package``\ 's path and all its subdirectories. Likewise, ``**/__pycache__`` will exclude + all files contained in any subdirectory named ``__pycache__``. + - The ``includes`` function like ``excludes``, but only include matching paths. ``excludes`` override + ``includes``: a file or directory in both lists will be excluded. + + This function does not work on zipped Python eggs. + + This function is intended to be used by hook scripts, not by main PyInstaller code. + """ + logger.debug('Collecting data files for %s' % package) + + # Accept only strings as packages. + if not isinstance(package, str): + raise TypeError('package must be a str') + + # Skip a module which is not a package. + if not is_package(package): + logger.warning("collect_data_files - skipping data collection for module '%s' as it is not a package.", package) + return [] + + # Make sure the excludes are a list; this also makes a copy, so we don't modify the original. + excludes = list(excludes) if excludes else [] + # These excludes may contain directories which need to be searched. + excludes_len = len(excludes) + # Including py files means don't exclude them. This pattern will search any directories for containing files, so + # do not modify ``excludes_len``. + if not include_py_files: + excludes += ['**/*' + s for s in compat.ALL_SUFFIXES] + + # Exclude .pyo files if include_py_files is False. + if not include_py_files and ".pyo" not in compat.ALL_SUFFIXES: + excludes.append('**/*.pyo') + + # If not specified, include all files. Follow the same process as the excludes. + includes = list(includes) if includes else ["**/*"] + includes_len = len(includes) + + # A helper function to glob the in/ex "cludes", adding a wildcard to refer to all files under a subdirectory if a + # subdirectory is matched by the first ``clude_len`` patterns. Otherwise, it in/excludes the matched file. + # **This modifies** ``cludes``. + def clude_walker( + # Package directory to scan + pkg_dir, + # A list of paths relative to ``pkg_dir`` to in/exclude. + cludes, + # The number of ``cludes`` for which matching directories should be searched for all files under them. + clude_len, + # True if the list is includes, False for excludes. + is_include + ): + for i, c in enumerate(cludes): + for g in Path(pkg_dir).glob(c): + if g.is_dir(): + # Only files are sources. Subdirectories are not. + if i < clude_len: + # In/exclude all files under a matching subdirectory. + cludes.append(str((g / "**/*").relative_to(pkg_dir))) + else: + # In/exclude a matching file. + sources.add(g) if is_include else sources.discard(g) + + # Obtain all paths for the specified package, and process each path independently. + datas = [] + + pkg_dirs = get_all_package_paths(package) + for pkg_dir in pkg_dirs: + sources = set() # Reset sources set + + pkg_base = package_base_path(pkg_dir, package) + if subdir: + pkg_dir = os.path.join(pkg_dir, subdir) + + # Process the package path with clude walker + clude_walker(pkg_dir, includes, includes_len, True) + clude_walker(pkg_dir, excludes, excludes_len, False) + + # Transform the sources into tuples for ``datas``. + datas += [(str(s), str(s.parent.relative_to(pkg_base))) for s in sources] + + logger.debug("collect_data_files - Found files: %s", datas) + return datas + + +def collect_system_data_files(path: str, destdir: str | os.PathLike | None = None, include_py_files: bool = False): + """ + This function produces a list of (source, dest) non-Python (i.e., data) files that reside somewhere on the system. + Its output can be directly assigned to ``datas`` in a hook script. + + This function is intended to be used by hook scripts, not by main PyInstaller code. + """ + # Accept only strings as paths. + if not isinstance(path, str): + raise TypeError('path must be a str') + + # Walk through all file in the given package, looking for data files. + datas = [] + for dirpath, dirnames, files in os.walk(path): + for f in files: + extension = os.path.splitext(f)[1] + if include_py_files or (extension not in PY_IGNORE_EXTENSIONS): + # Produce the tuple: (/abs/path/to/source/mod/submod/file.dat, mod/submod/destdir) + source = os.path.join(dirpath, f) + dest = str(Path(dirpath).relative_to(path)) + if destdir is not None: + dest = os.path.join(destdir, dest) + datas.append((source, dest)) + + return datas + + +def copy_metadata(package_name: str, recursive: bool = False): + """ + Collect distribution metadata so that ``pkg_resources.get_distribution()`` can find it. + + This function returns a list to be assigned to the ``datas`` global variable. This list instructs PyInstaller to + copy the metadata for the given package to the frozen application's data directory. + + Parameters + ---------- + package_name : str + Specifies the name of the package for which metadata should be copied. + recursive : bool + If true, collect metadata for the package's dependencies too. This enables use of + ``pkg_resources.require('package')`` inside the frozen application. + + Returns + ------- + list + This should be assigned to ``datas``. + + Examples + -------- + >>> from PyInstaller.utils.hooks import copy_metadata + >>> copy_metadata('sphinx') + [('c:\\python27\\lib\\site-packages\\Sphinx-1.3.2.dist-info', + 'Sphinx-1.3.2.dist-info')] + + + Some packages rely on metadata files accessed through the ``pkg_resources`` module. Normally PyInstaller does not + include these metadata files. If a package fails without them, you can use this function in a hook file to easily + add them to the frozen bundle. The tuples in the returned list have two strings. The first is the full pathname to a + folder in this system. The second is the folder name only. When these tuples are added to ``datas``\\ , the folder + will be bundled at the top level. + + .. versionchanged:: 4.3.1 + + Prevent ``dist-info`` metadata folders being renamed to ``egg-info`` which broke ``pkg_resources.require`` with + *extras* (see :issue:`#3033`). + + .. versionchanged:: 4.4.0 + + Add the **recursive** option. + """ + from collections import deque + + todo = deque([package_name]) + done = set() + out = [] + + while todo: + package_name = todo.pop() + if package_name in done: + continue + + dist = pkg_resources.get_distribution(package_name) + if dist.egg_info is not None: + # If available, dist.egg_info points to the source .egg-info or .dist-info directory. + dest = _copy_metadata_dest(dist.egg_info, dist.project_name) + out.append((dist.egg_info, dest)) + else: + # When .egg-info is not a directory but a single file, dist.egg_info is None, and we need to resolve the + # path ourselves. This format is common on Ubuntu/Debian with their deb-packaged python packages. + dist_src = _resolve_legacy_metadata_path(dist) + if dist_src is None: + raise RuntimeError( + f"No metadata path found for distribution '{dist.project_name}' (legacy fallback search failed)." + ) + out.append((dist_src, '.')) # It is a file, so dest path needs to be '.' + + if not recursive: + return out + done.add(package_name) + todo.extend(i.project_name for i in dist.requires()) + + return out + + +def _normalise_dist(name: str) -> str: + return name.lower().replace("_", "-") + + +def _resolve_legacy_metadata_path(dist): + """ + Attempt to resolve the legacy metadata file for the given distribution. + The .egg-info file is commonly used by Debian/Ubuntu when packaging python packages. + + Args: + dist: + The distribution information as returned by ``pkg_resources.get_distribution("xyz")``. + Returns: + The path to the distribution's metadata file. + """ + + candidates = [ + # This fallback was in place in pre-#5774 times. However, it is insufficient, because dist.egg_name() may be + # greenlet-0.4.15-py3.8 (Ubuntu 20.04 package) while the file we are searching for is greenlet-0.4.15.egg-info. + f"{dist.egg_name()}.egg-info", + # The extra name-version.egg-info path format + f"{dist.project_name}-{dist.version}.egg-info", + # And the name_with_underscores-version.egg-info.format + f"{dist.project_name.replace('-', '_')}-{dist.version}.egg-info", + ] + + # As an additional attempt, try to remove the-pyX.Y suffix from egg name. + pyxx_suffix = f"-py{sys.version_info[0]}.{sys.version_info[1]}" + if dist.egg_name().endswith(pyxx_suffix): + candidates.append(dist.egg_name()[:-len(pyxx_suffix)] + ".egg-info") + + for candidate in candidates: + candidate_path = os.path.join(dist.location, candidate) + if os.path.isfile(candidate_path): + return candidate_path + + return None + + +def _copy_metadata_dest(egg_path: str, project_name: str) -> str: + """ + Choose an appropriate destination path for a distribution's metadata. + + Args: + egg_path: + The output of ``pkg_resources.get_distribution("xyz").egg_info``: a full path to the source + ``xyz-version.dist-info`` or ``xyz-version.egg-info`` folder containing package metadata. + project_name: + The distribution name given. + Returns: + The *dest* parameter: where in the bundle should this folder go. + Raises: + RuntimeError: + If **egg_path** is None, i.e., no metadata is found. + """ + if egg_path is None: + # According to older implementations of this function, packages may have no metadata. I have no idea how this + # can happen... + raise RuntimeError(f"No metadata path found for distribution '{project_name}'.") + + egg_path = Path(egg_path) + _project_name = _normalise_dist(project_name) + + # There has been a fair amount of whack-a-mole fixing to this step. If new cases appear which this function cannot + # handle, add them to the corresponding test: + # tests/unit/test_hookutils.py::test_copy_metadata_dest() + # See there also for example input/outputs. + + # The most obvious answer is that the metadata folder should have the same name in a PyInstaller build as it does + # normally:: + if _normalise_dist(egg_path.name).startswith(_project_name): + # e.g., .../lib/site-packages/xyz-1.2.3.dist-info + return egg_path.name + + # Using just the base-name breaks for an egg_path of the form: + # '.../site-packages/xyz-version.win32.egg/EGG-INFO' + # because multiple collected metadata folders will be written to the same name 'EGG-INFO' and clobber each other + # (see #1888). In this case, the correct behaviour appears to be to use the last two parts of the path: + if len(egg_path.parts) >= 2: + if _normalise_dist(egg_path.parts[-2]).startswith(_project_name): + return os.path.join(*egg_path.parts[-2:]) + + # This is something unheard of. + raise RuntimeError( + f"Unknown metadata type '{egg_path}' from the '{project_name}' distribution. Please report this at " + f"https://github/pyinstaller/pyinstaller/issues." + ) + + +def get_installer(module: str): + """ + Try to find which package manager installed a module. + + :param module: Module to check + :return: Package manager or None + """ + file_name = get_module_file_attribute(module) + site_dir = file_name[:file_name.index('site-packages') + len('site-packages')] + # This is necessary for situations where the project name and module name do not match, e.g., + # pyenchant (project name) vs. enchant (module name). + pkgs = pkg_resources.find_distributions(site_dir) + package = None + for pkg in pkgs: + if module.lower() in pkg.key: + package = pkg + break + metadata_dir, dest_dir = copy_metadata(package)[0] + # Check for an INSTALLER file in the metedata_dir and return the first line which should be the program that + # installed the module. + installer_file = os.path.join(metadata_dir, 'INSTALLER') + if os.path.isdir(metadata_dir) and os.path.exists(installer_file): + with open(installer_file, 'r') as installer_file_object: + lines = installer_file_object.readlines() + if lines[0] != '': + installer = lines[0].rstrip('\r\n') + logger.debug( + "Found installer: '{0}' for module: '{1}' from package: '{2}'".format(installer, module, package) + ) + return installer + if compat.is_darwin: + try: + output = compat.exec_command_stdout('port', 'provides', file_name) + if 'is provided by' in output: + logger.debug( + "Found installer: 'macports' for module: '{0}' from package: '{1}'".format(module, package) + ) + return 'macports' + except ExecCommandFailed: + pass + real_path = os.path.realpath(file_name) + if 'Cellar' in real_path: + logger.debug("Found installer: 'homebrew' for module: '{0}' from package: '{1}'".format(module, package)) + return 'homebrew' + return None + + +# ``_map_distribution_to_packages`` is expensive. Compute it when used, then return the memoized value. This is a simple +# alternative to ``functools.lru_cache``. +def _memoize(f): + memo = [] + + def helper(): + if not memo: + memo.append(f()) + return memo[0] + + return helper + + +# Walk through every package, determining to which distribution it belongs. +@_memoize +def _map_distribution_to_packages(): + logger.info('Determining a mapping of distributions to packages...') + dist_to_packages = {} + for p in sys.path: + # The path entry ``''`` refers to the current directory. + if not p: + p = '.' + # Ignore any entries in ``sys.path`` that do not exist. + try: + lds = os.listdir(p) + except Exception: + pass + else: + for ld in lds: + # Not all packages belong to a distribution. Skip these. + try: + dist = pkg_resources.get_distribution(ld) + except Exception: + pass + else: + dist_to_packages.setdefault(dist.key, []).append(ld) + + return dist_to_packages + + +# Given a ``package_name`` as a string, this function returns a list of packages needed to satisfy the requirements. +# This output can be assigned directly to ``hiddenimports``. +def requirements_for_package(package_name: str): + hiddenimports = [] + + dist_to_packages = _map_distribution_to_packages() + for requirement in pkg_resources.get_distribution(package_name).requires(): + if requirement.key in dist_to_packages: + required_packages = dist_to_packages[requirement.key] + hiddenimports.extend(required_packages) + else: + logger.warning( + 'Unable to find package for requirement %s from package %s.', requirement.project_name, package_name + ) + + logger.info('Packages required by %s:\n%s', package_name, hiddenimports) + return hiddenimports + + +def collect_all( + package_name: str, + include_py_files: bool = True, + filter_submodules: Callable | None = None, + exclude_datas: list | None = None, + include_datas: list | None = None, + on_error: str = "warn once", +): + """ + Collect everything for a given package name. + + Arguments: + package_name: + An ``import``-able package name. + include_py_files: + Forwarded to :func:`collect_data_files`. + filter_submodules: + Forwarded to :func:`collect_submodules`. + exclude_datas: + Forwarded to :func:`collect_data_files`. + include_datas: + Forwarded to :func:`collect_data_files`. + on_error: + Forwarded onto :func:`collect_submodules`. + + Returns: + tuple: A ``(datas, binaries, hiddenimports)`` triplet containing: + + - All data files, raw Python files (if **include_py_files**), and package metadata folders. + - All dynamic libraries as returned by :func:`collect_dynamic_libs`. + - All submodules of **packagename** and its dependencies. + + Typical use:: + + datas, binaries, hiddenimports = collect_all('my_module_name') + """ + datas = [] + try: + datas += copy_metadata(package_name) + except Exception as e: + logger.warning('Unable to copy metadata for %s: %s', package_name, e) + datas += collect_data_files(package_name, include_py_files, excludes=exclude_datas, includes=include_datas) + binaries = collect_dynamic_libs(package_name) + if filter_submodules: + hiddenimports = collect_submodules(package_name, on_error=on_error, filter=filter_submodules) + else: + hiddenimports = collect_submodules(package_name) + try: + hiddenimports += requirements_for_package(package_name) + except Exception as e: + logger.warning('Unable to determine requirements for %s: %s', package_name, e) + + return datas, binaries, hiddenimports + + +def collect_entry_point(name: str): + """ + Collect modules and metadata for all exporters of a given entry point. + + Args: + name: + The name of the entry point. Check the documentation for the library that uses the entry point to find + its name. + Returns: + A ``(datas, hiddenimports)`` pair that should be assigned to the ``datas`` and ``hiddenimports``, respectively. + + For libraries, such as ``pytest`` or ``keyring``, that rely on plugins to extend their behaviour. + + Examples: + Pytest uses an entry point called ``'pytest11'`` for its extensions. + To collect all those extensions use:: + + datas, hiddenimports = collect_entry_point("pytest11") + + These values may be used in a hook or added to the ``datas`` and ``hiddenimports`` arguments in the ``.spec`` + file. See :ref:`using spec files`. + + .. versionadded:: 4.3 + """ + import pkg_resources + datas = [] + imports = [] + for dist in pkg_resources.iter_entry_points(name): + project_name = '' if dist.dist is None else dist.dist.project_name + datas += copy_metadata(project_name) + imports.append(dist.module_name) + return datas, imports + + +def get_hook_config(hook_api: PostGraphAPI, module_name: str, key: str): + """ + Get user settings for hooks. + + Args: + module_name: + The module/package for which the key setting belong to. + key: + A key for the config. + Returns: + The value for the config. ``None`` if not set. + + The ``get_hook_config`` function will lookup settings in the ``Analysis.hooksconfig`` dict. + + The hook settings can be added to ``.spec`` file in the form of:: + + a = Analysis(["my-app.py"], + ... + hooksconfig = { + "gi": { + "icons": ["Adwaita"], + "themes": ["Adwaita"], + "languages": ["en_GB", "zh_CN"], + }, + }, + ... + ) + """ + config = hook_api.analysis.hooksconfig + value = None + if module_name in config and key in config[module_name]: + value = config[module_name][key] + return value + + +def include_or_exclude_file( + filename: str, + include_list: list | None = None, + exclude_list: list | None = None, +): + """ + Generic inclusion/exclusion decision function based on filename and list of include and exclude patterns. + + Args: + filename: + Filename considered for inclusion. + include_list: + List of inclusion file patterns. + exclude_list: + List of exclusion file patterns. + + Returns: + A boolean indicating whether the file should be included or not. + + If ``include_list`` is provided, True is returned only if the filename matches one of include patterns (and does not + match any patterns in ``exclude_list``, if provided). If ``include_list`` is not provided, True is returned if + filename does not match any patterns in ``exclude list``, if provided. If neither list is provided, True is + returned for any filename. + """ + if include_list is not None: + for pattern in include_list: + if fnmatch.fnmatch(filename, pattern): + break + else: + return False # Not explicitly included; exclude + + if exclude_list is not None: + for pattern in exclude_list: + if fnmatch.fnmatch(filename, pattern): + return False # Explicitly excluded + + return True + + +def collect_delvewheel_libs_directory(package_name, libdir_name=None, datas=None, binaries=None): + """ + Collect data files and binaries from the .libs directory of a delvewheel-enabled python wheel. Such wheels ship + their shared libraries in a .libs directory that is located next to the package directory, and therefore falls + outside the purview of the collect_dynamic_libs() utility function. + + Args: + package_name: + Name of the package (e.g., scipy). + libdir_name: + Optional name of the .libs directory (e.g., scipy.libs). If not provided, ".libs" is added to + ``package_name``. + datas: + Optional list of datas to which collected data file entries are added. The combined result is retuned + as part of the output tuple. + binaries: + Optional list of binaries to which collected binaries entries are added. The combined result is retuned + as part of the output tuple. + + Returns: + tuple: A ``(datas, binaries)`` pair that should be assigned to the ``datas`` and ``binaries``, respectively. + + Examples: + Collect the ``scipy.libs`` delvewheel directory belonging to the Windows ``scipy`` wheel:: + + datas, binaries = collect_delvewheel_libs_directory("scipy") + + When the collected entries should be added to existing ``datas`` and ``binaries`` listst, the following form + can be used to avoid using intermediate temporary variables and merging those into existing lists:: + + datas, binaries = collect_delvewheel_libs_directory("scipy", datas=datas, binaries=binaries) + + .. versionadded:: 5.6 + """ + + datas = datas or [] + binaries = binaries or [] + + if libdir_name is None: + libdir_name = package_name + '.libs' + + # delvewheel is applicable only to Windows wheels + if not compat.is_win: + return datas, binaries + + # Get package's parent path + pkg_base, pkg_dir = get_package_paths(package_name) + pkg_base = Path(pkg_base) + libs_dir = pkg_base / libdir_name + + if not libs_dir.is_dir(): + return datas, binaries + + # Collect all dynamic libs - collect them as binaries in order to facilitate proper binary dependency analysis + # (for example, to ensure that system-installed VC runtime DLLs are collected, if needed). + # As of PyInstaller 5.4, this should be safe (should not result in duplication), because binary dependency + # analysis attempts to preserve the DLL directory structure. + binaries += [(str(dll_file), str(dll_file.parent.relative_to(pkg_base))) for dll_file in libs_dir.glob('*.dll')] + + # Collect the .load-order file; strictly speaking, this should be necessary only under python < 3.8, but let us + # collect it for completeness sake. Differently named variants have been observed: `.load_order`, `.load-order`, + # and `.load-order-Name`. + datas += [(str(load_order_file), str(load_order_file.parent.relative_to(pkg_base))) + for load_order_file in libs_dir.glob('.load[-_]order*')] + + return datas, binaries + + +if compat.is_pure_conda: + from PyInstaller.utils.hooks import conda as conda_support # noqa: F401 +elif compat.is_conda: + from PyInstaller.utils.hooks.conda import CONDA_META_DIR as _tmp + logger.warning( + "Assuming this is not an Anaconda environment or an additional venv/pipenv/... environment manager is being " + "used on top, because the conda-meta folder %s does not exist.", _tmp + ) + del _tmp diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/conda.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/conda.py new file mode 100755 index 000000000..8c2374a67 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/conda.py @@ -0,0 +1,400 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# language=rst +""" +Additional helper methods for working specifically with Anaconda distributions are found at +:mod:`PyInstaller.utils.hooks.conda_support` +which is designed to mimic (albeit loosely) the `importlib.metadata`_ package. These functions find and parse the +distribution metadata from json files located in the ``conda-meta`` directory. + +.. versionadded:: 4.2.0 + +This module is available only if run inside a Conda environment. Usage of this module should therefore be wrapped in +a conditional clause:: + + from PyInstaller.compat import is_pure_conda + + if is_pure_conda: + from PyInstaller.utils.hooks import conda_support + + # Code goes here. e.g. + binaries = conda_support.collect_dynamic_libs("numpy") + ... + +Packages are all referenced by the *distribution name* you use to install it, rather than the *package name* you import +it with. I.e., use ``distribution("pillow")`` instead of ``distribution("PIL")`` or use ``package_distribution("PIL")``. +""" +from __future__ import annotations + +import fnmatch +import json +import sys +from pathlib import Path +from typing import Iterable, List + +from PyInstaller import compat +from PyInstaller.log import logger + +if compat.is_py38: + from importlib.metadata import PackagePath as _PackagePath +else: + from importlib_metadata import PackagePath as _PackagePath + +# Conda virtual environments each get their own copy of `conda-meta` so the use of `sys.prefix` instead of +# `sys.base_prefix`, `sys.real_prefix` or anything from our `compat` module is intentional. +CONDA_ROOT = Path(sys.prefix) +CONDA_META_DIR = CONDA_ROOT / "conda-meta" + +# Find all paths in `sys.path` that are inside Conda root. +PYTHONPATH_PREFIXES = [] +for _path in sys.path: + _path = Path(_path) + try: + PYTHONPATH_PREFIXES.append(_path.relative_to(sys.prefix)) + except ValueError: + pass + +PYTHONPATH_PREFIXES.sort(key=lambda p: len(p.parts), reverse=True) + + +class Distribution: + """ + A bucket class representation of a Conda distribution. + + This bucket exports the following attributes: + + :ivar name: The distribution's name. + :ivar version: Its version. + :ivar files: All filenames as :meth:`PackagePath`\\ s included with this distribution. + :ivar dependencies: Names of other distributions that this distribution depends on (with version constraints + removed). + :ivar packages: Names of importable packages included in this distribution. + + This class is not intended to be constructed directly by users. Rather use :meth:`distribution` or + :meth:`package_distribution` to provide one for you. + """ + def __init__(self, json_path: str): + try: + self._json_path = Path(json_path) + assert self._json_path.exists() + except (TypeError, AssertionError): + raise TypeError( + "Distribution requires a path to a conda-meta json. Perhaps you want " + "`distribution({})` instead?".format(repr(json_path)) + ) + + # Everything we need (including this distribution's name) is kept in the metadata json. + self.raw: dict = json.loads(self._json_path.read_text()) + + # Unpack the more useful contents of the json. + self.name: str = self.raw["name"] + self.version: str = self.raw["version"] + self.files = [PackagePath(i) for i in self.raw["files"]] + self.dependencies = self._init_dependencies() + self.packages = self._init_package_names() + + def __repr__(self): + return "{}(name=\"{}\", packages={})".format(type(self).__name__, self.name, self.packages) + + def _init_dependencies(self): + """ + Read dependencies from ``self.raw["depends"]``. + + :return: Dependent distribution names. + :rtype: list + + The names in ``self.raw["depends"]`` come with extra version constraint information which must be stripped. + """ + dependencies = [] + # For each dependency: + for dependency in self.raw["depends"]: + # ``dependency`` is a string of the form: "[name] [version constraints]" + name, *version_constraints = dependency.split(maxsplit=1) + dependencies.append(name) + return dependencies + + def _init_package_names(self): + """ + Search ``self.files`` for package names shipped by this distribution. + + :return: Package names. + :rtype: list + + These are names you would ``import`` rather than names you would install. + """ + packages = [] + for file in self.files: + package = _get_package_name(file) + if package is not None: + packages.append(package) + return packages + + @classmethod + def from_name(cls, name: str): + """ + Get distribution information for a given distribution **name** (i.e., something you would ``conda install``). + + :rtype: :class:`Distribution` + """ + if name in distributions: + return distributions[name] + raise ModuleNotFoundError( + "Distribution {} is either not installed or was not installed using Conda.".format(name) + ) + + @classmethod + def from_package_name(cls, name: str): + """ + Get distribution information for a **package** (i.e., something you would import). + + :rtype: :class:`Distribution` + + For example, the package ``pkg_resources`` belongs to the distribution ``setuptools``, which contains three + packages. + + >>> package_distribution("pkg_resources") + Distribution(name="setuptools", + packages=['easy_install', 'pkg_resources', 'setuptools']) + """ + if name in distributions_by_package: + return distributions_by_package[name] + raise ModuleNotFoundError("Package {} is either not installed or was not installed using Conda.".format(name)) + + +distribution = Distribution.from_name +package_distribution = Distribution.from_package_name + + +class PackagePath(_PackagePath): + """ + A filename relative to Conda's root (``sys.prefix``). + + This class inherits from :class:`pathlib.PurePosixPath` even on non-Posix OSs. To convert to a :class:`pathlib.Path` + pointing to the real file, use the :meth:`locate` method. + """ + def locate(self): + """ + Return a path-like object for this path pointing to the file's true location. + """ + return Path(sys.prefix) / self + + +def walk_dependency_tree(initial: str, excludes: Iterable[str] | None = None): + """ + Collect a :class:`Distribution` and all direct and indirect dependencies of that distribution. + + Arguments: + initial: + Distribution name to collect from. + excludes: + Distributions to exclude. + Returns: + A ``{name: distribution}`` mapping where ``distribution`` is the output of + :func:`conda_support.distribution(name) `. + """ + if excludes is not None: + excludes = set(excludes) + + # Rather than use true recursion, mimic it with a to-do queue. + from collections import deque + done = {} + names_to_do = deque([initial]) + + while names_to_do: + # Grab a distribution name from the to-do list. + name = names_to_do.pop() + try: + # Collect and save it's metadata. + done[name] = distribution = Distribution.from_name(name) + logger.debug("Collected Conda distribution '%s', a dependency of '%s'.", name, initial) + except ModuleNotFoundError: + logger.warning( + "Conda distribution '%s', dependency of '%s', was not found. " + "If you installed this distribution with pip then you may ignore this warning.", name, initial + ) + continue + # For each dependency: + for _name in distribution.dependencies: + if _name in done: + # Skip anything already done. + continue + if _name == name: + # Avoid infinite recursion if a distribution depends on itself. This will probably never happen but I + # certainly would not chance it. + continue + if excludes is not None and _name in excludes: + # Do not recurse to excluded dependencies. + continue + names_to_do.append(_name) + return done + + +def _iter_distributions(name, dependencies, excludes): + if dependencies: + return walk_dependency_tree(name, excludes).values() + else: + return [Distribution.from_name(name)] + + +def requires(name: str, strip_versions: bool = False) -> List[str]: + """ + List requirements of a distribution. + + Arguments: + name: + The name of the distribution. + strip_versions: + List only their names, not their version constraints. + Returns: + A list of distribution names. + """ + if strip_versions: + return distribution(name).dependencies + return distribution(name).raw["depends"] + + +def files(name: str, dependencies: bool = False, excludes: list | None = None) -> List[PackagePath]: + """ + List all files belonging to a distribution. + + Arguments: + name: + The name of the distribution. + dependencies: + Recursively collect files of dependencies too. + excludes: + Distributions to ignore if **dependencies** is true. + Returns: + All filenames belonging to the given distribution. + + With ``dependencies=False``, this is just a shortcut for:: + + conda_support.distribution(name).files + """ + return [file for dist in _iter_distributions(name, dependencies, excludes) for file in dist.files] + + +if compat.is_win: + lib_dir = PackagePath("Library", "bin") +else: + lib_dir = PackagePath("lib") + + +def collect_dynamic_libs(name: str, dest: str = ".", dependencies: bool = True, excludes: Iterable[str] | None = None): + """ + Collect DLLs for distribution **name**. + + Arguments: + name: + The distribution's project-name. + dest: + Target destination, defaults to ``'.'``. + dependencies: + Recursively collect libs for dependent distributions (recommended). + excludes: + Dependent distributions to skip, defaults to ``None``. + Returns: + List of DLLs in PyInstaller's ``(source, dest)`` format. + + This collects libraries only from Conda's shared ``lib`` (Unix) or ``Library/bin`` (Windows) folders. To collect + from inside a distribution's installation use the regular :func:`PyInstaller.utils.hooks.collect_dynamic_libs`. + """ + DLL_SUFFIXES = ("*.dll", "*.dylib", "*.so", "*.so.*") + _files = [] + for file in files(name, dependencies, excludes): + # A file is classified as a dynamic library if: + # 1) it lives inside the dedicated ``lib_dir`` DLL folder + if file.parent != lib_dir: + continue + # 2) it is a file (and not a directory or a symbolic link pointing to a directory) + resolved_file = file.locate() + if not resolved_file.is_file(): + continue + # 3) has a correct suffix + if not any([resolved_file.match(suffix) for suffix in DLL_SUFFIXES]): + continue + + _files.append((str(resolved_file), dest)) + return _files + + +# --- Map packages to distributions and vice-versa --- + + +def _get_package_name(file: PackagePath): + """ + Determine the package name of a Python file in :data:`sys.path`. + + Arguments: + file: + A Python filename relative to Conda root (sys.prefix). + Returns: + Package name or None. + + This function only considers single file packages e.g. ``foo.py`` or top level ``foo/__init__.py``\\ s. + Anything else is ignored (returning ``None``). + """ + file = Path(file) + # TODO: Handle PEP 420 namespace packages (which are missing `__init__` module). No such Conda PEP 420 namespace + # packages are known. + + # Get top-level folders by finding parents of `__init__.xyz`s + if file.stem == "__init__" and file.suffix in compat.ALL_SUFFIXES: + file = file.parent + elif file.suffix not in compat.ALL_SUFFIXES: + # Keep single-file packages but skip DLLs, data and junk files. + return + + # Check if this file/folder's parent is in ``sys.path`` i.e. it's directly importable. This intentionally excludes + # submodules which would cause confusion because ``sys.prefix`` is in ``sys.path``, meaning that every file in an + # Conda installation is a submodule. + for prefix in PYTHONPATH_PREFIXES: + if len(file.parts) != len(prefix.parts) + 1: + # This check is redundant but speeds it up quite a bit. + continue + # There are no wildcards involved here. The use of ``fnmatch`` is simply to handle the `if case-insensitive + # file system: use case-insensitive string matching.` + if fnmatch.fnmatch(str(file.parent), str(prefix)): + return file.stem + + +# All the information we want is organised the wrong way. + +# We want to look up distribution based on package names, but we can only search for packages using distribution names. +# And we would like to search for a distribution's json file, but, due to the noisy filenames of the jsons, we can only +# find a json's distribution rather than a distribution's json. + +# So we have to read everything, then regroup distributions in the ways we want them grouped. This will likely be a +# spectacular bottleneck on full-blown Conda (non miniconda) with 250+ packages by default at several GiBs. I suppose we +# could cache this on a per-json basis if it gets too much. + + +def _init_distributions(): + distributions = {} + for path in CONDA_META_DIR.glob("*.json"): + dist = Distribution(path) + distributions[dist.name] = dist + return distributions + + +distributions = _init_distributions() + + +def _init_packages(): + distributions_by_package = {} + for distribution in distributions.values(): + for package in distribution.packages: + distributions_by_package[package] = distribution + return distributions_by_package + + +distributions_by_package = _init_packages() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/django.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/django.py new file mode 100755 index 000000000..565277865 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/django.py @@ -0,0 +1,151 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +# ---------------------------------------------------------------------------- +import os + +from PyInstaller import isolated + + +@isolated.decorate +def django_dottedstring_imports(django_root_dir): + """ + An isolated helper that returns list of all Django dependencies, parsed from the `mysite.settings` module. + + NOTE: With newer version of Django this is most likely the part of PyInstaller that will be broken. + + Tested with Django 2.2 + """ + + import sys + import os + + import PyInstaller.utils.misc + from PyInstaller.utils import hooks as hookutils + + # Extra search paths to add to sys.path: + # - parent directory of the django_root_dir + # - django_root_dir itself; often, Django users do not specify absolute imports in the settings module. + search_paths = [ + PyInstaller.utils.misc.get_path_to_toplevel_modules(django_root_dir), + django_root_dir, + ] + sys.path += search_paths + + # Set the path to project's settings module + default_settings_module = os.path.basename(django_root_dir) + '.settings' + settings_module = os.environ.get('DJANGO_SETTINGS_MODULE', default_settings_module) + os.environ['DJANGO_SETTINGS_MODULE'] = settings_module + + # Calling django.setup() avoids the exception AppRegistryNotReady() and also reads the user settings + # from DJANGO_SETTINGS_MODULE. + # https://stackoverflow.com/questions/24793351/django-appregistrynotready + import django # noqa: E402 + + django.setup() + + # This allows to access all django settings even from the settings.py module. + from django.conf import settings # noqa: E402 + + hiddenimports = list(settings.INSTALLED_APPS) + + # Do not fail script when settings does not have such attributes. + if hasattr(settings, 'TEMPLATE_CONTEXT_PROCESSORS'): + hiddenimports += list(settings.TEMPLATE_CONTEXT_PROCESSORS) + + if hasattr(settings, 'TEMPLATE_LOADERS'): + hiddenimports += list(settings.TEMPLATE_LOADERS) + + hiddenimports += [settings.ROOT_URLCONF] + + def _remove_class(class_name): + return '.'.join(class_name.split('.')[0:-1]) + + #-- Changes in Django 1.7. + + # Remove class names and keep just modules. + if hasattr(settings, 'AUTHENTICATION_BACKENDS'): + for cl in settings.AUTHENTICATION_BACKENDS: + cl = _remove_class(cl) + hiddenimports.append(cl) + if hasattr(settings, 'DEFAULT_FILE_STORAGE'): + cl = _remove_class(settings.DEFAULT_FILE_STORAGE) + hiddenimports.append(cl) + if hasattr(settings, 'FILE_UPLOAD_HANDLERS'): + for cl in settings.FILE_UPLOAD_HANDLERS: + cl = _remove_class(cl) + hiddenimports.append(cl) + if hasattr(settings, 'MIDDLEWARE_CLASSES'): + for cl in settings.MIDDLEWARE_CLASSES: + cl = _remove_class(cl) + hiddenimports.append(cl) + # Templates is a dict: + if hasattr(settings, 'TEMPLATES'): + for templ in settings.TEMPLATES: + backend = _remove_class(templ['BACKEND']) + hiddenimports += backend + # Include context_processors. + if hasattr(templ, 'OPTIONS'): + if hasattr(templ['OPTIONS'], 'context_processors'): + # Context processors are functions - strip last word. + mods = templ['OPTIONS']['context_processors'] + mods = [_remove_class(x) for x in mods] + hiddenimports += mods + # Include database backends - it is a dict. + for v in settings.DATABASES.values(): + hiddenimports.append(v['ENGINE']) + + # Add templatetags and context processors for each installed app. + for app in settings.INSTALLED_APPS: + app_templatetag_module = app + '.templatetags' + app_ctx_proc_module = app + '.context_processors' + hiddenimports.append(app_templatetag_module) + hiddenimports += hookutils.collect_submodules(app_templatetag_module) + hiddenimports.append(app_ctx_proc_module) + + # Deduplicate imports. + hiddenimports = list(set(hiddenimports)) + + # Return the hidden imports + return hiddenimports + + +def django_find_root_dir(): + """ + Return path to directory (top-level Python package) that contains main django files. Return None if no directory + was detected. + + Main Django project directory contain files like '__init__.py', 'settings.py' and 'url.py'. + + In Django 1.4+ the script 'manage.py' is not in the directory with 'settings.py' but usually one level up. We + need to detect this special case too. + """ + # 'PyInstaller.config' cannot be imported as other top-level modules. + from PyInstaller.config import CONF + + # Get the directory with manage.py. Manage.py is supplied to PyInstaller as the first main executable script. + manage_py = CONF['main_script'] + manage_dir = os.path.dirname(os.path.abspath(manage_py)) + + # Get the Django root directory. The directory that contains settings.py and url.py. It could be the directory + # containing manage.py or any of its subdirectories. + settings_dir = None + files = set(os.listdir(manage_dir)) + if ('settings.py' in files or 'settings' in files) and 'urls.py' in files: + settings_dir = manage_dir + else: + for f in files: + if os.path.isdir(os.path.join(manage_dir, f)): + subfiles = os.listdir(os.path.join(manage_dir, f)) + # Subdirectory contains critical files. + if ('settings.py' in subfiles or 'settings' in subfiles) and 'urls.py' in subfiles: + settings_dir = os.path.join(manage_dir, f) + break # Find the first directory. + + return settings_dir diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/gi.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/gi.py new file mode 100755 index 000000000..6066aa409 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/gi.py @@ -0,0 +1,426 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +# ---------------------------------------------------------------------------- +import os +import pathlib +import shutil +import subprocess +import hashlib +import re + +from PyInstaller.depend.utils import _resolveCtypesImports +from PyInstaller.utils.hooks import collect_submodules, collect_system_data_files, get_hook_config +from PyInstaller import isolated +from PyInstaller import log as logging +from PyInstaller import compat +from PyInstaller.depend.bindepend import findSystemLibrary + +logger = logging.getLogger(__name__) + + +class GiModuleInfo: + def __init__(self, module, version, hook_api=None): + self.name = module + self.version = version + self.available = False + self.sharedlibs = [] + self.typelib = None + self.dependencies = [] + + # If hook API is available, use it to override the version from hookconfig. + if hook_api is not None: + module_versions = get_hook_config(hook_api, 'gi', 'module-versions') + if module_versions: + self.version = module_versions.get(module, version) + + logger.debug("Gathering GI module info for %s %s", module, self.version) + + @isolated.decorate + def _get_module_info(module, version): + import gi + gi.require_version("GIRepository", "2.0") + from gi.repository import GIRepository + + repo = GIRepository.Repository.get_default() + repo.require(module, version, GIRepository.RepositoryLoadFlags.IREPOSITORY_LOAD_FLAG_LAZY) + + # Shared library/libraries + # Comma-separated list of paths to shared libraries, or None if none are associated. Convert to list. + sharedlibs = repo.get_shared_library(module) + sharedlibs = [lib.strip() for lib in sharedlibs.split(",")] if sharedlibs else [] + + # Path to .typelib file + typelib = repo.get_typelib_path(module) + + # Dependencies + # GIRepository.Repository.get_immediate_dependencies is available from gobject-introspection v1.44 on + if hasattr(repo, 'get_immediate_dependencies'): + dependencies = repo.get_immediate_dependencies(module) + else: + dependencies = repo.get_dependencies(module) + + return { + 'sharedlibs': sharedlibs, + 'typelib': typelib, + 'dependencies': dependencies, + } + + # Try to query information; if this fails, mark module as unavailable. + try: + info = _get_module_info(module, self.version) + self.sharedlibs = info['sharedlibs'] + self.typelib = info['typelib'] + self.dependencies = info['dependencies'] + self.available = True + except Exception as e: + logger.debug("Failed to query GI module %s %s: %s", module, self.version, e) + self.available = False + + def get_libdir(self): + """ + Return the path to shared library used by the module. If no libraries are associated with the typelib, None is + returned. If multiple library names are associated with the typelib, the path to the first resolved shared + library is returned. Raises exception if module is unavailable or none of the shared libraries could be + resolved. + """ + # Module unavailable + if not self.available: + raise ValueError(f"Module {self.name} {self.version} is unavailable!") + # Module has no associated shared libraries + if not self.sharedlibs: + return None + for lib in self.sharedlibs: + path = findSystemLibrary(lib) + if path: + return os.path.normpath(os.path.dirname(path)) + raise ValueError(f"Could not resolve any shared library of {self.name} {self.version}: {self.sharedlibs}!") + + def collect_typelib_data(self): + """ + Return a tuple of (binaries, datas, hiddenimports) to be used by PyGObject related hooks. + """ + datas = [] + binaries = [] + hiddenimports = [] + + logger.debug("Collecting module data for %s %s", self.name, self.version) + + # Module unavailable + if not self.available: + raise ValueError(f"Module {self.name} {self.version} is unavailable!") + + # Find shared libraries + resolved_libs = _resolveCtypesImports(self.sharedlibs) + for resolved_lib in resolved_libs: + logger.debug("Collecting shared library %s at %s", resolved_lib[0], resolved_lib[1]) + binaries.append((resolved_lib[1], ".")) + + # Find and collect .typelib file. Run it through the `gir_library_path_fix` to fix the library path, if + # necessary. + typelib_entry = gir_library_path_fix(self.typelib) + if typelib_entry: + logger.debug('Collecting gir typelib at %s', typelib_entry[0]) + datas.append(typelib_entry) + + # Overrides for the module + hiddenimports += collect_submodules('gi.overrides', lambda name: name.endswith('.' + self.name)) + + # Module dependencies + for dep in self.dependencies: + dep_module, _ = dep.rsplit('-', 1) + hiddenimports += [f'gi.repository.{dep_module}'] + + return binaries, datas, hiddenimports + + +# The old function, provided for backwards compatibility in 3rd party hooks. +def get_gi_libdir(module, version): + module_info = GiModuleInfo(module, version) + return module_info.get_libdir() + + +# The old function, provided for backwards compatibility in 3rd party hooks. +def get_gi_typelibs(module, version): + """ + Return a tuple of (binaries, datas, hiddenimports) to be used by PyGObject related hooks. Searches for and adds + dependencies recursively. + + :param module: GI module name, as passed to 'gi.require_version()' + :param version: GI module version, as passed to 'gi.require_version()' + """ + module_info = GiModuleInfo(module, version) + return module_info.collect_typelib_data() + + +def gir_library_path_fix(path): + import subprocess + + # 'PyInstaller.config' cannot be imported as other top-level modules. + from PyInstaller.config import CONF + + path = os.path.abspath(path) + + # On Mac OS we need to recompile the GIR files to reference the loader path, + # but this is not necessary on other platforms. + if compat.is_darwin: + + # If using a virtualenv, the base prefix and the path of the typelib + # have really nothing to do with each other, so try to detect that. + common_path = os.path.commonprefix([compat.base_prefix, path]) + if common_path == '/': + logger.debug("virtualenv detected? fixing the gir path...") + common_path = os.path.abspath(os.path.join(path, '..', '..', '..')) + + gir_path = os.path.join(common_path, 'share', 'gir-1.0') + + typelib_name = os.path.basename(path) + gir_name = os.path.splitext(typelib_name)[0] + '.gir' + + gir_file = os.path.join(gir_path, gir_name) + + if not os.path.exists(gir_path): + logger.error( + "Unable to find gir directory: %s.\nTry installing your platform's gobject-introspection package.", + gir_path + ) + return None + if not os.path.exists(gir_file): + logger.error( + "Unable to find gir file: %s.\nTry installing your platform's gobject-introspection package.", gir_file + ) + return None + + with open(gir_file, 'r', encoding='utf-8') as f: + lines = f.readlines() + # GIR files are `XML encoded `_, + # which means they are by definition encoded using UTF-8. + with open(os.path.join(CONF['workpath'], gir_name), 'w', encoding='utf-8') as f: + for line in lines: + if 'shared-library' in line: + split = re.split('(=)', line) + files = re.split('(["|,])', split[2]) + for count, item in enumerate(files): + if 'lib' in item: + files[count] = '@loader_path/' + os.path.basename(item) + line = ''.join(split[0:2]) + ''.join(files) + f.write(line) + + # g-ir-compiler expects a file so we cannot just pipe the fixed file to it. + command = subprocess.Popen(( + 'g-ir-compiler', os.path.join(CONF['workpath'], gir_name), + '-o', os.path.join(CONF['workpath'], typelib_name) + )) # yapf: disable + command.wait() + + return os.path.join(CONF['workpath'], typelib_name), 'gi_typelibs' + else: + return path, 'gi_typelibs' + + +@isolated.decorate +def get_glib_system_data_dirs(): + import gi + gi.require_version('GLib', '2.0') + from gi.repository import GLib + return GLib.get_system_data_dirs() + + +def get_glib_sysconf_dirs(): + """ + Try to return the sysconf directories (e.g., /etc). + """ + if compat.is_win: + # On Windows, if you look at gtkwin32.c, sysconfdir is actually relative to the location of the GTK DLL. Since + # that is what we are actually interested in (not the user path), we have to do that the hard way... + return [os.path.join(get_gi_libdir('GLib', '2.0'), 'etc')] + + @isolated.call + def data_dirs(): + import gi + gi.require_version('GLib', '2.0') + from gi.repository import GLib + return GLib.get_system_config_dirs() + + return data_dirs + + +def collect_glib_share_files(*path): + """ + Path is relative to the system data directory (e.g., /usr/share). + """ + glib_data_dirs = get_glib_system_data_dirs() + if glib_data_dirs is None: + return [] + + destdir = os.path.join('share', *path) + + # TODO: will this return too much? + collected = [] + for data_dir in glib_data_dirs: + p = os.path.join(data_dir, *path) + collected += collect_system_data_files(p, destdir=destdir, include_py_files=False) + + return collected + + +def collect_glib_etc_files(*path): + """ + Path is relative to the system config directory (e.g., /etc). + """ + glib_config_dirs = get_glib_sysconf_dirs() + if glib_config_dirs is None: + return [] + + destdir = os.path.join('etc', *path) + + # TODO: will this return too much? + collected = [] + for config_dir in glib_config_dirs: + p = os.path.join(config_dir, *path) + collected += collect_system_data_files(p, destdir=destdir, include_py_files=False) + + return collected + + +_glib_translations = None + + +def collect_glib_translations(prog, lang_list=None): + """ + Return a list of translations in the system locale directory whose names equal prog.mo. + """ + global _glib_translations + if _glib_translations is None: + if lang_list is not None: + trans = [] + for lang in lang_list: + trans += collect_glib_share_files(os.path.join("locale", lang)) + _glib_translations = trans + else: + _glib_translations = collect_glib_share_files('locale') + + names = [os.sep + prog + '.mo', os.sep + prog + '.po'] + namelen = len(names[0]) + + return [(src, dst) for src, dst in _glib_translations if src[-namelen:] in names] + + +# Not a hook utility function per-se (used by main Analysis class), but kept here to have all GLib/GObject functions +# in one place... +def compile_glib_schema_files(datas_toc, workdir, collect_source_files=False): + """ + Compile collected GLib schema files. Extracts the list of GLib schema files from the given input datas TOC, copies + them to temporary working directory, and compiles them. The resulting `gschemas.compiled` file is added to the + output TOC, replacing any existing entry with that name. If `collect_source_files` flag is set, the source XML + schema files are also (re)added to the output TOC; by default, they are not. This function is no-op (returns the + original TOC) if no GLib schemas are found in TOC or if `glib-compile-schemas` executable is not found in `PATH`. + """ + SCHEMA_DEST_DIR = pathlib.PurePath("share/glib-2.0/schemas") + workdir = pathlib.Path(workdir) + + schema_files = [] + output_toc = [] + for toc_entry in datas_toc: + dest_name, src_name, typecode = toc_entry + dest_name = pathlib.PurePath(dest_name) + src_name = pathlib.PurePath(src_name) + + # Pass-through for non-schema files, identified based on the destination directory. + if dest_name.parent != SCHEMA_DEST_DIR: + output_toc.append(toc_entry) + continue + + # It seems schemas directory contains different files with different suffices: + # - .gschema.xml + # - .schema.override + # - .enums.xml + # To avoid omitting anything, simply collect everything into temporary directory. + # Exemptions are gschema.dtd (which should be unnecessary) and gschemas.compiled (which we will generate + # ourselves in this function). + if src_name.name in {"gschema.dtd", "gschemas.compiled"}: + continue + + schema_files.append(src_name) + + # If there are no schema files available, simply return the input datas TOC. + if not schema_files: + return datas_toc + + # Ensure that `glib-compile-schemas` executable is in PATH, just in case... + schema_compiler_exe = shutil.which('glib-compile-schemas') + if not schema_compiler_exe: + logger.warning("GLib schema compiler (glib-compile-schemas) not found! Skipping GLib schema recompilation...") + return datas_toc + + # If `gschemas.compiled` file already exists in the temporary working directory, record its modification time and + # hash. This will allow us to restore the modification time on the newly-compiled copy, if the latter turns out + # to be identical to the existing old one. Just in case, if the file becomes subject to timestamp-based caching + # mechanism. + compiled_file = workdir / "gschemas.compiled" + old_compiled_file_hash = None + old_compiled_file_stat = None + + if compiled_file.is_file(): + # Record creation/modification time + old_compiled_file_stat = compiled_file.stat() + # Compute SHA1 hash; since compiled schema files are relatively small, do it in single step. + old_compiled_file_hash = hashlib.sha1(compiled_file.read_bytes()).digest() + + # Ensure that temporary working directory exists, and is empty. + if workdir.exists(): + shutil.rmtree(workdir) + workdir.mkdir(exist_ok=True) + + # Copy schema (source) files to temporary working directory + for schema_file in schema_files: + shutil.copy(schema_file, workdir) + + # Compile. The glib-compile-schema might produce warnings on its own (e.g., schemas using deprecated paths, or + # overrides for non-existent keys). Since these are non-actionable, capture and display them only as a DEBUG + # message, or as a WARNING one if the command fails. + logger.info("Compiling collected GLib schema files in %r...", str(workdir)) + try: + cmd_args = [schema_compiler_exe, str(workdir), '--targetdir', str(workdir)] + p = subprocess.run( + cmd_args, + stdin=subprocess.DEVNULL, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + check=True, + text=True, + errors='ignore', + ) + logger.debug("Output from glib-compile-schemas:\n%s", p.stdout) + except subprocess.CalledProcessError as e: + # The called glib-compile-schema returned error. Display stdout/stderr, and return original datas TOC to + # minimize damage. + logger.warning("Failed to recompile GLib schemas! Returning collected files as-is!", exc_info=True) + logger.warning("Output from glib-compile-schemas:\n%s", e.stdout) + return datas_toc + except Exception: + # Compilation failed for whatever reason. Return original datas TOC to minimize damage. + logger.warning("Failed to recompile GLib schemas! Returning collected files as-is!", exc_info=True) + return datas_toc + + # Compute the checksum of the new compiled file, and if it matches the old checksum, restore the modification time. + if old_compiled_file_hash is not None: + new_compiled_file_hash = hashlib.sha1(compiled_file.read_bytes()).digest() + if new_compiled_file_hash == old_compiled_file_hash: + os.utime(compiled_file, ns=(old_compiled_file_stat.st_atime_ns, old_compiled_file_stat.st_mtime_ns)) + + # Add the resulting gschemas.compiled file to the output TOC + output_toc.append((str(SCHEMA_DEST_DIR / compiled_file.name), str(compiled_file), "DATA")) + + # Include source schema files in the output TOC (optional) + if collect_source_files: + for schema_file in schema_files: + output_toc.append((str(SCHEMA_DEST_DIR / schema_file.name), str(schema_file), "DATA")) + + return output_toc diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/qt/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/qt/__init__.py new file mode 100755 index 000000000..12be1725a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/qt/__init__.py @@ -0,0 +1,858 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +import glob +import os +import pathlib + +from PyInstaller import compat +from PyInstaller import isolated +from PyInstaller import log as logging +from PyInstaller.depend import bindepend +from PyInstaller.utils import hooks, misc +from PyInstaller.utils.hooks.qt import _modules_info + +logger = logging.getLogger(__name__) + +# Qt deployment approach +# ---------------------- +# This is the core of PyInstaller's approach to Qt deployment. It is based on: +# +# - Discovering the location of Qt libraries by introspection, using QtLibraryInfo_. This provides compatibility with +# many variants of Qt5/6 (conda, self-compiled, provided by a Linux distro, etc.) and many versions of Qt5/6, all of +# which vary in the location of Qt files. +# +# - Placing all frozen PyQt5/6 or PySide2/6 Qt files in a standard subdirectory layout, which matches the layout of the +# corresponding wheel on PyPI. This is necessary to support Qt installs which are not in a subdirectory of the PyQt5/6 +# or PySide2/6 wrappers. See ``hooks/rthooks/pyi_rth_qt5.py`` for the use of environment variables to establish this +# layout. +# +# - Emitting warnings on missing QML and translation files which some installations do not have. +# +# - Determining additional files needed for deployment based on the information in the centralized Qt module information +# list in the ``_modules_info`` module. This includes plugins and translation files associated with each Qt python +# extension module, as well as additional python Qt extension modules. +# +# - Collecting additional files that are specific to each module and are handled separately, for example: +# +# - For dynamic OpenGL applications, the ``libEGL.dll``, ``libGLESv2.dll``, ``d3dcompiler_XX.dll`` (the XX is a +# version number), and ``opengl32sw.dll`` libraries need to be collected on Windows. This is handled by the +# "base" bindings hook, for example ``hook-PyQt5.py``. +# +# - If Qt was configured to use ICU, the ``icudtXX.dll``, ``icuinXX.dll``, and ``icuucXX.dll`` libraries need to +# be collected on Windows. This is handled by the "base" bindings hook, for example ``hook-PyQt5.py``. +# +# - Per the `Deploying QML Applications `_ page, QML-based +# applications need the ``qml/`` directory available. This is handled by ``QtQuick`` hook, for example +# ``hook-PyQt5.QtQuick.py``. +# +# - For ``QtWebEngine``-based applications, we follow the `deployWebEngineCore +# `_ +# function copies the following files from ``resources/``, and also copies the web engine process executable. +# - ``icudtl.dat`` +# - ``qtwebengine_devtools_resources.pak`` +# - ``qtwebengine_resources.pak`` +# - ``qtwebengine_resources_100p.pak`` +# - ``qtwebengine_resources_200p.pak`` +# +# This is handled by the ``QtWebEngineCore`` hook, for example ``hook-PyQt5.QtWebEngineCore.py``. +# +# For details and references, see the `original write-up +# `_ +# and the documentation in the ``_modules_info`` module. + + +# QtModuleInfo +# ------------ +# This class contains information about python module (extension), its corresponding Qt module (shared library), and +# associated plugins and translations. It is used within QtLibraryInfo_ to establish name-based mappings for file +# collection. +class QtModuleInfo: + def __init__(self, module, shared_lib=None, translations=None, plugins=None): + # Python module (extension) name without package namespace. For example, `QtCore`. + # Can be None if python bindings do not bind the module, but we still need to establish relationship between + # the Qt module (shared library) and its plugins and translations. + self.module = module + # Associated Qt module (shared library), if any. Used during recursive dependency analysis, where a python + # module (extension) is analyzed for linked Qt modules (shared libraries), and then their corresponding + # python modules (extensions) are added to hidden imports. For example, the Qt module name is `Qt5Core` or + # `Qt6Core`, depending on the Qt version. Can be None for python modules that are not tied to a particular + # Qt shared library (for example, the corresponding Qt module is headers-only) and hence they cannot be + # inferred from recursive link-time dependency analysis. + self.shared_lib = shared_lib + # List of base names of translation files (if any) associated with the Qt module. Multiple base names may be + # associated with a single module. + # For example, `['qt', 'qtbase']` for `QtCore` or `['qtmultimedia']` for `QtMultimedia`. + self.translations = translations or [] + # List of plugins associated with the Qt module. + self.plugins = plugins or [] + + def __repr__(self): + return f"(module={self.module!r}, shared_lib={self.shared_lib!r}, " \ + f"translations={self.translations!r}, plugins={self.plugins!r}" + + +# QtLibraryInfo +# -------------- +# This class uses introspection to determine the location of Qt files. This is essential to deal with the many variants +# of the PyQt5/6 and PySide2/6 package, each of which places files in a different location. Therefore, this class +# provides all location-related members of `QLibraryInfo `_. +class QtLibraryInfo: + def __init__(self, namespace): + if namespace not in ['PyQt5', 'PyQt6', 'PySide2', 'PySide6']: + raise Exception('Invalid namespace: {0}'.format(namespace)) + self.namespace = namespace + # Distinction between PyQt5/6 and PySide2/6 + self.is_pyqt = namespace in {'PyQt5', 'PyQt6'} + # Distinction between Qt5 and Qt6 + self.qt_major = 6 if namespace in {'PyQt6', 'PySide6'} else 5 + # Determine relative path where Qt libraries and data need to be collected in the frozen application. This + # varies between PyQt5/PyQt6/PySide2/PySide6, their versions, and platforms. NOTE: it is tempting to consider + # deriving this path as simply the value of QLibraryInfo.PrefixPath, taken relative to the package's root + # directory. However, we also need to support non-wheel deployments (e.g., with Qt installed in custom path on + # Windows, or with Qt and PyQt5 installed on linux using native package manager), and in those, the Qt + # PrefixPath does not reflect the required relative target path for the frozen application. + if namespace == 'PyQt5': + if self._use_new_layout("PyQt5", "5.15.4", False): + self.qt_rel_dir = os.path.join('PyQt5', 'Qt5') + else: + self.qt_rel_dir = os.path.join('PyQt5', 'Qt') + elif namespace == 'PyQt6': + if self._use_new_layout("PyQt6", "6.0.3", True): + self.qt_rel_dir = os.path.join('PyQt6', 'Qt6') + else: + self.qt_rel_dir = os.path.join('PyQt6', 'Qt') + elif namespace == 'PySide2': + # PySide2 uses PySide2/Qt on linux and macOS, and PySide2 on Windows + if compat.is_win: + self.qt_rel_dir = 'PySide2' + else: + self.qt_rel_dir = os.path.join('PySide2', 'Qt') + else: + # PySide6 follows the same logic as PySide2 + if compat.is_win: + self.qt_rel_dir = 'PySide6' + else: + self.qt_rel_dir = os.path.join('PySide6', 'Qt') + + # Process module information list to construct python-module-name -> info and shared-lib-name -> info mappings. + self._load_module_info() + + def __repr__(self): + return f"QtLibraryInfo({self.namespace})" + + # Delay initialization of the Qt library information until the corresponding attributes are first requested. + def __getattr__(self, name): + if 'version' in self.__dict__: + # Initialization was already done, but requested attribute is not available. + raise AttributeError(name) + + # Load Qt library info... + self._load_qt_info() + # ... and return the requested attribute + return getattr(self, name) + + # Check whether we must use the new layout (e.g. PyQt5/Qt5, PyQt6/Qt6) instead of the old layout (PyQt5/Qt, + # PyQt6/Qt). + @staticmethod + def _use_new_layout(package_basename: str, version: str, fallback_value: bool) -> bool: + # The call to is_module_satisfies might fail with AttributeError in case of a partial installation, or when dist + # information is missing, in which case a fallback codepath tries to check for a __version__ attribute that does + # not exist. + # + # This may happen for the following (not exhaustive) reasons: + # + # - PyQt 5.9.2 installed from conda's main channel. + # - User installs PyQt6 via pip, which also installs PyQt6-Qt6 and PyQt6-sip. Then they naively uninstall PyQt6 + # package, which leaves the other two behind. PyQt6 now becomes a namespace package and there is no dist + # metadata. + # - The PyQt5 commercial wheel is installed. It creates the PyQt5 namespace package but dist information is + # available under PyQt5_commercial. Since we first check for the non-commercial wheel, we trip the fallback + # codepath inside is_module_satisfies. + try: + return hooks.is_module_satisfies(f"{package_basename} >= {version}") + except AttributeError: + try: + return hooks.is_module_satisfies(f"{package_basename}_commercial >= {version}") + except AttributeError: + return fallback_value + + # Load Qt information (called on first access to related fields) + def _load_qt_info(self): + """ + Load and process Qt library information. Called on the first access to the related attributes of the class + (e.g., `version` or `location`). + """ + + # Ensure self.version exists, even if PyQt{5,6}/PySide{2,6} cannot be imported. Hooks and util functions use + # `if .version` to check whether package was imported and other attributes are expected to be available. + # This also serves as a marker that initialization was already done. + self.version = None + + # Get library path information from Qt. See QLibraryInfo_. + @isolated.decorate + def _read_qt_library_info(package): + import os + import sys + import importlib + + # Import the Qt-based package + # equivalent to: from package.QtCore import QLibraryInfo, QCoreApplication + QtCore = importlib.import_module('.QtCore', package) + QLibraryInfo = QtCore.QLibraryInfo + QCoreApplication = QtCore.QCoreApplication + + # QLibraryInfo is not always valid until a QCoreApplication is instantiated. + app = QCoreApplication(sys.argv) # noqa: F841 + + # Qt6 deprecated QLibraryInfo.location() in favor of QLibraryInfo.path(), and + # QLibraryInfo.LibraryLocation enum was replaced by QLibraryInfo.LibraryPath. + if hasattr(QLibraryInfo, 'path'): + # Qt6; enumerate path enum values directly from the QLibraryInfo.LibraryPath enum. + path_names = [x for x in dir(QLibraryInfo.LibraryPath) if x.endswith('Path')] + location = {x: QLibraryInfo.path(getattr(QLibraryInfo.LibraryPath, x)) for x in path_names} + else: + # Qt5; in recent versions, location enum values can be enumeratd from QLibraryInfo.LibraryLocation. + # However, in older versions of Qt5 and its python bindings, that is unavailable. Hence the + # enumeration of "*Path"-named members of QLibraryInfo. + path_names = [x for x in dir(QLibraryInfo) if x.endswith('Path')] + location = {x: QLibraryInfo.location(getattr(QLibraryInfo, x)) for x in path_names} + + # Determine the python-based package location, by looking where the QtCore module is located. + package_location = os.path.dirname(QtCore.__file__) + + # Determine Qt version. Works for Qt 5.8 and later, where QLibraryInfo.version() was introduced. + try: + version = QLibraryInfo.version().segments() + except AttributeError: + version = [] + + return { + 'is_debug_build': QLibraryInfo.isDebugBuild(), + 'version': version, + 'location': location, + 'package_location': package_location, + } + + try: + qt_info = _read_qt_library_info(self.namespace) + except Exception as e: + logger.warning("%s: failed to obtain Qt library info: %s", self, e) + qt_info = {} + + for k, v in qt_info.items(): + setattr(self, k, v) + + # Module information list loading/processing + def _load_module_info(self): + """ + Process the Qt modules info definition list and construct two dictionaries: + - dictionary that maps Qt python module names to Qt module info entries + - dictionary that maps shared library names to Qt module info entries + """ + + self.python_modules = dict() + self.shared_libraries = dict() + + for entry in _modules_info.QT_MODULES_INFO: + # If entry specifies applicable bindings, check them + if entry.bindings: + applicable_bindings = _modules_info.process_namespace_strings(entry.bindings) + if self.namespace not in applicable_bindings: + continue + + # Create a QtModuleInfo entry + info_entry = QtModuleInfo( + module=entry.module, + shared_lib=f"Qt{self.qt_major}{entry.shared_lib}" if entry.shared_lib else None, + translations=entry.translations, + plugins=entry.plugins + ) + + # If we have python module (extension) name, create python-module-name -> info mapping. + if info_entry.module is not None: + self.python_modules[info_entry.module] = info_entry + + # If we have Qt module (shared library) name, create shared-lib-name -> info mapping. + if info_entry.shared_lib is not None: + self.shared_libraries[info_entry.shared_lib.lower()] = info_entry + + # Collection + def collect_module(self, module_name): + """ + Collect all dependencies (hiddenimports, binaries, datas) for the given Qt python module. + + This function performs recursive analysis of extension module's link-time dependencies, and uses dictionaries + built by `_load_module_info` to discover associated plugin types, translation file base names, and hidden + imports that need to be collected. + """ + + # Accumulate all dependencies in a set to avoid duplicates. + hiddenimports = set() + translation_base_names = set() + plugin_types = set() + + # Exit if the requested library cannot be imported. + # NOTE: self..version can be empty list on older Qt5 versions (#5381). + if self.version is None: + return [], [], [] + + logger.debug('%s: processing module %s...', self, module_name) + + # Look up the associated Qt module information by python module name. + # This allows us to collect associated module data directly, even if there is no associated shared library + # (e.g., header-only Qt module, or statically-built one). + short_module_name = module_name.split('.', 1)[-1] # PySide2.QtModule -> QtModule + if short_module_name in self.python_modules: + qt_module_info = self.python_modules[short_module_name] + + # NOTE: no need to add a hiddenimport here, because this is the module under consideration. + + # Add plugins + plugin_types.update(qt_module_info.plugins) + + # Add translation base name(s) + translation_base_names.update(qt_module_info.translations) + + # Find the actual module extension file. + module_file = hooks.get_module_file_attribute(module_name) + + # Walk through all the link-time dependencies of a dynamically-linked library (``.so``/``.dll``/``.dylib``). + imported_libraries = set(bindepend.getImports(module_file)) + while imported_libraries: + imported_library = imported_libraries.pop() + + # On Windows, resolve the shared library's full path; other platforms already provide the full path. + if compat.is_win: + # First, look for Qt binaries in the local Qt install. For PyQt5 and PyQt6, DLLs should be in + # BinariesPath, while for PySide2 and PySide6, they should be in PrefixPath. + dll_location = self.location['BinariesPath' if self.is_pyqt else 'PrefixPath'] + imported_library = bindepend.getfullnameof(imported_library, dll_location) + + # Strip off the extension and ``lib`` prefix (Linux/Mac) to give the raw name. + # Lowercase (since Windows always normalizes names to lowercase). + lib_name = os.path.splitext(os.path.basename(imported_library))[0].lower() + # Linux libraries sometimes have a dotted version number -- ``libfoo.so.3``. It is now ''libfoo.so``, + # but the ``.so`` must also be removed. + if compat.is_linux and os.path.splitext(lib_name)[1] == '.so': + lib_name = os.path.splitext(lib_name)[0] + if lib_name.startswith('lib'): + lib_name = lib_name[3:] + # Mac OS: handle different naming schemes. PyPI wheels ship framework-enabled Qt builds, where shared + # libraries are part of .framework bundles (e.g., ``PyQt5/Qt5/lib/QtCore.framework/Versions/5/QtCore``). + # In Anaconda (Py)Qt installations, the shared libraries are installed in environment's library directory, + # and contain versioned extensions, e.g., ``libQt5Core.5.dylib``. + if compat.is_darwin: + if lib_name.startswith('qt') and not lib_name.startswith('qt' + str(self.qt_major)): + # Qt library from a framework bundle (e.g., ``QtCore``); change prefix from ``qt`` to ``qt5`` or + # ``qt6`` to match names in Windows/Linux. + lib_name = 'qt' + str(self.qt_major) + lib_name[2:] + if lib_name.endswith('.' + str(self.qt_major)): + # Qt library from Anaconda, which originally had versioned extension, e.g., ``libfoo.5.dynlib``. + # The above processing turned it into ``foo.5``, so we need to remove the last two characters. + lib_name = lib_name[:-2] + + # Match libs with QT_LIBINFIX set to '_conda', i.e. conda-forge builds. + if lib_name.endswith('_conda'): + lib_name = lib_name[:-6] + + logger.debug('%s: raw imported library name %s -> parsed name %s.', self, imported_library, lib_name) + + # PySide2 and PySide6 on linux seem to link all extension modules against libQt5Core, libQt5Network, and + # libQt5Qml (or their libQt6* equivalents). While the first two are reasonable, the libQt5Qml dependency + # pulls in whole QtQml module, along with its data and plugins, which in turn pull in several other Qt + # libraries, greatly inflating the bundle size (see #6447). + # + # Similarly, some extension modules (QtWebChannel, QtWebEngine*) seem to be also linked against libQt5Qml, + # even when the module can be used without having the whole QtQml module collected. + # + # Therefore, we explicitly prevent inclusion of QtQml based on the dynamic library dependency, except for + # QtQml* and QtQuick* modules, whose use directly implies the use of QtQml. + if lib_name in ("qt5qml", "qt6qml"): + if not short_module_name.startswith(('QtQml', 'QtQuick')): + logger.debug('%s: ignoring imported library %s.', self, imported_library) + continue + + # Use the parsed library name to look up associated Qt module information. + if lib_name in self.shared_libraries: + logger.debug( + '%s: collecting Qt module associated with imported shared library %s (%s).', self, imported_library, + lib_name + ) + + # Look up associated module info + qt_module_info = self.shared_libraries[lib_name] + + # If there is a python extension module associated with Qt module, add it to hiddenimports. Since this + # means that we (most likely) have a hook available for that module, we can avoid analyzing the shared + # library itself (i.e., stop the recursive analysis), because this will be done by the corresponding + # hook. + if qt_module_info.module: + if qt_module_info.module == short_module_name: + # The one exception is if we are analyzing shared library associated with the input module; in + # that case, avoid adding a hidden import and analyze the library's link-time dependencies. We + # do not need to worry about plugins and translations for this particular module, because those + # have been handled at the beginning of this function. + imported_libraries.update(bindepend.getImports(imported_library)) + else: + hiddenimports.add(self.namespace + "." + qt_module_info.module) + continue + + # Add plugins + plugin_types.update(qt_module_info.plugins) + + # Add translation base name(s) + translation_base_names.update(qt_module_info.translations) + + # Analyze the linked shared libraries for its dependencies (recursive analysis). + imported_libraries.update(bindepend.getImports(imported_library)) + + # Collect plugin files. + binaries = [] + for plugin_type in plugin_types: + binaries += self.collect_plugins(plugin_type) + + # Collect translation files. + datas = [] + translation_src = self.location['TranslationsPath'] + translation_dst = os.path.join(self.qt_rel_dir, 'translations') + + for translation_base_name in translation_base_names: + # Not all PyQt5 installations include translations. See + # https://github.com/pyinstaller/pyinstaller/pull/3229#issuecomment-359479893 + # and + # https://github.com/pyinstaller/pyinstaller/issues/2857#issuecomment-368744341. + translation_pattern = os.path.join(translation_src, translation_base_name + '_*.qm') + translation_files = glob.glob(translation_pattern) + if translation_files: + datas += [(translation_file, translation_dst) for translation_file in translation_files] + else: + logger.warning( + '%s: could not find translations with base name %r! These translations will not be collected.', + self, translation_base_name + ) + + # Convert hiddenimports to a list. + hiddenimports = list(hiddenimports) + + logger.debug( + '%s: dependencies for %s:\n' + ' hiddenimports = %r\n' + ' binaries = %r\n' + ' datas = %r', self, module_name, hiddenimports, binaries, datas + ) + + return hiddenimports, binaries, datas + + @staticmethod + def _filter_release_plugins(plugin_files): + """ + Filter the provided list of Qt plugin files and remove the debug variants, under the assumption that both the + release version of a plugin (qtplugin.dll) and its debug variant (qtplugind.dll) appear in the list. + """ + # All basenames for lookup + plugin_basenames = {os.path.normcase(os.path.basename(f)) for f in plugin_files} + # Process all given filenames + release_plugin_files = [] + for plugin_filename in plugin_files: + plugin_basename = os.path.normcase(os.path.basename(plugin_filename)) + if plugin_basename.endswith('d.dll'): + # If we can find a variant without trailing 'd' in the plugin list, then the DLL we are dealing with is + # a debug variant and needs to be excluded. + release_name = os.path.splitext(plugin_basename)[0][:-1] + '.dll' + if release_name in plugin_basenames: + continue + release_plugin_files.append(plugin_filename) + return release_plugin_files + + def collect_plugins(self, plugin_type): + """ + Collect all plugins of the specified type from the Qt plugin directory. + + Returns list of (src, dst) tuples. + """ + # Ensure plugin directory exists + plugin_src_dir = self.location['PluginsPath'] + if not os.path.isdir(plugin_src_dir): + raise Exception(f"Qt plugin directory '{plugin_src_dir}' does not exist!") + + # Collect all shared lib files in plugin type (sub)directory + plugin_files = misc.dlls_in_dir(os.path.join(plugin_src_dir, plugin_type)) + + # Windows: + # + # dlls_in_dir() grabs all files ending with ``*.dll``, ``*.so`` and ``*.dylib`` in a certain directory. On + # Windows this would grab debug copies of Qt plugins, which then causes PyInstaller to add a dependency on the + # Debug CRT *in addition* to the release CRT. + if compat.is_win: + plugin_files = self._filter_release_plugins(plugin_files) + + logger.debug("%s: found plugin files for plugin type %r: %r", self, plugin_type, plugin_files) + + plugin_dst_dir = os.path.join(self.qt_rel_dir, 'plugins', plugin_type) + return [(plugin_file, plugin_dst_dir) for plugin_file in plugin_files] + + def _collect_all_or_none(self, mandatory_dll_patterns, optional_dll_patterns=None): + """ + Try to find Qt DLLs from the specified mandatory pattern list. If all mandatory patterns resolve to DLLs, + collect them all, as well as any DLLs from the optional pattern list. If a mandatory pattern fails to resolve + to a DLL, return an empty list. + + This allows all-or-none collection of particular groups of Qt DLLs that may or may not be available. + """ + optional_dll_patterns = optional_dll_patterns or [] + + # Resolve path to the the corresponding python package (actually, its parent directory). Used to preserve the + # directory structure when DLLs are collected from the python package (e.g., PyPI wheels). + package_parent_path = pathlib.Path(self.package_location).resolve().parent + + # In PyQt5 and PyQt6, the DLLs we are looking for are located in location['BinariesPath'], whereas in PySide2 + # and PySide6, they are located in location['PrefixPath']. + dll_path = self.location['BinariesPath' if self.is_pyqt else 'PrefixPath'] + dll_path = pathlib.Path(dll_path).resolve() + + # Helper for processing single DLL pattern + def _process_dll_pattern(dll_pattern): + discovered_dlls = [] + + dll_files = dll_path.glob(dll_pattern) + for dll_file in dll_files: + if package_parent_path in dll_file.parents: + # The DLL is located within python package; preserve the layout + dst_dll_dir = dll_file.parent.relative_to(package_parent_path) + else: + # The DLL is not located within python package; collect into top-level directory + dst_dll_dir = '.' + discovered_dlls.append((str(dll_file), str(dst_dll_dir))) + + return discovered_dlls + + # Process mandatory patterns + collected_dlls = [] + for pattern in mandatory_dll_patterns: + discovered_dlls = _process_dll_pattern(pattern) + if not discovered_dlls: + return [] # Mandatory pattern resulted in no DLLs; abort + collected_dlls += discovered_dlls + + # Process optional patterns + for pattern in optional_dll_patterns: + collected_dlls += _process_dll_pattern(pattern) + + return collected_dlls + + # Collect required Qt binaries, but only if all binaries in a group exist. + def collect_extra_binaries(self): + """ + Collect extra binaries/DLLs required by Qt. These include ANGLE DLLs, OpenGL software renderer DLL, and ICU + DLLs. Applicable only on Windows (on other OSes, empty list is returned). + """ + + binaries = [] + + # Applicable only to Windows. + if not compat.is_win: + return [] + + # OpenGL: EGL/GLES via ANGLE, software OpenGL renderer. + binaries += self._collect_all_or_none(['libEGL.dll', 'libGLESv2.dll'], ['d3dcompiler_??.dll']) + binaries += self._collect_all_or_none(['opengl32sw.dll']) + + # Include ICU files, if they exist. + # See the "Deployment approach" section in ``PyInstaller/utils/hooks/qt.py``. + binaries += self._collect_all_or_none(['icudt??.dll', 'icuin??.dll', 'icuuc??.dll']) + + return binaries + + # Collect additional shared libraries required for SSL support in QtNetwork, if they are available. + # Applicable only to Windows. See issue #3520, #4048. + def collect_qtnetwork_files(self): + """ + Collect extra binaries/DLLs required by the QtNetwork module. These include OpenSSL DLLs. Applicable only + on Windows (on other OSes, empty list is returned). + """ + + # No-op if requested Qt-based package is not available. + if self.version is None: + return [] + + # Applicable only to Windows. + if not compat.is_win: + return [] + + # Check if QtNetwork supports SSL + @isolated.decorate + def _ssl_enabled(package): + import sys + import importlib + + # Import the Qt-based package + # equivalent to: from package.QtCore import QCoreApplication + QtCore = importlib.import_module('.QtCore', package) + QCoreApplication = QtCore.QCoreApplication + # equivalent to: from package.QtNetwork import QSslSocket + QtNetwork = importlib.import_module('.QtNetwork', package) + QSslSocket = QtNetwork.QSslSocket + + # Instantiate QCoreApplication to suppress warnings + app = QCoreApplication(sys.argv) # noqa: F841 + + return QSslSocket.supportsSsl() + + if not _ssl_enabled(self.namespace): + return [] + + # Resolve path to the the corresponding python package (actually, its parent directory). Used to preserve the + # directory structure when DLLs are collected from the python package (e.g., PyPI wheels). + package_parent_path = pathlib.Path(self.package_location).resolve().parent + + # PyPI version of PySide2 requires user to manually install SSL libraries into the PrefixPath. Other versions + # (e.g., the one provided by Conda) put the libraries into the BinariesPath. PyQt5 also uses BinariesPath. + # Accommodate both options by searching both locations... + locations = (self.location['BinariesPath'], self.location['PrefixPath']) + dll_names = ('libeay32.dll', 'ssleay32.dll', 'libssl-1_1-x64.dll', 'libcrypto-1_1-x64.dll') + binaries = [] + for location in locations: + location = pathlib.Path(location).resolve() + for dll in dll_names: + dll_file_path = location / dll + if not dll_file_path.exists(): + continue + if package_parent_path in dll_file_path.parents: + # The DLL is located within python package; preserve the layout + dst_dll_path = dll_file_path.parent.relative_to(package_parent_path) + else: + # The DLL is not located within python package; collect into top-level directory + dst_dll_path = '.' + binaries.append((str(dll_file_path), str(dst_dll_path))) + return binaries + + def collect_qtqml_files(self): + """ + Collect additional binaries and data for QtQml module. + """ + + # No-op if requested Qt-based package is not available. + if self.version is None: + return [], [] + + # Not all PyQt5/PySide2 installs have QML files. In this case, location['Qml2ImportsPath'] is empty. + # Furthermore, even if location path is provided, the directory itself may not exist. + # + # https://github.com/pyinstaller/pyinstaller/pull/3229#issuecomment-359735031 + # https://github.com/pyinstaller/pyinstaller/issues/3864 + # + # In Qt 6, Qml2ImportsPath was deprecated in favor of QmlImportsPath. The former is not available in PySide6 + # 6.4.0 anymore (but is in PyQt6 6.4.0). Use the new QmlImportsPath if available. + if 'QmlImportsPath' in self.location: + qml_src_dir = self.location['QmlImportsPath'] + else: + qml_src_dir = self.location['Qml2ImportsPath'] + if not qml_src_dir or not os.path.isdir(qml_src_dir): + logger.warning('%s: QML directory %r does not exist. QML files not packaged.', self, qml_src_dir) + return [], [] + + qml_dst_dir = os.path.join(self.qt_rel_dir, 'qml') + datas = [(qml_src_dir, qml_dst_dir)] + binaries = [ + # Produce ``/path/to/Qt/Qml/path_to_qml_binary/qml_binary, PyQt5/Qt/Qml/path_to_qml_binary``. + ( + qml_plugin_file, + os.path.join(qml_dst_dir, os.path.dirname(os.path.relpath(qml_plugin_file, qml_src_dir))) + ) for qml_plugin_file in misc.dlls_in_subdirs(qml_src_dir) + ] + + return binaries, datas + + def collect_qtwebengine_files(self): + """ + Collect QtWebEngine helper process executable, translations, and resources. + """ + + binaries = [] + datas = [] + + # Output directory (varies between PyQt and PySide and among OSes; the difference is abstracted by + # QtLibraryInfo.qt_rel_dir) + rel_data_path = self.qt_rel_dir + + is_macos_framework = False + if compat.is_darwin: + # Determine if we are dealing with a framework-based Qt build (e.g., PyPI wheels) or a dylib-based one + # (e.g., Anaconda). The former requires special handling, while the latter is handled in the same way as + # Windows and Linux builds. + is_macos_framework = os.path.exists( + os.path.join(self.location['LibrariesPath'], 'QtWebEngineCore.framework') + ) + + if is_macos_framework: + # On macOS, Qt shared libraries are provided in form of .framework bundles. However, PyInstaller collects + # shared library from the bundle into top-level application directory, breaking the bundle structure. + # + # QtWebEngine and its underlying Chromium engine, however, have very strict data file layout requirements + # due to sandboxing, and does not work if the helper process executable does not load the shared library + # from QtWebEngineCore.framework (which also needs to contain all resources). + # + # Therefore, we collect the QtWebEngineCore.framework manually, in order to obtain a working + # QtWebEngineProcess helper executable. But because that bypasses our dependency scanner, we need to collect + # the dependent .framework bundles as well. And we need to override QTWEBENGINEPROCESS_PATH in rthook, + # because the QtWebEngine python extensions actually load up the copy of shared library that is located in + # sys._MEIPASS (as opposed to the manually-copied one in .framework bundle). Furthermore, because the + # extension modules use Qt shared libraries in sys._MEIPASS, we also copy all contents of + # QtWebEngineCore.framework/Resources into sys._MEIPASS to make resource loading in the main process work. + # + # Besides being ugly, this approach has three main ramifications: + # 1. we bundle two copies of each Qt shared library involved: the copy used by main process, picked up by + # dependency scanner; and a copy in manually-collected .framework bundle that is used by the helper + # process. + # 2. the trick with copying contents of Resource directory of QtWebEngineCore.framework does not work in + # onefile mode, and consequently QtWebEngine does not work in onefile mode. + # 3. copying contents of QtWebEngineCore.framework/Resource means that its Info.plist ends up in + # sys._MEIPASS, causing the main process in onedir mode to be mis-identified as "QtWebEngineProcess". + # + # In the near future, this quagmire will hopefully be properly sorted out, but in the mean time, we have to + # live with what we have been given. + data_path = self.location['DataPath'] + libraries = [ + 'QtCore', 'QtWebEngineCore', 'QtQuick', 'QtQml', 'QtQmlModels', 'QtNetwork', 'QtGui', 'QtWebChannel', + 'QtPositioning' + ] + if self.qt_major == 6: + libraries.extend(['QtOpenGL', 'QtDBus']) + for i in libraries: + framework_dir = i + '.framework' + framework_src_path = os.path.join(data_path, 'lib', framework_dir) + framework_dst_path = os.path.join(rel_data_path, 'lib', framework_dir) + datas += hooks.collect_system_data_files(framework_src_path, framework_dst_path, True) + datas += [(os.path.join(data_path, 'lib', 'QtWebEngineCore.framework', 'Resources'), '.')] + else: + # Windows and linux (or Anaconda on macOS) + locales = 'qtwebengine_locales' + resources = 'resources' + + # Translations + datas.append(( + os.path.join(self.location['TranslationsPath'], locales), + os.path.join(rel_data_path, 'translations', locales), + )) + + # Resources; ``DataPath`` is the base directory for ``resources``, as per the + # `docs `_. + datas.append((os.path.join(self.location['DataPath'], resources), os.path.join(rel_data_path, resources)),) + + # Helper process executable (QtWebEngineProcess), located in ``LibraryExecutablesPath``. + dest = os.path.join( + rel_data_path, os.path.relpath(self.location['LibraryExecutablesPath'], self.location['PrefixPath']) + ) + binaries.append((os.path.join(self.location['LibraryExecutablesPath'], 'QtWebEngineProcess*'), dest)) + + # The helper QtWebEngineProcess executable should have an accompanying qt.conf file that helps it locate the + # Qt shared libraries. Try collecting it as well + qt_conf_file = os.path.join(self.location['LibraryExecutablesPath'], 'qt.conf') + if not os.path.isfile(qt_conf_file): + # The file seems to have been dropped from Qt 6.3 (and corresponding PySide6 and PyQt6) due to + # redundancy; however, we still need it in the frozen application - so generate our own. + from PyInstaller.config import CONF # workpath + # Relative path to root prefix of bundled Qt + rel_prefix = os.path.relpath(self.location['PrefixPath'], self.location['LibraryExecutablesPath']) + # We expect the relative path to be either . or .. depending on PySide/PyQt layout; if that is not the + # case, warn about irregular path. + if rel_prefix not in ('.', '..'): + logger.warning( + "%s: unexpected relative Qt prefix path for QtWebEngineProcess qt.conf: %s", self, rel_prefix + ) + # The Qt docs on qt.conf (https://doc.qt.io/qt-5/qt-conf.html) recommend using forward slashes on + # Windows as well, due to backslash having to be escaped. This should not matter as we expect the + # relative path to be . or .., but you never know... + if os.sep == '\\': + rel_prefix = rel_prefix.replace(os.sep, '/') + # Create temporary file in workpath + qt_conf_file = os.path.join(CONF['workpath'], "qt.conf") + with open(qt_conf_file, 'w') as fp: + print("[Paths]", file=fp) + print("Prefix = {}".format(rel_prefix), file=fp) + datas.append((qt_conf_file, dest)) + + # Add Linux-specific libraries. + if compat.is_linux: + # The automatic library detection fails for `NSS `_, + # which is used by QtWebEngine. In some distributions, the ``libnss`` supporting libraries are stored in a + # subdirectory ``nss``. Since ``libnss`` is not statically linked to these, but dynamically loads them, we + # need to search for and add them. + + # First, get all libraries linked to ``QtWebEngineCore`` extension module. + module_file = hooks.get_module_file_attribute(self.namespace + '.QtWebEngineCore') + module_imports = bindepend.getImports(module_file) + for imp in module_imports: + # Look for ``libnss3.so``. + if os.path.basename(imp).startswith('libnss3.so'): + # Find the location of NSS: given a ``/path/to/libnss.so``, add ``/path/to/nss/*.so`` to get the + # missing NSS libraries. + nss_glob = os.path.join(os.path.dirname(imp), 'nss', '*.so') + if glob.glob(nss_glob): + binaries.append((nss_glob, 'nss')) + + return binaries, datas + + +# Provide single instances of this class to avoid each hook constructing its own. +pyqt5_library_info = QtLibraryInfo('PyQt5') +pyqt6_library_info = QtLibraryInfo('PyQt6') +pyside2_library_info = QtLibraryInfo('PySide2') +pyside6_library_info = QtLibraryInfo('PySide6') + + +def get_qt_library_info(namespace): + """ + Return QtLibraryInfo instance for the given namespace. + """ + if namespace == 'PyQt5': + return pyqt5_library_info + if namespace == 'PyQt6': + return pyqt6_library_info + elif namespace == 'PySide2': + return pyside2_library_info + elif namespace == 'PySide6': + return pyside6_library_info + + raise ValueError(f'Invalid namespace: {namespace}!') + + +# add_qt_dependencies +# -------------------- +# Generic implemnentation that finds the Qt 5/6 dependencies based on the hook name of a PyQt5/PyQt6/PySide2/PySide6 +# hook. Returns (hiddenimports, binaries, datas). Typical usage: +# ``hiddenimports, binaries, datas = add_qt5_dependencies(__file__)``. +def add_qt_dependencies(hook_file): + # Find the module underlying this Qt hook: change ``/path/to/hook-PyQt5.blah.py`` to ``PyQt5.blah``. + hook_name, hook_ext = os.path.splitext(os.path.basename(hook_file)) + assert hook_ext.startswith('.py') + assert hook_name.startswith('hook-') + module_name = hook_name[5:] + namespace = module_name.split('.')[0] + + # Retrieve Qt library info structure.... + qt_info = get_qt_library_info(namespace) + # ... and use it to collect module dependencies + return qt_info.collect_module(module_name) + + +# add_qt5_dependencies +# -------------------- +# Find the Qt5 dependencies based on the hook name of a PySide2/PyQt5 hook. Returns (hiddenimports, binaries, datas). +# Typical usage: ``hiddenimports, binaries, datas = add_qt5_dependencies(__file__)``. +add_qt5_dependencies = add_qt_dependencies # Use generic implementation + +# add_qt6_dependencies +# -------------------- +# Find the Qt6 dependencies based on the hook name of a PySide6/PyQt6 hook. Returns (hiddenimports, binaries, datas). +# Typical usage: ``hiddenimports, binaries, datas = add_qt6_dependencies(__file__)``. +add_qt6_dependencies = add_qt_dependencies # Use generic implementation diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/qt/_modules_info.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/qt/_modules_info.py new file mode 100755 index 000000000..c0bf5c9c3 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/qt/_modules_info.py @@ -0,0 +1,446 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2022-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# Qt modules information - the core of our Qt collection approach +# ---------------------------------------------------------------- +# +# The python bindings for Qt (``PySide2``, ``PyQt5``, ``PySide6``, ``PyQt6``) consist of several python binary extension +# modules that provide bindings for corresponding Qt modules. For example, the ``PySide2.QtNetwork`` python extension +# module provides bindings for the ``QtNetwork`` Qt module from the ``qt/qtbase`` Qt repository. +# +# A Qt module can be considered as consisting of: +# * a shared library (for example, on Linux, the shared library names for the ``QtNetwork`` Qt module in Qt5 and Qt6 +# are ``libQt5Network.so`` and ``libQt6Network.so``, respectively). +# * plugins: a certain type (or class) of plugins is usually associated with a single Qt module (for example, +# ``imageformats`` plugins are associated with the ``QtGui`` Qt module from the ``qt/qtbase`` Qt repository), but +# additional plugins of that type may come from other Qt repositories. For example, ``imageformats/qsvg`` plugin +# is provided by ``qtsvg/src/plugins/imageformats/svg`` from the ``qt/qtsvg`` repository, and ``imageformats/qpdf`` +# is provided by ``qtwebengine/src/pdf/plugins/imageformats/pdf`` from the ``qt/qtwebengine`` repository. +# * translation files: names of translation files consist of a base name, which typically corresponds to the Qt +# repository name, and language code. A single translation file usually covers all Qt modules contained within +# the same repository. For example, translation files with base name ``qtbase`` contain translations for ``QtCore``, +# ``QtGui``, ``QtWidgets``, ``QtNetwork``, and other Qt modules from the ``qt/qtbase`` Qt repository. +# +# The PyInstaller's built-in analysis of link-time dependencies ensures that when collecting a Qt python extension +# module, we automatically pick up the linked Qt shared libraries. However, collection of linked Qt shared libraries +# does not result in collection of plugins, nor translation files. In addition, the dependency of a Qt python extension +# module on other Qt python extension modules (i.e., at the bindings level) cannot be automatically determined due to +# PyInstaller's inability to scan imports in binary extensions. +# +# PyInstaller < 5.7 solved this problem using a dictionary that associated a Qt shared library name with python +# extension name, plugins, and translation files. For each hooked Qt python extension module, the hook calls a helper +# that analyzes the extension file for link-time dependencies, and matches those against the dictionary. Therefore, +# based on linked shared libraries, we could recursively infer the list of files to collect in addition to the shared +# libraries themselves: +# - plugins and translation files belonging to Qt modules whose shared libraries we collect +# - Qt python extension modules corresponding to the Qt modules that we collect +# +# The above approach ensures that even if analyzed python script contains only ``from PySide2 import QtWidgets``, +# we would also collect ``PySide2.QtGui`` and ``PySide2.QtCore``, as well as all corresponding Qt module files +# (the shared libraries, plugins, translation files). For this to work, a hook must be provided for the +# ``PySide2.QtWidgets`` that performs the recursive analysis of the extension module file; so to ensure that each +# Qt python extension module by itself ensures collection of all its dependencies, we need to hook all Qt python +# extension modules provided by specific python Qt bindings package. +# +# The above approach with single dictionary, however, has several limitations: +# - it cannot provide association for Qt python module that binds a Qt module without a shared library (i.e., a +# headers-only module, or a statically-built module). In such cases, potential plugins and translations should +# be associated directly with the Qt python extension file instead of the Qt module's (non-existent) shared library. +# - it cannot (directly) handle differences between Qt5 and Qt6; we had to build a second dictionary +# - it cannot handle differences between the bindings themselves; for example, PyQt5 binds some Qt modules that +# PySide2 does not bind. Or, the binding's Qt python extension module is named differently in PyQt and PySide +# bindings (or just differently in PyQt5, while PySide2, PySide6, and PyQt6 use the same name). +# +# In order address the above shortcomings, we now store all information a list of structures that contain information +# for a particular Qt python extension and/or Qt module (shared library): +# - python extension name (if applicable) +# - Qt module name base (if applicable) +# - plugins +# - translation files base name +# - applicable Qt version (if necessary) +# - applicable Qt bindings (if necessary) +# +# This list is used to dynamically construct two dictionaries (based on the bindings name and Qt version): +# - mapping python extension names to associated module information +# - mapping Qt shared library names to associated module information +# This allows us to associate plugins and translations with either Qt python extension or with the Qt module's shared +# library (or both), whichever is applicable. +# +# The `qt_dynamic_dependencies_dict`_ from the original approach was constructed using several information sources, as +# documented `here +# ˙_. +# +# In the current approach, the relations stored in the `QT_MODULES_INFO`_ list were determined directly, by inspecting +# the Qt source code. This requires some prior knowledge of how the Qt code is organized (repositories and individual Qt +# modules within them), as well as some searching based on guesswork. The procedure can be outlined as follows: +# * check out the `main Qt repository `_. This repository contains references to all other +# Qt repositories in the form of git submodules. +# * for Qt5: +# * check out the latest release tag, e.g., v5.15.2, then check out the submodules. +# * search the Qt modules' qmake .pro files; for example, ``qtbase/src/network/network.pro`` for QtNetwork module. +# The plugin types associated with the module are listed in the ``MODULE_PLUGIN_TYPES`` variable (in this case, +# ``bearer``). +# * all translations are gathered in ``qttranslations`` sub-module/repository, and their association with +# individual repositories can be seen in ``qttranslations/translations/translations.pro``. +# * for Qt6: +# * check out the latest release tag, e.g., v6.3.1, then check out the submodules. +# * search the Qt modules' CMake files; for example, ``qtbase/src/network/CMakeLists.txt`` for QtNetwork module. +# The plugin types associated with the module are listed under ``PLUGIN_TYPES`` argument of the +# ``qt_internal_add_module()`` function that defines the Qt module. +# +# The idea is to make a list of all extension modules found in a Qt bindings package, as well as all available plugin +# directories (which correspond to plugin types) and translation files. For each extension, identify the corresponding +# Qt module (shared library name) and its associated plugins and translation files. Once this is done, most of available +# plugins and translations in the python bindings package should have a corresponding python Qt extension module +# available; this gives us associations based on the python extension module names as well as based on the Qt shared +# library names. For any plugins and translation files remaining unassociated, identify the corresponding Qt module; +# this gives us associations based only on Qt shared library names. While this second group of associations are never +# processed directly (due to lack of corresponding python extension), they may end up being processed during the +# recursive dependency analysis, if the corresponding Qt shared library is linked against by some Qt python extension +# or another Qt shared library. + + +# This structure is used to define Qt module information, such as python module/extension name, Qt module (shared +# library) name, translation files' base names, plugins, as well as associated python bindings (which implicitly +# also encode major Qt version). +class _QtModuleDef: + def __init__(self, module, shared_lib=None, translations=None, plugins=None, bindings=None): + # Python module (extension) name without package namespace. For example, `QtCore`. + # Can be None if python bindings do not bind the module, but we still need to establish relationship between + # the Qt module (shared library) and its plugins and translations. + self.module = module + # Associated Qt module (shared library), if any. Used during recursive dependency analysis, where a python + # module (extension) is analyzed for linked Qt modules (shared libraries), and then their corresponding + # python modules (extensions) are added to hidden imports. For example, the Qt module name is `Qt5Core` or + # `Qt6Core`, depending on the Qt version. Can be None for python modules that are not tied to a particular + # Qt shared library (for example, the corresponding Qt module is headers-only) and hence they cannot be + # inferred from recursive link-time dependency analysis. + self.shared_lib = shared_lib + # List of base names of translation files (if any) associated with the Qt module. Multiple base names may be + # associated with a single module. + # For example, `['qt', 'qtbase']` for `QtCore` or `['qtmultimedia']` for `QtMultimedia`. + self.translations = translations or [] + # List of plugins associated with the Qt module. + self.plugins = plugins or [] + # List of bindings (PySide2, PyQt5, PySide6, PyQt6) that provide the python module. This allows association of + # plugins and translations with shared libraries even for bindings that do not provide python module binding + # for the Qt module. + self.bindings = set(bindings or []) + + +# All Qt-based bindings. +ALL_QT_BINDINGS = {"PySide2", "PyQt5", "PySide6", "PyQt6"} + +# Qt modules information - the core of our Qt collection approach. +# +# For every python module/extension (i.e., entry in the list below that has valid `module`), we need a corresponding +# hook, ensuring that the extension file is analyzed, so that we collect the associated plugins and translation +# files, as well as perform recursive analysis of link-time binary dependencies (so that plugins and translation files +# belonging to those dependencies are collected as well). +QT_MODULES_INFO = ( + # *** qt/qt3d *** + _QtModuleDef("Qt3DAnimation", shared_lib="3DAnimation"), + _QtModuleDef("Qt3DCore", shared_lib="3DCore"), + _QtModuleDef("Qt3DExtras", shared_lib="3DExtras"), + _QtModuleDef("Qt3DInput", shared_lib="3DInput", plugins=["3dinputdevices"]), + _QtModuleDef("Qt3DLogic", shared_lib="3DLogic"), + _QtModuleDef( + "Qt3DRender", shared_lib="3DRender", plugins=["geometryloaders", "renderplugins", "renderers", "sceneparsers"] + ), + + # *** qt/qtactiveqt *** + # The python module is called QAxContainer in PyQt bindings, but QtAxContainer in PySide. The associated Qt module + # is header-only, so there is no shared library. + _QtModuleDef("QAxContainer", bindings=["PyQt*"]), + _QtModuleDef("QtAxContainer", bindings=["PySide*"]), + + # *** qt/qtcharts *** + # The python module is called QtChart in PyQt5, and QtCharts in PySide2, PySide6, and PyQt6 (which corresponds to + # the associated Qt module name, QtCharts). + _QtModuleDef("QtChart", shared_lib="Charts", bindings=["PyQt5"]), + _QtModuleDef("QtCharts", shared_lib="Charts", bindings=["!PyQt5"]), + + # *** qt/qtbase *** + # QtConcurrent python module is available only in PySide bindings. + _QtModuleDef(None, shared_lib="Concurrent", bindings=["PyQt*"]), + _QtModuleDef("QtConcurrent", shared_lib="Concurrent", bindings=["PySide*"]), + _QtModuleDef("QtCore", shared_lib="Core", translations=["qt", "qtbase"]), + # QtDBus python module is available in all bindings but PySide2. + _QtModuleDef(None, shared_lib="DBus", bindings=["PySide2"]), + _QtModuleDef("QtDBus", shared_lib="DBus", bindings=["!PySide2"]), + # QtNetwork uses different plugins in Qt5 and Qt6. + _QtModuleDef("QtNetwork", shared_lib="Network", plugins=["bearer"], bindings=["PySide2", "PyQt5"]), + _QtModuleDef( + "QtNetwork", + shared_lib="Network", + plugins=["networkaccess", "networkinformation", "tls"], + bindings=["PySide6", "PyQt6"] + ), + _QtModuleDef( + "QtGui", + shared_lib="Gui", + plugins=[ + "accessiblebridge", + "egldeviceintegrations", + "generic", + "iconengines", + "imageformats", + "platforms", + "platforms/darwin", + "platforminputcontexts", + "platformthemes", + "xcbglintegrations", + # The ``wayland-*`` plugins are part of QtWaylandClient Qt module, whose shared library + # (e.g., libQt5WaylandClient.so) is linked by the wayland-related ``platforms`` plugins. Ideally, we would + # collect these plugins based on the QtWaylandClient shared library entry, but as our Qt hook utilities do + # not scan the plugins for dependencies, that would not work. So instead we list these plugins under QtGui + # to achieve pretty much the same end result. + "wayland-decoration-client", + "wayland-graphics-integration-client", + "wayland-shell-integration" + ] + ), + _QtModuleDef("QtOpenGL", shared_lib="OpenGL"), + # This python module is specific to PySide2 and has no associated Qt module. + _QtModuleDef("QtOpenGLFunctions", bindings=["PySide2"]), + # This Qt module was introduced with Qt6. + _QtModuleDef("QtOpenGLWidgets", shared_lib="OpenGLWidgets", bindings=["PySide6", "PyQt6"]), + _QtModuleDef("QtPrintSupport", shared_lib="PrintSupport", plugins=["printsupport"]), + _QtModuleDef("QtSql", shared_lib="Sql", plugins=["sqldrivers"]), + _QtModuleDef("QtTest", shared_lib="Test"), + _QtModuleDef("QtWidgets", shared_lib="Widgets", plugins=["styles"]), + _QtModuleDef("QtXml", shared_lib="Xml"), + + # *** qt/qtconnectivity *** + _QtModuleDef("QtBluetooth", shared_lib="QtBluetooth", translations=["qtconnectivity"]), + _QtModuleDef("QtNfc", shared_lib="Nfc", translations=["qtconnectivity"]), + + # *** qt/qtdatavis3d *** + _QtModuleDef("QtDataVisualization", shared_lib="DataVisualization"), + + # *** qt/qtdeclarative *** + _QtModuleDef("QtQml", shared_lib="Qml", translations=["qtdeclarative"], plugins=["qmltooling"]), + # Have the Qt5 variant collect translations for qtquickcontrols (qt/qtquickcontrols provides only QtQuick plugins). + _QtModuleDef( + "QtQuick", + shared_lib="Quick", + translations=["qtquickcontrols"], + plugins=["scenegraph"], + bindings=["PySide2", "PyQt5"] + ), + _QtModuleDef("QtQuick", shared_lib="Quick", plugins=["scenegraph"], bindings=["PySide6", "PyQt6"]), + # Qt6-only; in Qt5, this module is part of qt/qtquickcontrols2. Python module is available only in PySide6. + _QtModuleDef(None, shared_lib="QuickControls2", bindings=["PyQt6"]), + _QtModuleDef("QtQuickControls2", shared_lib="QuickControls2", bindings=["PySide6"]), + _QtModuleDef("QtQuickWidgets", shared_lib="QuickWidgets"), + + # *** qt/qtgamepad *** + # No python module; shared library -> plugins association entry. + _QtModuleDef(None, shared_lib="Gamepad", plugins=["gamepads"]), + + # *** qt/qthttpserver *** + # Qt6 >= 6.4.0; python module is available only in PySide6. + _QtModuleDef("QtHttpServer", shared_lib="HttpServer", bindings=["PySide6"]), + + # *** qt/qtlocation *** + # QtLocation was reintroduced in Qt6 v6.5.0. + _QtModuleDef( + "QtLocation", + shared_lib="Location", + translations=["qtlocation"], + plugins=["geoservices"], + bindings=["PySide2", "PyQt5", "PySide6"] + ), + _QtModuleDef( + "QtPositioning", + shared_lib="Positioning", + translations=["qtlocation"], + plugins=["position"], + ), + + # *** qt/qtmacextras *** + # Qt5-only Qt module. + _QtModuleDef("QtMacExtras", shared_lib="MacExtras", bindings=["PySide2", "PyQt5"]), + + # *** qt/qtmultimedia *** + # QtMultimedia on Qt6 currently uses only a subset of plugin names from Qt5 counterpart. + _QtModuleDef( + "QtMultimedia", + shared_lib="Multimedia", + translations=["qtmultimedia"], + plugins=[ + "mediaservice", "audio", "video/bufferpool", "video/gstvideorenderer", "video/videonode", "playlistformats", + "resourcepolicy" + ], + bindings=["PySide2", "PyQt5"] + ), + _QtModuleDef( + "QtMultimedia", + shared_lib="Multimedia", + translations=["qtmultimedia"], + # `multimedia` plugins are available as of Qt6 >= 6.4.0; earlier versions had `video/gstvideorenderer` and + # `video/videonode` plugins. + plugins=["multimedia", "video/gstvideorenderer", "video/videonode"], + bindings=["PySide6", "PyQt6"] + ), + _QtModuleDef("QtMultimediaWidgets", shared_lib="MultimediaWidgets"), + # Qt6-only Qt module; python module is available in PySide6 >= 6.4.0 and PyQt6 >= 6.5.0 + _QtModuleDef("QtSpatialAudio", shared_lib="SpatialAudio", bindings=["PySide6", "PyQt6"]), + + # *** qt/qtnetworkauth *** + # QtNetworkAuth python module is available in all bindings but PySide2. + _QtModuleDef(None, shared_lib="NetworkAuth", bindings=["PySide2"]), + _QtModuleDef("QtNetworkAuth", shared_lib="NetworkAuth", bindings=["!PySide2"]), + + # *** qt/qtpurchasing *** + # Qt5-only Qt module, python module is available only in PyQt5. + _QtModuleDef("QtPurchasing", shared_lib="Purchasing", bindings=["PyQt5"]), + + # *** qt/qtquick1 *** + # This is an old, Qt 5.3-era module... + _QtModuleDef( + "QtDeclarative", + shared_lib="Declarative", + translations=["qtquick1"], + plugins=["qml1tooling"], + bindings=["PySide2", "PyQt5"] + ), + + # *** qt/qtquick3d *** + # QtQuick3D python module is available in all bindings but PySide2. + _QtModuleDef(None, shared_lib="Quick3D", bindings=["PySide2"]), + _QtModuleDef("QtQuick3D", shared_lib="Quick3D", bindings=["!PySide2"]), + # No python module; shared library -> plugins association entry. + _QtModuleDef(None, shared_lib="Quick3DAssetImport", plugins=["assetimporters"]), + + # *** qt/qtquickcontrols2 *** + # Qt5-only module; in Qt6, this module is part of qt/declarative. Python module is available only in PySide2. + _QtModuleDef(None, translations=["qtquickcontrols2"], shared_lib="QuickControls2", bindings=["PyQt5"]), + _QtModuleDef( + "QtQuickControls2", translations=["qtquickcontrols2"], shared_lib="QuickControls2", bindings=["PySide2"] + ), + + # *** qt/qtremoteobjects *** + _QtModuleDef("QtRemoteObjects", shared_lib="RemoteObjects"), + + # *** qt/qtscxml *** + # Python module is available only in PySide bindings. Plugins are available only in Qt6. + # PyQt wheels do not seem to ship the corresponding Qt modules (shared libs) at all. + _QtModuleDef("QtScxml", shared_lib="Scxml", bindings=["PySide2"]), + _QtModuleDef("QtScxml", shared_lib="Scxml", plugins=["scxmldatamodel"], bindings=["PySide6"]), + # Qt6-only Qt module, python module is available only in PySide6. + _QtModuleDef("QtStateMachine", shared_lib="StateMachine", bindings=["PySide6"]), + + # *** qt/qtsensors *** + _QtModuleDef("QtSensors", shared_lib="Sensors", plugins=["sensors", "sensorgestures"]), + + # *** qt/qtserialport *** + _QtModuleDef("QtSerialPort", shared_lib="SerialPort", translations=["qtserialport"]), + + # *** qt/qtscript *** + # Qt5-only Qt module, python module is available only in PySide2. PyQt5 wheels do not seem to ship the corresponding + # Qt modules (shared libs) at all. + _QtModuleDef("QtScript", shared_lib="Script", translations=["qtscript"], plugins=["script"], bindings=["PySide2"]), + _QtModuleDef("QtScriptTools", shared_lib="ScriptTools", bindings=["PySide2"]), + + # *** qt/qtserialbus *** + # No python module; shared library -> plugins association entry. + # PySide6 6.5.0 introduced python module. + _QtModuleDef(None, shared_lib="SerialBus", plugins=["canbus"], bindings=["!PySide6"]), + _QtModuleDef("QtSerialBus", shared_lib="SerialBus", plugins=["canbus"], bindings=["PySide6"]), + + # *** qt/qtsvg *** + _QtModuleDef("QtSvg", shared_lib="Svg"), + # Qt6-only Qt module. + _QtModuleDef("QtSvgWidgets", shared_lib="SvgWidgets", bindings=["PySide6", "PyQt6"]), + + # *** qt/qtspeech *** + _QtModuleDef("QtTextToSpeech", shared_lib="TextToSpeech", plugins=["texttospeech"]), + + # *** qt/qttools *** + # QtDesigner python module is available in all bindings but PySide2. + _QtModuleDef(None, shared_lib="Designer", plugins=["designer"], bindings=["PySide2"]), + _QtModuleDef( + "QtDesigner", shared_lib="Designer", translations=["designer"], plugins=["designer"], bindings=["!PySide2"] + ), + _QtModuleDef("QtHelp", shared_lib="Help", translations=["qt_help"]), + # Python module is available only in PySide bindings. + _QtModuleDef("QtUiTools", shared_lib="UiTools", bindings=["PySide*"]), + + # *** qt/qtvirtualkeyboard *** + # No python module; shared library -> plugins association entry. + _QtModuleDef(None, shared_lib="VirtualKeyboard", plugins=["virtualkeyboard"]), + + # *** qt/qtwebchannel *** + _QtModuleDef("QtWebChannel", shared_lib="WebChannel"), + + # *** qt/qtwebengine *** + # QtWebEngine is Qt5-only module (replaced by QtWebEngineQuick in Qt6). + _QtModuleDef("QtWebEngine", shared_lib="WebEngine", bindings=["PySide2", "PyQt5"]), + _QtModuleDef("QtWebEngineCore", shared_lib="WebEngineCore", translations=["qtwebengine"]), + # QtWebEngineQuick is Qt6-only module (replacement for QtWebEngine in Qt5). + _QtModuleDef("QtWebEngineQuick", shared_lib="WebEngineQuick", bindings=["PySide6", "PyQt6"]), + _QtModuleDef("QtWebEngineWidgets", shared_lib="WebEngineWidgets"), + # QtPdf and QtPdfWidgets have python module available in PySide6 and PyQt6 >= 6.4.0. + _QtModuleDef("QtPdf", shared_lib="Pdf", bindings=["PySide6", "PyQt6"]), + _QtModuleDef("QtPdfWidgets", shared_lib="PdfWidgets", bindings=["PySide6", "PyQt6"]), + + # *** qt/qtwebsockets *** + _QtModuleDef("QtWebSockets", shared_lib="WebSockets", translations=["qtwebsockets"]), + + # *** qt/qtwebview *** + # No python module; shared library -> plugins association entry. + _QtModuleDef(None, shared_lib="WebView", plugins=["webview"]), + + # *** qt/qtwinextras *** + # Qt5-only Qt module. + _QtModuleDef("QtWinExtras", shared_lib="WinExtras", bindings=["PySide2", "PyQt5"]), + + # *** qt/qtx11extras *** + # Qt5-only Qt module. + _QtModuleDef("QtX11Extras", shared_lib="X11Extras", bindings=["PySide2", "PyQt5"]), + + # *** qt/qtxmlpatterns *** + # Qt5-only Qt module. + _QtModuleDef( + "QtXmlPatterns", shared_lib="XmlPatterns", translations=["qtxmlpatterns"], bindings=["PySide2", "PyQt5"] + ), + + # *** qscintilla *** + # Python module is available only in PyQt bindings. No associated shared library. + _QtModuleDef("Qsci", translations=["qscintilla"], bindings=["PyQt*"]), +) + + +# Helpers for turning Qt namespace specifiers, such as "!PySide2" or "PyQt*", into set of applicable +# namespaces. +def process_namespace_strings(namespaces): + """"Process list of Qt namespace specifier strings into set of namespaces.""" + bindings = set() + for namespace in namespaces: + bindings |= _process_namespace_string(namespace) + return bindings + + +def _process_namespace_string(namespace): + """Expand a Qt namespace specifier string into set of namespaces.""" + if namespace.startswith("!"): + bindings = _process_namespace_string(namespace[1:]) + return ALL_QT_BINDINGS - bindings + else: + if namespace == "PySide*": + return {"PySide2", "PySide6"} + elif namespace == "PyQt*": + return {"PyQt5", "PyQt6"} + elif namespace in ALL_QT_BINDINGS: + return {namespace} + else: + raise ValueError(f"Invalid Qt namespace specifier: {namespace}!") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/tcl_tk.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/tcl_tk.py new file mode 100755 index 000000000..2dbc08b0a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/tcl_tk.py @@ -0,0 +1,284 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +import locale +import os + +from PyInstaller import compat +from PyInstaller import isolated +from PyInstaller import log as logging +from PyInstaller.building.datastruct import Tree +from PyInstaller.depend import bindepend + +logger = logging.getLogger(__name__) + +TK_ROOTNAME = 'tk' +TCL_ROOTNAME = 'tcl' + + +@isolated.decorate +def _get_tcl_tk_info(): + """ + Isolated-subprocess helper to retrieve the basic Tcl/Tk information: + - tcl_dir = path to the Tcl library/data directory. + - tcl_version = Tcl version + - tk_version = Tk version + - tcl_theaded = boolean indicating whether Tcl/Tk is built with multi-threading support. + """ + try: + import tkinter + from _tkinter import TCL_VERSION, TK_VERSION + except ImportError: + # tkinter unavailable + return None, None, None, False + try: + tcl = tkinter.Tcl() + except tkinter.TclError: # e.g. "Can't find a usable init.tcl in the following directories: ..." + return None, None, None, False + + # Query the location of Tcl library/data directory. + tcl_dir = tcl.eval("info library") + + # Check if Tcl/Tk is built with multi-threaded support (built with --enable-threads), as indicated by the presence + # of optional `threaded` member in `tcl_platform` array. + try: + tcl.getvar("tcl_platform(threaded)") # Ignore the actual value. + tcl_threaded = True + except tkinter.TclError: + tcl_threaded = False + + return tcl_dir, TCL_VERSION, TK_VERSION, tcl_threaded + + +# Populate the variables. If `tkinter` is unavailable, the values are set to `None` or `False`. +( + tcl_dir, + tcl_version, + tk_version, + tcl_threaded, +) = _get_tcl_tk_info() + + +def _warn_if_activetcl_or_teapot_installed(tcl_root, tcltree): + """ + If the current Tcl installation is a Teapot-distributed version of ActiveTcl *and* the current platform is macOS, + log a non-fatal warning that the resulting executable will (probably) fail to run on non-host systems. + + PyInstaller does *not* freeze all ActiveTcl dependencies -- including Teapot, which is typically ignorable. Since + Teapot is *not* ignorable in this case, this function warns of impending failure. + + See Also + ------- + https://github.com/pyinstaller/pyinstaller/issues/621 + """ + import macholib.util + + # System libraries do not experience this problem. + if macholib.util.in_system_path(tcl_root): + return + + # Absolute path of the "init.tcl" script. + try: + init_resource = [r[1] for r in tcltree if r[1].endswith('init.tcl')][0] + except IndexError: + # If such script could not be found, silently return. + return + + mentions_activetcl = False + mentions_teapot = False + # TCL/TK reads files using the system encoding: + # https://www.tcl.tk/doc/howto/i18n.html#system_encoding + with open(init_resource, 'r', encoding=locale.getpreferredencoding()) as init_file: + for line in init_file.readlines(): + line = line.strip().lower() + if line.startswith('#'): + continue + if 'activetcl' in line: + mentions_activetcl = True + if 'teapot' in line: + mentions_teapot = True + if mentions_activetcl and mentions_teapot: + break + + if mentions_activetcl and mentions_teapot: + logger.warning( + """ +You appear to be using an ActiveTcl build of Tcl/Tk, which PyInstaller has +difficulty freezing. To fix this, comment out all references to "teapot" in: + + %s + +See https://github.com/pyinstaller/pyinstaller/issues/621 for more information. + """ % init_resource + ) + + +def find_tcl_tk_shared_libs(tkinter_ext_file): + """ + Find Tcl and Tk shared libraries against which the _tkinter module is linked. + + Returns + ------- + list + list containing two tuples, one for Tcl and one for Tk library, where each tuple contains the library name and + its full path, i.e., [(tcl_lib, tcl_libpath), (tk_lib, tk_libpath)]. If a library is not found, the + corresponding tuple elements are set to None. + """ + tcl_lib = None + tcl_libpath = None + tk_lib = None + tk_libpath = None + + # Do not use bindepend.selectImports, as it ignores libraries seen during previous invocations. + _tkinter_imports = bindepend.getImports(tkinter_ext_file) + + def _get_library_path(lib): + if compat.is_win: + # On Windows, we need to resolve full path to the library. + path = bindepend.getfullnameof(lib) + else: + # Non-Windows systems (including Cygwin) already return full path to the library. + path = lib + return path + + for lib in _tkinter_imports: + # On some platforms, full path to the shared library is returned. So check only basename to prevent false + # positive matches due to words tcl or tk being contained in the path. + lib_name = os.path.basename(lib) + lib_name_lower = lib_name.lower() # lower-case for comparisons + + if 'tcl' in lib_name_lower: + tcl_lib = lib_name + tcl_libpath = _get_library_path(lib) + elif 'tk' in lib_name_lower: + tk_lib = lib_name + tk_libpath = _get_library_path(lib) + + return [(tcl_lib, tcl_libpath), (tk_lib, tk_libpath)] + + +def _find_tcl_tk(tkinter_ext_file): + """ + Get a platform-specific 2-tuple of the absolute paths of the top-level external data directories for both + Tcl and Tk, respectively. + + Returns + ------- + list + 2-tuple that contains the values of `${TCL_LIBRARY}` and `${TK_LIBRARY}`, respectively. + """ + if compat.is_darwin: + # On macOS, _tkinter extension is linked either against the system Tcl/Tk framework (older homebrew python, + # python3 from XCode tools) or against bundled Tcl/Tk library (recent python.org builds, recent homebrew + # python with python-tk). PyInstaller does not bundle data from system frameworks (as it does not not collect + # shared libraries from them, either), so we need to determine what kind of Tcl/Tk we are dealing with. + libs = find_tcl_tk_shared_libs(tkinter_ext_file) + + # Check the full path to the Tcl library. + path_to_tcl = libs[0][1] + + # Starting with macOS 11, system libraries are hidden (unless both Python and PyInstaller's bootloader are built + # against MacOS 11.x SDK). Therefore, libs may end up empty; but that implicitly indicates that the system + # framework is used, so return (None, None) to inform the caller. + if path_to_tcl is None: + return None, None + + # Check if the path corresponds to the system framework, i.e., [/System]/Library/Frameworks/Tcl.framework/Tcl + if 'Library/Frameworks/Tcl.framework' in path_to_tcl: + return None, None # Do not collect system framework's data. + + # Bundled copy of Tcl/Tk; in this case, the dynamic library is + # /Library/Frameworks/Python.framework/Versions/3.x/lib/libtcl8.6.dylib + # and the data directories have standard layout that is handled by code below. + else: + # On Windows and linux, data directories have standard layout that is handled by code below. + pass + + # The Tcl library location is already stored in `tcl_dir` global variable. The Tk library is in the same prefix, so + # construct the path using `tk_version` global variable. + tk_dir = os.path.join(os.path.dirname(tcl_dir), f"tk{tk_version}") + return tcl_dir, tk_dir + + +def _collect_tcl_modules(tcl_root): + """ + Get a list of TOC-style 3-tuples describing Tcl modules. The modules directory is separate from the library/data + one, and is located at $tcl_root/../tclX, where X is the major Tcl version. + + Returns + ------- + Tree + Such list, if the modules directory exists. + """ + + # Obtain Tcl major version. + tcl_major_version = tcl_version.split('.')[0] + + modules_dirname = f"tcl{tcl_major_version}" + modules_path = os.path.join(tcl_root, '..', modules_dirname) + + if not os.path.isdir(modules_path): + logger.warning('Tcl modules directory %s does not exist.', modules_path) + return [] + + return Tree(modules_path, prefix=modules_dirname) + + +def collect_tcl_tk_files(tkinter_ext_file): + """ + Get a list of TOC-style 3-tuples describing all external Tcl/Tk data files. + + Returns + ------- + Tree + Such list. + """ + # Find Tcl and Tk data directory by analyzing the _tkinter extension. + tcl_root, tk_root = _find_tcl_tk(tkinter_ext_file) + + # On macOS, we do not collect system libraries. Therefore, if system Tcl/Tk framework is used, it makes no sense to + # collect its data, either. In this case, _find_tcl_tk() will return None, None - either deliberately (we found the + # data paths, but ignore them) or not (starting with macOS 11, the data path cannot be found until shared library + # discovery is fixed). + if compat.is_darwin and not tcl_root and not tk_root: + logger.info( + "Not collecting Tcl/Tk data - either python is using macOS\' system Tcl/Tk framework, or Tcl/Tk data " + "directories could not be found." + ) + return [] + + # TODO Shouldn't these be fatal exceptions? + if not tcl_root: + logger.error('Tcl/Tk improperly installed on this system.') + return [] + if not os.path.isdir(tcl_root): + logger.error('Tcl data directory "%s" not found.', tcl_root) + return [] + if not os.path.isdir(tk_root): + logger.error('Tk data directory "%s" not found.', tk_root) + return [] + + # Collect Tcl and Tk scripts from their corresponding library/data directories. In contrast to source directories, + # which are typically versioned (tcl8.6, tk8.6), the target directories are unversioned (tcl, tk); they are added + # to the Tcl/Tk search path via runtime hook for _tkinter, which sets the `TCL_LIBRARY` and `TK_LIBRARY` environment + # variables. + tcltree = Tree(tcl_root, prefix=TCL_ROOTNAME, excludes=['demos', '*.lib', 'tclConfig.sh']) + tktree = Tree(tk_root, prefix=TK_ROOTNAME, excludes=['demos', '*.lib', 'tkConfig.sh']) + + # If the current Tcl installation is a Teapot-distributed version of ActiveTcl and the current platform is Mac OS, + # warn that this is bad. + if compat.is_darwin: + _warn_if_activetcl_or_teapot_installed(tcl_root, tcltree) + + # Collect Tcl modules. + tclmodulestree = _collect_tcl_modules(tcl_root) + + return tcltree + tktree + tclmodulestree diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/win32.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/win32.py new file mode 100755 index 000000000..50b013d31 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/hooks/win32.py @@ -0,0 +1,46 @@ +# ---------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +# ---------------------------------------------------------------------------- + +from PyInstaller import isolated + + +@isolated.decorate +def get_pywin32_module_file_attribute(module_name): + """ + Get the absolute path of the PyWin32 DLL specific to the PyWin32 module with the passed name. + + On import, each PyWin32 module: + + * Imports a DLL specific to that module. + * Overwrites the values of all module attributes with values specific to that DLL. This includes that module's + `__file__` attribute, which then provides the absolute path of that DLL. + + This function safely imports that module in a PyWin32-aware subprocess and returns the value of that module's + `__file__` attribute. + + Parameters + ---------- + module_name : str + Fully-qualified name of that module. + + Returns + ---------- + str + Absolute path of that DLL. + + See Also + ---------- + `PyInstaller.utils.win32.winutils.import_pywin32_module()` + For further details. + """ + from PyInstaller.utils.win32 import winutils + module = winutils.import_pywin32_module(module_name) + return module.__file__ diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/misc.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/misc.py new file mode 100755 index 000000000..b43dfe88e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/misc.py @@ -0,0 +1,247 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +This module contains miscellaneous functions that do not fit anywhere else. +""" + +import glob +import os +import pprint +import codecs +import re +import tokenize +import io +import pathlib + +from PyInstaller import log as logging +from PyInstaller.compat import is_win + +logger = logging.getLogger(__name__) + + +def dlls_in_subdirs(directory): + """ + Returns a list *.dll, *.so, *.dylib in the given directory and its subdirectories. + """ + filelist = [] + for root, dirs, files in os.walk(directory): + filelist.extend(dlls_in_dir(root)) + return filelist + + +def dlls_in_dir(directory): + """ + Returns a list of *.dll, *.so, *.dylib in the given directory. + """ + return files_in_dir(directory, ["*.so", "*.dll", "*.dylib"]) + + +def files_in_dir(directory, file_patterns=None): + """ + Returns a list of files in the given directory that match the given pattern. + """ + + file_patterns = file_patterns or [] + + files = [] + for file_pattern in file_patterns: + files.extend(glob.glob(os.path.join(directory, file_pattern))) + return files + + +def get_unicode_modules(): + """ + Try importing modules required for unicode support in the frozen application. + """ + modules = [] + try: + # `codecs` depends on `encodings`, so the latter are included automatically. + import codecs # noqa: F401 + modules.append('codecs') + except ImportError: + logger.error("Cannot detect modules 'codecs'.") + + return modules + + +def get_path_to_toplevel_modules(filename): + """ + Return the path to top-level directory that contains Python modules. + + It will look in parent directories for __init__.py files. The first parent directory without __init__.py is the + top-level directory. + + Returned directory might be used to extend the PYTHONPATH. + """ + curr_dir = os.path.dirname(os.path.abspath(filename)) + pattern = '__init__.py' + + # Try max. 10 levels up. + try: + for i in range(10): + files = set(os.listdir(curr_dir)) + # 'curr_dir' is still not top-level; go to parent dir. + if pattern in files: + curr_dir = os.path.dirname(curr_dir) + # Top-level dir found; return it. + else: + return curr_dir + except IOError: + pass + # No top-level directory found, or error was encountered. + return None + + +def mtime(fnm): + try: + # TODO: explain why this does not use os.path.getmtime() ? + # - It is probably not used because it returns float and not int. + return os.stat(fnm)[8] + except Exception: + return 0 + + +def save_py_data_struct(filename, data): + """ + Save data into text file as Python data structure. + :param filename: + :param data: + :return: + """ + dirname = os.path.dirname(filename) + if not os.path.exists(dirname): + os.makedirs(dirname) + with open(filename, 'w', encoding='utf-8') as f: + pprint.pprint(data, f) + + +def load_py_data_struct(filename): + """ + Load data saved as python code and interpret that code. + :param filename: + :return: + """ + with open(filename, 'r', encoding='utf-8') as f: + # Binding redirects are stored as a named tuple, so bring the namedtuple class into scope for parsing the TOC. + from PyInstaller.depend.bindepend import BindingRedirect # noqa: F401 + + if is_win: + # import versioninfo so that VSVersionInfo can parse correctly. + from PyInstaller.utils.win32 import versioninfo # noqa: F401 + + return eval(f.read()) + + +def absnormpath(apath): + return os.path.abspath(os.path.normpath(apath)) + + +def module_parent_packages(full_modname): + """ + Return list of parent package names. + 'aaa.bb.c.dddd' -> ['aaa', 'aaa.bb', 'aaa.bb.c'] + :param full_modname: Full name of a module. + :return: List of parent module names. + """ + prefix = '' + parents = [] + # Ignore the last component in module name and get really just parent, grandparent, great grandparent, etc. + for pkg in full_modname.split('.')[0:-1]: + # Ensure that first item does not start with dot '.' + prefix += '.' + pkg if prefix else pkg + parents.append(prefix) + return parents + + +def is_file_qt_plugin(filename): + """ + Check if the given file is a Qt plugin file. + :param filename: Full path to file to check. + :return: True if given file is a Qt plugin file, False if not. + """ + + # Check the file contents; scan for QTMETADATA string. The scan is based on the brute-force Windows codepath of + # findPatternUnloaded() from qtbase/src/corelib/plugin/qlibrary.cpp in Qt5. + with open(filename, 'rb') as fp: + fp.seek(0, os.SEEK_END) + end_pos = fp.tell() + + SEARCH_CHUNK_SIZE = 8192 + QTMETADATA_MAGIC = b'QTMETADATA ' + + magic_offset = -1 + while end_pos >= len(QTMETADATA_MAGIC): + start_pos = max(end_pos - SEARCH_CHUNK_SIZE, 0) + chunk_size = end_pos - start_pos + # Is the remaining chunk large enough to hold the pattern? + if chunk_size < len(QTMETADATA_MAGIC): + break + # Read and scan the chunk + fp.seek(start_pos, os.SEEK_SET) + buf = fp.read(chunk_size) + pos = buf.rfind(QTMETADATA_MAGIC) + if pos != -1: + magic_offset = start_pos + pos + break + # Adjust search location for next chunk; ensure proper overlap. + end_pos = start_pos + len(QTMETADATA_MAGIC) - 1 + if magic_offset == -1: + return False + + return True + + +BOM_MARKERS_TO_DECODERS = { + codecs.BOM_UTF32_LE: codecs.utf_32_le_decode, + codecs.BOM_UTF32_BE: codecs.utf_32_be_decode, + codecs.BOM_UTF32: codecs.utf_32_decode, + codecs.BOM_UTF16_LE: codecs.utf_16_le_decode, + codecs.BOM_UTF16_BE: codecs.utf_16_be_decode, + codecs.BOM_UTF16: codecs.utf_16_decode, + codecs.BOM_UTF8: codecs.utf_8_decode, +} +BOM_RE = re.compile(rb"\A(%s)?(.*)" % b"|".join(map(re.escape, BOM_MARKERS_TO_DECODERS)), re.DOTALL) + + +def decode(raw: bytes): + """ + Decode bytes to string, respecting and removing any byte-order marks if present, or respecting but not removing any + PEP263 encoding comments (# encoding: cp1252). + """ + bom, raw = BOM_RE.match(raw).groups() + if bom: + return BOM_MARKERS_TO_DECODERS[bom](raw)[0] + + encoding, _ = tokenize.detect_encoding(io.BytesIO(raw).readline) + return raw.decode(encoding) + + +def is_iterable(arg): + """ + Check if the passed argument is an iterable." + """ + try: + iter(arg) + except TypeError: + return False + return True + + +def path_to_parent_archive(filename): + """ + Check if the given file path points to a file inside an existing archive file. Returns first path from the set of + parent paths that points to an existing file, or `None` if no such path exists (i.e., file is an actual stand-alone + file). + """ + for parent in pathlib.Path(filename).parents: + if parent.is_file(): + return parent + return None diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/osx.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/osx.py new file mode 100755 index 000000000..d81a4582b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/osx.py @@ -0,0 +1,542 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2014-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Utils for Mac OS platform. +""" + +import math +import os +import pathlib +import subprocess +import shutil +import tempfile + +from macholib.mach_o import ( + LC_BUILD_VERSION, + LC_CODE_SIGNATURE, + LC_ID_DYLIB, + LC_LOAD_DYLIB, + LC_LOAD_UPWARD_DYLIB, + LC_LOAD_WEAK_DYLIB, + LC_PREBOUND_DYLIB, + LC_REEXPORT_DYLIB, + LC_RPATH, + LC_SEGMENT_64, + LC_SYMTAB, + LC_VERSION_MIN_MACOSX, +) +from macholib.MachO import MachO +import macholib.util + +import PyInstaller.log as logging +from PyInstaller.compat import base_prefix + +logger = logging.getLogger(__name__) + + +def is_homebrew_env(): + """ + Check if Python interpreter was installed via Homebrew command 'brew'. + + :return: True if Homebrew else otherwise. + """ + # Python path prefix should start with Homebrew prefix. + env_prefix = get_homebrew_prefix() + if env_prefix and base_prefix.startswith(env_prefix): + return True + return False + + +def is_macports_env(): + """ + Check if Python interpreter was installed via Macports command 'port'. + + :return: True if Macports else otherwise. + """ + # Python path prefix should start with Macports prefix. + env_prefix = get_macports_prefix() + if env_prefix and base_prefix.startswith(env_prefix): + return True + return False + + +def get_homebrew_prefix(): + """ + :return: Root path of the Homebrew environment. + """ + prefix = shutil.which('brew') + # Conversion: /usr/local/bin/brew -> /usr/local + prefix = os.path.dirname(os.path.dirname(prefix)) + return prefix + + +def get_macports_prefix(): + """ + :return: Root path of the Macports environment. + """ + prefix = shutil.which('port') + # Conversion: /usr/local/bin/port -> /usr/local + prefix = os.path.dirname(os.path.dirname(prefix)) + return prefix + + +def _find_version_cmd(header): + """ + Helper that finds the version command in the given MachO header. + """ + # The SDK version is stored in LC_BUILD_VERSION command (used when targeting the latest versions of macOS) or in + # older LC_VERSION_MIN_MACOSX command. Check for presence of either. + version_cmd = [cmd for cmd in header.commands if cmd[0].cmd in {LC_BUILD_VERSION, LC_VERSION_MIN_MACOSX}] + assert len(version_cmd) == 1, "Expected exactly one LC_BUILD_VERSION or LC_VERSION_MIN_MACOSX command!" + return version_cmd[0] + + +def get_macos_sdk_version(filename): + """ + Obtain the version of macOS SDK against which the given binary was built. + + NOTE: currently, version is retrieved only from the first arch slice in the binary. + + :return: (major, minor, revision) tuple + """ + binary = MachO(filename) + header = binary.headers[0] + # Find version command using helper + version_cmd = _find_version_cmd(header) + return _hex_triplet(version_cmd[1].sdk) + + +def _hex_triplet(version): + # Parse SDK version number + major = (version & 0xFF0000) >> 16 + minor = (version & 0xFF00) >> 8 + revision = (version & 0xFF) + return major, minor, revision + + +def macosx_version_min(filename: str) -> tuple: + """ + Get the -macosx-version-min used to compile a macOS binary. + + For fat binaries, the minimum version is selected. + """ + versions = [] + for header in MachO(filename).headers: + cmd = _find_version_cmd(header) + if cmd[0].cmd == LC_VERSION_MIN_MACOSX: + versions.append(cmd[1].version) + else: + # macOS >= 10.14 uses LC_BUILD_VERSION instead. + versions.append(cmd[1].minos) + + return min(map(_hex_triplet, versions)) + + +def set_macos_sdk_version(filename, major, minor, revision): + """ + Overwrite the macOS SDK version declared in the given binary with the specified version. + + NOTE: currently, only version in the first arch slice is modified. + """ + # Validate values + assert 0 <= major <= 255, "Invalid major version value!" + assert 0 <= minor <= 255, "Invalid minor version value!" + assert 0 <= revision <= 255, "Invalid revision value!" + # Open binary + binary = MachO(filename) + header = binary.headers[0] + # Find version command using helper + version_cmd = _find_version_cmd(header) + # Write new SDK version number + version_cmd[1].sdk = major << 16 | minor << 8 | revision + # Write changes back. + with open(binary.filename, 'rb+') as fp: + binary.write(fp) + + +def fix_exe_for_code_signing(filename): + """ + Fixes the Mach-O headers to make code signing possible. + + Code signing on Mac OS does not work out of the box with embedding .pkg archive into the executable. + + The fix is done this way: + - Make the embedded .pkg archive part of the Mach-O 'String Table'. 'String Table' is at end of the Mac OS exe file, + so just change the size of the table to cover the end of the file. + - Fix the size of the __LINKEDIT segment. + + Note: the above fix works only if the single-arch thin executable or the last arch slice in a multi-arch fat + executable is not signed, because LC_CODE_SIGNATURE comes after LC_SYMTAB, and because modification of headers + invalidates the code signature. On modern arm64 macOS, code signature is mandatory, and therefore compilers + create a dummy signature when executable is built. In such cases, that signature needs to be removed before this + function is called. + + Mach-O format specification: http://developer.apple.com/documentation/Darwin/Reference/ManPages/man5/Mach-O.5.html + """ + # Estimate the file size after data was appended + file_size = os.path.getsize(filename) + + # Take the last available header. A single-arch thin binary contains a single slice, while a multi-arch fat binary + # contains multiple, and we need to modify the last one, which is adjacent to the appended data. + executable = MachO(filename) + header = executable.headers[-1] + + # Sanity check: ensure the executable slice is not signed (otherwise signature's section comes last in the + # __LINKEDIT segment). + sign_sec = [cmd for cmd in header.commands if cmd[0].cmd == LC_CODE_SIGNATURE] + assert len(sign_sec) == 0, "Executable contains code signature!" + + # Find __LINKEDIT segment by name (16-byte zero padded string) + __LINKEDIT_NAME = b'__LINKEDIT\x00\x00\x00\x00\x00\x00' + linkedit_seg = [cmd for cmd in header.commands if cmd[0].cmd == LC_SEGMENT_64 and cmd[1].segname == __LINKEDIT_NAME] + assert len(linkedit_seg) == 1, "Expected exactly one __LINKEDIT segment!" + linkedit_seg = linkedit_seg[0][1] # Take the segment command entry + # Find SYMTAB section + symtab_sec = [cmd for cmd in header.commands if cmd[0].cmd == LC_SYMTAB] + assert len(symtab_sec) == 1, "Expected exactly one SYMTAB section!" + symtab_sec = symtab_sec[0][1] # Take the symtab command entry + + # The string table is located at the end of the SYMTAB section, which in turn is the last section in the __LINKEDIT + # segment. Therefore, the end of SYMTAB section should be aligned with the end of __LINKEDIT segment, and in turn + # both should be aligned with the end of the file (as we are in the last or the only arch slice). + # + # However, when removing the signature from the executable using codesign under Mac OS 10.13, the codesign utility + # may produce an invalid file, with the declared length of the __LINKEDIT segment (linkedit_seg.filesize) pointing + # beyond the end of file, as reported in issue #6167. + # + # We can compensate for that by not using the declared sizes anywhere, and simply recompute them. In the final + # binary, the __LINKEDIT segment and the SYMTAB section MUST end at the end of the file (otherwise, we have bigger + # issues...). So simply recompute the declared sizes as difference between the final file length and the + # corresponding start offset (NOTE: the offset is relative to start of the slice, which is stored in header.offset. + # In thin binaries, header.offset is zero and start offset is relative to the start of file, but with fat binaries, + # header.offset is non-zero) + symtab_sec.strsize = file_size - (header.offset + symtab_sec.stroff) + linkedit_seg.filesize = file_size - (header.offset + linkedit_seg.fileoff) + + # Compute new vmsize by rounding filesize up to full page size. + page_size = (0x4000 if _get_arch_string(header.header).startswith('arm64') else 0x1000) + linkedit_seg.vmsize = math.ceil(linkedit_seg.filesize / page_size) * page_size + + # NOTE: according to spec, segments need to be aligned to page boundaries: 0x4000 (16 kB) for arm64, 0x1000 (4 kB) + # for other arches. But it seems we can get away without rounding and padding the segment file size - perhaps + # because it is the last one? + + # Write changes + with open(filename, 'rb+') as fp: + executable.write(fp) + + # In fat binaries, we also need to adjust the fat header. macholib as of version 1.14 does not support this, so we + # need to do it ourselves... + if executable.fat: + from macholib.mach_o import (FAT_MAGIC, FAT_MAGIC_64, fat_arch, fat_arch64, fat_header) + with open(filename, 'rb+') as fp: + # Taken from MachO.load_fat() implementation. The fat header's signature has already been validated when we + # loaded the file for the first time. + fat = fat_header.from_fileobj(fp) + if fat.magic == FAT_MAGIC: + archs = [fat_arch.from_fileobj(fp) for i in range(fat.nfat_arch)] + elif fat.magic == FAT_MAGIC_64: + archs = [fat_arch64.from_fileobj(fp) for i in range(fat.nfat_arch)] + # Adjust the size in the fat header for the last slice. + arch = archs[-1] + arch.size = file_size - arch.offset + # Now write the fat headers back to the file. + fp.seek(0) + fat.to_fileobj(fp) + for arch in archs: + arch.to_fileobj(fp) + + +def _get_arch_string(header): + """ + Converts cputype and cpusubtype from mach_o.mach_header_64 into arch string comparible with lipo/codesign. + The list of supported architectures can be found in man(1) arch. + """ + # NOTE: the constants below are taken from macholib.mach_o + cputype = header.cputype + cpusubtype = header.cpusubtype & 0x0FFFFFFF + if cputype == 0x01000000 | 7: + if cpusubtype == 8: + return 'x86_64h' # 64-bit intel (haswell) + else: + return 'x86_64' # 64-bit intel + elif cputype == 0x01000000 | 12: + if cpusubtype == 2: + return 'arm64e' + else: + return 'arm64' + elif cputype == 7: + return 'i386' # 32-bit intel + assert False, 'Unhandled architecture!' + + +class InvalidBinaryError(Exception): + """ + Exception raised by ˙get_binary_architectures˙ when it is passed an invalid binary. + """ + pass + + +class IncompatibleBinaryArchError(Exception): + """ + Exception raised by `binary_to_target_arch` when the passed binary fails the strict architecture check. + """ + pass + + +def get_binary_architectures(filename): + """ + Inspects the given binary and returns tuple (is_fat, archs), where is_fat is boolean indicating fat/thin binary, + and arch is list of architectures with lipo/codesign compatible names. + """ + try: + executable = MachO(filename) + except ValueError as e: + raise InvalidBinaryError("Invalid Mach-O binary!") from e + return bool(executable.fat), [_get_arch_string(hdr.header) for hdr in executable.headers] + + +def convert_binary_to_thin_arch(filename, thin_arch, output_filename=None): + """ + Convert the given fat binary into thin one with the specified target architecture. + """ + output_filename = output_filename or filename + cmd_args = ['lipo', '-thin', thin_arch, filename, '-output', output_filename] + p = subprocess.run(cmd_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) + if p.returncode: + raise SystemError(f"lipo command ({cmd_args}) failed with error code {p.returncode}!\noutput: {p.stdout}") + + +def merge_into_fat_binary(output_filename, *slice_filenames): + """ + Merge the given single-arch thin binary files into a fat binary. + """ + cmd_args = ['lipo', '-create', '-output', output_filename, *slice_filenames] + p = subprocess.run(cmd_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) + if p.returncode: + raise SystemError(f"lipo command ({cmd_args}) failed with error code {p.returncode}!\noutput: {p.stdout}") + + +def binary_to_target_arch(filename, target_arch, display_name=None): + """ + Check that the given binary contains required architecture slice(s) and convert the fat binary into thin one, + if necessary. + """ + if not display_name: + display_name = filename # Same as input file + # Check the binary + is_fat, archs = get_binary_architectures(filename) + if target_arch == 'universal2': + if not is_fat: + raise IncompatibleBinaryArchError(f"{display_name} is not a fat binary!") + # Assume fat binary is universal2; nothing to do + else: + if is_fat: + if target_arch not in archs: + raise IncompatibleBinaryArchError(f"{display_name} does not contain slice for {target_arch}!") + # Convert to thin arch + logger.debug("Converting fat binary %s (%s) to thin binary (%s)", filename, display_name, target_arch) + convert_binary_to_thin_arch(filename, target_arch) + else: + if target_arch not in archs: + raise IncompatibleBinaryArchError( + f"{display_name} is incompatible with target arch {target_arch} (has arch: {archs[0]})!" + ) + # Binary has correct arch; nothing to do + + +def remove_signature_from_binary(filename): + """ + Remove the signature from all architecture slices of the given binary file using the codesign utility. + """ + logger.debug("Removing signature from file %r", filename) + cmd_args = ['codesign', '--remove', '--all-architectures', filename] + p = subprocess.run(cmd_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) + if p.returncode: + raise SystemError(f"codesign command ({cmd_args}) failed with error code {p.returncode}!\noutput: {p.stdout}") + + +def sign_binary(filename, identity=None, entitlements_file=None, deep=False): + """ + Sign the binary using codesign utility. If no identity is provided, ad-hoc signing is performed. + """ + extra_args = [] + if not identity: + identity = '-' # ad-hoc signing + else: + extra_args.append('--options=runtime') # hardened runtime + if entitlements_file: + extra_args.append('--entitlements') + extra_args.append(entitlements_file) + if deep: + extra_args.append('--deep') + + logger.debug("Signing file %r", filename) + cmd_args = ['codesign', '-s', identity, '--force', '--all-architectures', '--timestamp', *extra_args, filename] + p = subprocess.run(cmd_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) + if p.returncode: + raise SystemError(f"codesign command ({cmd_args}) failed with error code {p.returncode}!\noutput: {p.stdout}") + + +def set_dylib_dependency_paths(filename, target_rpath): + """ + Modify the given dylib's identity (in LC_ID_DYLIB command) and the paths to dependent dylibs (in LC_LOAD_DYLIB) + commands into `@rpath/` format, remove any existing rpaths (LC_RPATH commands), and add a new rpath + (LC_RPATH command) with the specified path. + + Uses `install-tool-name` utility to make the changes. + + The system libraries (e.g., the ones found in /usr/lib) are exempted from path rewrite. + + For multi-arch fat binaries, this function extracts each slice into temporary file, processes it separately, + and then merges all processed slices back into fat binary. This is necessary because `install-tool-name` cannot + modify rpaths in cases when an existing rpath is present only in one slice. + """ + + # Check if we are dealing with a fat binary; the `install-name-tool` seems to be unable to remove an rpath that is + # present only in one slice, so we need to extract each slice, process it separately, and then stich processed + # slices back into a fat binary. + is_fat, archs = get_binary_architectures(filename) + + if is_fat: + with tempfile.TemporaryDirectory() as tmpdir: + slice_filenames = [] + for arch in archs: + slice_filename = os.path.join(tmpdir, arch) + convert_binary_to_thin_arch(filename, arch, output_filename=slice_filename) + _set_dylib_dependency_paths(slice_filename, target_rpath) + slice_filenames.append(slice_filename) + merge_into_fat_binary(filename, *slice_filenames) + else: + # Thin binary - we can process it directly + _set_dylib_dependency_paths(filename, target_rpath) + + +def _set_dylib_dependency_paths(filename, target_rpath): + """ + The actual implementation of set_dylib_dependency_paths functionality. + + Implicitly assumes that a single-arch thin binary is given. + """ + + # Relocatable commands that we should overwrite - same list as used by `macholib`. + _RELOCATABLE = { + LC_LOAD_DYLIB, + LC_LOAD_UPWARD_DYLIB, + LC_LOAD_WEAK_DYLIB, + LC_PREBOUND_DYLIB, + LC_REEXPORT_DYLIB, + } + + # Parse dylib's header to extract the following commands: + # - LC_LOAD_DYLIB (or any member of _RELOCATABLE list): dylib load commands (dependent libraries) + # - LC_RPATH: rpath definitions + # - LC_ID_DYLIB: dylib's identity + binary = MachO(filename) + + dylib_id = None + rpaths = set() + linked_libs = set() + + for header in binary.headers: + for cmd in header.commands: + lc_type = cmd[0].cmd + if lc_type not in _RELOCATABLE and lc_type not in {LC_RPATH, LC_ID_DYLIB}: + continue + + # Decode path, strip trailing NULL characters + path = cmd[2].decode('utf-8').rstrip('\x00') + + if lc_type in _RELOCATABLE: + linked_libs.add(path) + elif lc_type == LC_RPATH: + rpaths.add(path) + elif lc_type == LC_ID_DYLIB: + dylib_id = path + + del binary + + # If dylib has identifier set, compute the normalized version, in form of `@rpath/basename`. + normalized_dylib_id = None + if dylib_id: + normalized_dylib_id = str(pathlib.PurePath('@rpath') / pathlib.PurePath(dylib_id).name) + + # Find dependent libraries that should have their prefix path changed to `@rpath`. If any dependent libraries + # end up using `@rpath` (originally or due to rewrite), set the `rpath_required` boolean to True, so we know + # that we need to add our rpath. + changed_lib_paths = [] + rpath_required = False + for linked_lib in linked_libs: + # Leave system dynamic libraries unchanged. + if macholib.util.in_system_path(linked_lib): + continue + + # The older python.org builds that use system Tcl/Tk framework have their _tkinter.cpython-*-darwin.so + # library linked against /Library/Frameworks/Tcl.framework/Versions/8.5/Tcl and + # /Library/Frameworks/Tk.framework/Versions/8.5/Tk, although the actual frameworks are located in + # /System/Library/Frameworks. Therefore, they slip through the above in_system_path() check, and we need to + # exempt them manually. + _exemptions = [ + '/Library/Frameworks/Tcl.framework/', + '/Library/Frameworks/Tk.framework/', + ] + if any([x in linked_lib for x in _exemptions]): + continue + + # This linked library will end up using `@rpath`, whether modified or not... + rpath_required = True + + new_path = str(pathlib.PurePath('@rpath') / pathlib.PurePath(linked_lib).name) + if linked_lib == new_path: + continue + + changed_lib_paths.append((linked_lib, new_path)) + + # Gather arguments for `install-name-tool` + install_name_tool_args = [] + + # Modify the dylib identifier if necessary + if normalized_dylib_id and normalized_dylib_id != dylib_id: + install_name_tool_args += ["-id", normalized_dylib_id] + + # Changed libs + for original_path, new_path in changed_lib_paths: + install_name_tool_args += ["-change", original_path, new_path] + + # Remove all existing rpaths except for the target rpath (if it already exists). `install_name_tool` disallows using + # `-delete_rpath` and `-add_rpath` with the same argument. + for rpath in rpaths: + if rpath == target_rpath: + continue + install_name_tool_args += [ + "-delete_rpath", + rpath, + ] + + # If any of linked libraries use @rpath now and our target rpath is not already added, add it. + # NOTE: @rpath in the dylib identifier does not actually require the rpath to be set on the binary... + if rpath_required and target_rpath not in rpaths: + install_name_tool_args += [ + "-add_rpath", + target_rpath, + ] + + # If we have no arguments, finish immediately. + if not install_name_tool_args: + return + + # Run `install_name_tool` + cmd_args = ["install_name_tool", *install_name_tool_args, filename] + p = subprocess.run(cmd_args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True) + if p.returncode: + raise SystemError( + f"install_name_tool command ({cmd_args}) failed with error code {p.returncode}!\noutput: {p.stdout}" + ) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/run_tests.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/run_tests.py new file mode 100755 index 000000000..8eb02826b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/run_tests.py @@ -0,0 +1,69 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +# ----------------------------------------------------------------------------- + +import argparse +import sys + +import pkg_resources +import pytest + + +def paths_to_test(include_only=None): + """ + If ``include_only`` is falsey, this functions returns paths from all entry points. Otherwise, this parameter + must be a string or sequence of strings. In this case, this function will return *only* paths from entry points + whose ``module_name`` begins with the provided string(s). + """ + # Convert a string to a list. + if isinstance(include_only, str): + include_only = [include_only] + + # Walk through all entry points. + test_path_list = [] + for entry_point in pkg_resources.iter_entry_points("pyinstaller40", "tests"): + # Implement ``include_only``. + if ( + not include_only # If falsey, include everything, + # Otherwise, include only the specified modules. + or any(entry_point.module_name.startswith(name) for name in include_only) + ): + test_path_list += list(entry_point.load()()) + return test_path_list + + +# Run pytest on all tests registered by the PyInstaller setuptools testing entry point. If provided, +# the ``include_only`` argument is passed to ``path_to_test``. +def run_pytest(*args, **kwargs): + paths = paths_to_test(include_only=kwargs.pop("include_only", None)) + # Return an error code if no tests were discovered. + if not paths: + print("Error: no tests discovered.", file=sys.stderr) + # This indicates no tests were discovered; see + # https://docs.pytest.org/en/latest/usage.html#possible-exit-codes. + return 5 + else: + # See https://docs.pytest.org/en/latest/usage.html#calling-pytest-from-python-code. + # Omit ``args[0]``, which is the name of this script. + print("pytest " + " ".join([*paths, *args[1:]])) + return pytest.main([*paths, *args[1:]], **kwargs) + + +if __name__ == "__main__": + # Look only for the ``--include_only`` argument. + parser = argparse.ArgumentParser(description='Run PyInstaller packaging tests.') + parser.add_argument( + "--include_only", + action="append", + help="Only run tests from the specified package.", + ) + args, unknown = parser.parse_known_args(sys.argv) + # Convert the parsed args into a dict using ``vars(args)``. + sys.exit(run_pytest(*unknown, **vars(args))) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/tests.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/tests.py new file mode 100755 index 000000000..d13b21c7b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/tests.py @@ -0,0 +1,154 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Decorators for skipping PyInstaller tests when specific requirements are not met. +""" + +import distutils.ccompiler +import inspect +import os +import shutil +import textwrap + +import pytest +import sys + +from PyInstaller.compat import is_win + +# Wrap some pytest decorators to be consistent in tests. +parametrize = pytest.mark.parametrize +skipif = pytest.mark.skipif +xfail = pytest.mark.xfail + + +def _check_for_compiler(): + import tempfile + + # Change to some tempdir since cc.has_function() would compile into the current directory, leaving garbage. + old_wd = os.getcwd() + tmp = tempfile.mkdtemp() + os.chdir(tmp) + cc = distutils.ccompiler.new_compiler() + if is_win: + try: + cc.initialize() + has_compiler = True + # This error is raised on Windows if a compiler can't be found. + except distutils.errors.DistutilsPlatformError: + has_compiler = False + else: + # The C standard library contains the ``clock`` function. Use that to determine if a compiler is installed. This + # does not work on Windows:: + # + # Users\bjones\AppData\Local\Temp\a.out.exe.manifest : general error + # c1010070: Failed to load and parse the manifest. The system cannot + # find the file specified. + has_compiler = cc.has_function('clock', includes=['time.h']) + os.chdir(old_wd) + # TODO: Find a way to remove the generated clockXXXX.c file, too + shutil.rmtree(tmp) + return has_compiler + + +# A decorator to skip tests if a C compiler is not detected. +has_compiler = _check_for_compiler() +skipif_no_compiler = skipif(not has_compiler, reason="Requires a C compiler") + +skip = pytest.mark.skip + + +def importorskip(package: str): + """ + Skip a decorated test if **package** is not importable. + + Arguments: + package: + The name of the module. May be anything that is allowed after the ``import`` keyword. e.g. 'numpy' or + 'PIL.Image'. + Returns: + A pytest marker which either skips the test or does nothing. + + This function intentionally does not import the module. Doing so can lead to `sys.path` and `PATH` being + polluted, which then breaks later builds. + """ + if not importable(package): + return pytest.mark.skip(f"Can't import '{package}'.") + return pytest.mark.skipif(False, reason=f"Don't skip: '{package}' is importable.") + + +def importable(package: str): + from importlib.util import find_spec + + # The find_spec() function is used by the importlib machinery to locate a module to import. Using it finds the + # module but does not run it. Unfortunately, it does import parent modules to check submodules. + if "." in package: + # Using subprocesses is slow. If the top level module doesn't exist then we can skip it. + if not importable(package.split(".")[0]): + return False + # This is a submodule, import it in isolation. + from subprocess import DEVNULL, run + return run([sys.executable, "-c", "import " + package], stdout=DEVNULL, stderr=DEVNULL).returncode == 0 + + return find_spec(package) is not None + + +def requires(requirement: str): + """ + Mark a test to be skipped if **requirement** is not satisfied. + + Args: + requirement: + A distribution name and optionally a version. See :func:`pkg_resources.require` which this argument is + forwarded to. + Returns: + Either a skip marker or a dummy marker. + + This function intentionally does not import the module. Doing so can lead to `sys.path` and `PATH` being + polluted, which then breaks later builds. + """ + import pkg_resources + try: + pkg_resources.require(requirement) + return pytest.mark.skipif(False, reason=f"Don't skip: '{requirement}' is satisfied.") + except pkg_resources.ResolutionError: + return pytest.mark.skip("Requires " + requirement) + + +def gen_sourcefile(tmpdir, source, test_id=None): + """ + Generate a source file for testing. + + The source will be written into a file named like the test-function. This file will then be passed to + `test_script`. If you need other related file, e.g. as `.toc`-file for testing the content, put it at at the + normal place. Just mind to take the basnename from the test-function's name. + + :param script: Source code to create executable from. This will be saved into a temporary file which is then + passed on to `test_script`. + + :param test_id: Test-id for parametrized tests. If given, it will be appended to the script filename, + separated by two underscores. + + Ensure that the caller of `test_source` is in a UTF-8 encoded file with the correct '# -*- coding: utf-8 -*-' + marker. + """ + testname = inspect.stack()[1][3] + if test_id: + # For parametrized test append the test-id. + testname = testname + '__' + test_id + + # Periods are not allowed in Python module names. + testname = testname.replace('.', '_') + scriptfile = tmpdir / (testname + '.py') + source = textwrap.dedent(source) + with scriptfile.open('w', encoding='utf-8') as ofh: + print('# -*- coding: utf-8 -*-', file=ofh) + print(source, file=ofh) + return scriptfile diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/win32/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/win32/__init__.py new file mode 100755 index 000000000..a7501ae07 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/win32/__init__.py @@ -0,0 +1 @@ +__author__ = 'martin' diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/win32/icon.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/win32/icon.py new file mode 100755 index 000000000..776ba0741 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/win32/icon.py @@ -0,0 +1,248 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +The code in this module supports the --icon parameter on Windows. +(For --icon support under Mac OS, see building/osx.py.) + +The only entry point, called from api.py, is CopyIcons(), below. All the elaborate structure of classes that follows +is used to support the operation of CopyIcons_FromIco(). None of these classes and globals are referenced outside +this module. +""" + +import os.path +import struct + +import PyInstaller.log as logging +from PyInstaller import config +from PyInstaller.compat import pywintypes, win32api +from PyInstaller.building.icon import normalize_icon_type + +logger = logging.getLogger(__name__) + +RT_ICON = 3 +RT_GROUP_ICON = 14 +LOAD_LIBRARY_AS_DATAFILE = 2 + + +class Structure: + def __init__(self): + size = self._sizeInBytes = struct.calcsize(self._format_) + self._fields_ = list(struct.unpack(self._format_, b'\000' * size)) + indexes = self._indexes_ = {} + for i, nm in enumerate(self._names_): + indexes[nm] = i + + def dump(self): + logger.info("DUMP of %s", self) + for name in self._names_: + if not name.startswith('_'): + logger.info("%20s = %s", name, getattr(self, name)) + logger.info("") + + def __getattr__(self, name): + if name in self._names_: + index = self._indexes_[name] + return self._fields_[index] + try: + return self.__dict__[name] + except KeyError as e: + raise AttributeError(name) from e + + def __setattr__(self, name, value): + if name in self._names_: + index = self._indexes_[name] + self._fields_[index] = value + else: + self.__dict__[name] = value + + def tostring(self): + return struct.pack(self._format_, *self._fields_) + + def fromfile(self, file): + data = file.read(self._sizeInBytes) + self._fields_ = list(struct.unpack(self._format_, data)) + + +class ICONDIRHEADER(Structure): + _names_ = "idReserved", "idType", "idCount" + _format_ = "hhh" + + +class ICONDIRENTRY(Structure): + _names_ = ("bWidth", "bHeight", "bColorCount", "bReserved", "wPlanes", "wBitCount", "dwBytesInRes", "dwImageOffset") + _format_ = "bbbbhhii" + + +class GRPICONDIR(Structure): + _names_ = "idReserved", "idType", "idCount" + _format_ = "hhh" + + +class GRPICONDIRENTRY(Structure): + _names_ = ("bWidth", "bHeight", "bColorCount", "bReserved", "wPlanes", "wBitCount", "dwBytesInRes", "nID") + _format_ = "bbbbhhih" + + +# An IconFile instance is created for each .ico file given. +class IconFile: + def __init__(self, path): + self.path = path + try: + # The path is from the user parameter, don't trust it. + file = open(self.path, "rb") + except OSError: + # The icon file can't be opened for some reason. Stop the + # program with an informative message. + raise SystemExit(f'Unable to open icon file {self.path}!') + with file: + self.entries = [] + self.images = [] + header = self.header = ICONDIRHEADER() + header.fromfile(file) + for i in range(header.idCount): + entry = ICONDIRENTRY() + entry.fromfile(file) + self.entries.append(entry) + for e in self.entries: + file.seek(e.dwImageOffset, 0) + self.images.append(file.read(e.dwBytesInRes)) + + def grp_icon_dir(self): + return self.header.tostring() + + def grp_icondir_entries(self, id=1): + data = b'' + for entry in self.entries: + e = GRPICONDIRENTRY() + for n in e._names_[:-1]: + setattr(e, n, getattr(entry, n)) + e.nID = id + id = id + 1 + data = data + e.tostring() + return data + + +def CopyIcons_FromIco(dstpath, srcpath, id=1): + """ + Use the Win API UpdateResource facility to apply the icon resource(s) to the .exe file. + + :param str dstpath: absolute path of the .exe file being built. + :param str srcpath: list of 1 or more .ico file paths + """ + icons = map(IconFile, srcpath) + logger.info("Copying icons from %s", srcpath) + + hdst = win32api.BeginUpdateResource(dstpath, 0) + + iconid = 1 + # Each step in the following enumerate() will instantiate an IconFile object, as a result of deferred execution + # of the map() above. + for i, f in enumerate(icons): + data = f.grp_icon_dir() + data = data + f.grp_icondir_entries(iconid) + win32api.UpdateResource(hdst, RT_GROUP_ICON, i, data) + logger.info("Writing RT_GROUP_ICON %d resource with %d bytes", i, len(data)) + for data in f.images: + win32api.UpdateResource(hdst, RT_ICON, iconid, data) + logger.info("Writing RT_ICON %d resource with %d bytes", iconid, len(data)) + iconid = iconid + 1 + + win32api.EndUpdateResource(hdst, 0) + + +def CopyIcons(dstpath, srcpath): + """ + Called from building/api.py to handle icons. If the input was by --icon on the command line, srcpath is a single + string. However, it is possible to modify the spec file adding icon=['foo.ico','bar.ico'] to the EXE() statement. + In that case, srcpath is a list of strings. + + The string format is either path-to-.ico or path-to-.exe,n for n an integer resource index in the .exe. In either + case, the path can be relative or absolute. + """ + + if isinstance(srcpath, str): + # Just a single string, make it a one-element list. + srcpath = [srcpath] + + def splitter(s): + """ + Convert "pathname" to tuple ("pathname", None) + Convert "pathname,n" to tuple ("pathname", n) + """ + try: + srcpath, index = s.split(',') + return srcpath.strip(), int(index) + except ValueError: + return s, None + + # split all the items in the list into tuples as above. + srcpath = list(map(splitter, srcpath)) + + if len(srcpath) > 1: + # More than one icon source given. We currently handle multiple icons by calling CopyIcons_FromIco(), which only + # allows .ico, but will convert to that format if needed. + # + # Note that a ",index" on a .ico is just ignored in the single or multiple case. + srcs = [] + for s in srcpath: + srcs.append(normalize_icon_type(s[0], ("ico",), "ico", config.CONF["workpath"])) + return CopyIcons_FromIco(dstpath, srcs) + + # Just one source given. + srcpath, index = srcpath[0] + + # Makes sure the icon exists and attempts to convert to the proper format if applicable + srcpath = normalize_icon_type(srcpath, ("exe", "ico"), "ico", config.CONF["workpath"]) + + srcext = os.path.splitext(srcpath)[1] + + # Handle the simple case of foo.ico, ignoring any index. + if srcext.lower() == '.ico': + return CopyIcons_FromIco(dstpath, [srcpath]) + + # Single source is not .ico, presumably it is .exe (and if not, some error will occur). + if index is not None: + logger.info("Copying icon from %s, %d", srcpath, index) + else: + logger.info("Copying icons from %s", srcpath) + + try: + # Attempt to load the .ico or .exe containing the icon into memory using the same mechanism as if it were a DLL. + # If this fails for any reason (for example if the file does not exist or is not a .ico/.exe) then LoadLibraryEx + # returns a null handle and win32api raises a unique exception with a win error code and a string. + hsrc = win32api.LoadLibraryEx(srcpath, 0, LOAD_LIBRARY_AS_DATAFILE) + except pywintypes.error as W32E: + # We could continue with no icon (i.e., just return), but it seems best to terminate the build with a message. + raise SystemExit( + "Unable to load icon file {}\n {} (Error code {})".format(srcpath, W32E.strerror, W32E.winerror) + ) + hdst = win32api.BeginUpdateResource(dstpath, 0) + if index is None: + grpname = win32api.EnumResourceNames(hsrc, RT_GROUP_ICON)[0] + elif index >= 0: + grpname = win32api.EnumResourceNames(hsrc, RT_GROUP_ICON)[index] + else: + grpname = -index + data = win32api.LoadResource(hsrc, RT_GROUP_ICON, grpname) + win32api.UpdateResource(hdst, RT_GROUP_ICON, grpname, data) + for iconname in win32api.EnumResourceNames(hsrc, RT_ICON): + data = win32api.LoadResource(hsrc, RT_ICON, iconname) + win32api.UpdateResource(hdst, RT_ICON, iconname, data) + win32api.FreeLibrary(hsrc) + win32api.EndUpdateResource(hdst, 0) + + +if __name__ == "__main__": + import sys + + dstpath = sys.argv[1] + srcpath = sys.argv[2:] + CopyIcons(dstpath, srcpath) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/win32/versioninfo.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/win32/versioninfo.py new file mode 100755 index 000000000..4a56425f6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/win32/versioninfo.py @@ -0,0 +1,605 @@ +# -*- coding: utf-8 -*- +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +import struct + +import pefile + +from PyInstaller.compat import win32api + + +def pefile_check_control_flow_guard(filename): + """ + Checks if the specified PE file has CFG (Control Flow Guard) enabled. + + Parameters + ---------- + filename : str + Path to the PE file to inspect. + + Returns + ---------- + bool + True if file is a PE file with CFG enabled. False if CFG is not enabled or if file could not be processed using + the pefile library. + """ + try: + pe = pefile.PE(filename, fast_load=True) + # https://docs.microsoft.com/en-us/windows/win32/debug/pe-format + # IMAGE_DLLCHARACTERISTICS_GUARD_CF = 0x4000 + return bool(pe.OPTIONAL_HEADER.DllCharacteristics & 0x4000) + except Exception: + return False + + +# Ensures no code from the executable is executed. +LOAD_LIBRARY_AS_DATAFILE = 2 + + +def getRaw(text): + """ + Encodes text as UTF-16LE (Microsoft 'Unicode') for use in structs. + """ + return text.encode('UTF-16LE') + + +def read_version_info_from_executable(exe_filename): + """ + Read the version information structure from the given executable's resources, and return it as an instance of + `VSVersionInfo` structure. + """ + h = win32api.LoadLibraryEx(exe_filename, 0, LOAD_LIBRARY_AS_DATAFILE) + res = win32api.EnumResourceNames(h, pefile.RESOURCE_TYPE['RT_VERSION']) + if not len(res): + return None + data = win32api.LoadResource(h, pefile.RESOURCE_TYPE['RT_VERSION'], res[0]) + info = VSVersionInfo() + info.fromRaw(data) + win32api.FreeLibrary(h) + return info + + +def nextDWord(offset): + """ + Align `offset` to the next 4-byte boundary. + """ + return ((offset + 3) >> 2) << 2 + + +class VSVersionInfo: + """ + WORD wLength; // length of the VS_VERSION_INFO structure + WORD wValueLength; // length of the Value member + WORD wType; // 1 means text, 0 means binary + WCHAR szKey[]; // Contains the Unicode string "VS_VERSION_INFO". + WORD Padding1[]; + VS_FIXEDFILEINFO Value; + WORD Padding2[]; + WORD Children[]; // zero or more StringFileInfo or VarFileInfo + // structures (or both) that are children of the + // current version structure. + """ + def __init__(self, ffi=None, kids=None): + self.ffi = ffi + self.kids = kids or [] + + def fromRaw(self, data): + i, (sublen, vallen, wType, nm) = parseCommon(data) + #vallen is length of the ffi, typ is 0, nm is 'VS_VERSION_INFO'. + i = nextDWord(i) + # Now a VS_FIXEDFILEINFO + self.ffi = FixedFileInfo() + j = self.ffi.fromRaw(data, i) + i = j + while i < sublen: + j = i + i, (csublen, cvallen, ctyp, nm) = parseCommon(data, i) + if nm.strip() == 'StringFileInfo': + sfi = StringFileInfo() + k = sfi.fromRaw(csublen, cvallen, nm, data, i, j + csublen) + self.kids.append(sfi) + i = k + else: + vfi = VarFileInfo() + k = vfi.fromRaw(csublen, cvallen, nm, data, i, j + csublen) + self.kids.append(vfi) + i = k + i = j + csublen + i = nextDWord(i) + return i + + def toRaw(self): + raw_name = getRaw('VS_VERSION_INFO') + rawffi = self.ffi.toRaw() + vallen = len(rawffi) + typ = 0 + sublen = 6 + len(raw_name) + 2 + pad = b'' + if sublen % 4: + pad = b'\000\000' + sublen = sublen + len(pad) + vallen + pad2 = b'' + if sublen % 4: + pad2 = b'\000\000' + tmp = b''.join([kid.toRaw() for kid in self.kids]) + sublen = sublen + len(pad2) + len(tmp) + return struct.pack('hhh', sublen, vallen, typ) + raw_name + b'\000\000' + pad + rawffi + pad2 + tmp + + def __eq__(self, other): + return self.toRaw() == other + + def __str__(self, indent=''): + indent = indent + ' ' + tmp = [kid.__str__(indent + ' ') for kid in self.kids] + tmp = ', \n'.join(tmp) + return '\n'.join([ + "# UTF-8", + "#", + "# For more details about fixed file info 'ffi' see:", + "# http://msdn.microsoft.com/en-us/library/ms646997.aspx", + "VSVersionInfo(", + indent + f"ffi={self.ffi.__str__(indent)},", + indent + "kids=[", + tmp, + indent + "]", + ")", + ]) + + def __repr__(self): + return "versioninfo.VSVersionInfo(ffi=%r, kids=%r)" % (self.ffi, self.kids) + + +def parseCommon(data, start=0): + i = start + 6 + (wLength, wValueLength, wType) = struct.unpack('3h', data[start:i]) + i, text = parseUString(data, i, i + wLength) + return i, (wLength, wValueLength, wType, text) + + +def parseUString(data, start, limit): + i = start + while i < limit: + if data[i:i + 2] == b'\000\000': + break + i += 2 + text = data[start:i].decode('UTF-16LE') + i += 2 + return i, text + + +class FixedFileInfo: + """ + DWORD dwSignature; //Contains the value 0xFEEFO4BD + DWORD dwStrucVersion; // binary version number of this structure. + // The high-order word of this member contains + // the major version number, and the low-order + // word contains the minor version number. + DWORD dwFileVersionMS; // most significant 32 bits of the file's binary + // version number + DWORD dwFileVersionLS; // + DWORD dwProductVersionMS; // most significant 32 bits of the binary version + // number of the product with which this file was + // distributed + DWORD dwProductVersionLS; // + DWORD dwFileFlagsMask; // bitmask that specifies the valid bits in + // dwFileFlags. A bit is valid only if it was + // defined when the file was created. + DWORD dwFileFlags; // VS_FF_DEBUG, VS_FF_PATCHED etc. + DWORD dwFileOS; // VOS_NT, VOS_WINDOWS32 etc. + DWORD dwFileType; // VFT_APP etc. + DWORD dwFileSubtype; // 0 unless VFT_DRV or VFT_FONT or VFT_VXD + DWORD dwFileDateMS; + DWORD dwFileDateLS; + """ + def __init__( + self, + filevers=(0, 0, 0, 0), + prodvers=(0, 0, 0, 0), + mask=0x3f, + flags=0x0, + OS=0x40004, + fileType=0x1, + subtype=0x0, + date=(0, 0) + ): + self.sig = 0xfeef04bd + self.strucVersion = 0x10000 + self.fileVersionMS = (filevers[0] << 16) | (filevers[1] & 0xffff) + self.fileVersionLS = (filevers[2] << 16) | (filevers[3] & 0xffff) + self.productVersionMS = (prodvers[0] << 16) | (prodvers[1] & 0xffff) + self.productVersionLS = (prodvers[2] << 16) | (prodvers[3] & 0xffff) + self.fileFlagsMask = mask + self.fileFlags = flags + self.fileOS = OS + self.fileType = fileType + self.fileSubtype = subtype + self.fileDateMS = date[0] + self.fileDateLS = date[1] + + def fromRaw(self, data, i): + ( + self.sig, + self.strucVersion, + self.fileVersionMS, + self.fileVersionLS, + self.productVersionMS, + self.productVersionLS, + self.fileFlagsMask, + self.fileFlags, + self.fileOS, + self.fileType, + self.fileSubtype, + self.fileDateMS, + self.fileDateLS, + ) = struct.unpack('13L', data[i:i + 52]) + return i + 52 + + def toRaw(self): + return struct.pack( + '13L', + self.sig, + self.strucVersion, + self.fileVersionMS, + self.fileVersionLS, + self.productVersionMS, + self.productVersionLS, + self.fileFlagsMask, + self.fileFlags, + self.fileOS, + self.fileType, + self.fileSubtype, + self.fileDateMS, + self.fileDateLS, + ) + + def __eq__(self, other): + return self.toRaw() == other + + def __str__(self, indent=''): + fv = ( + self.fileVersionMS >> 16, self.fileVersionMS & 0xffff, + self.fileVersionLS >> 16, self.fileVersionLS & 0xffff, + ) # yapf: disable + pv = ( + self.productVersionMS >> 16, self.productVersionMS & 0xffff, + self.productVersionLS >> 16, self.productVersionLS & 0xffff, + ) # yapf: disable + fd = (self.fileDateMS, self.fileDateLS) + tmp = [ + 'FixedFileInfo(', + '# filevers and prodvers should be always a tuple with four items: (1, 2, 3, 4)', + '# Set not needed items to zero 0.', + 'filevers=%s,' % (fv,), + 'prodvers=%s,' % (pv,), + "# Contains a bitmask that specifies the valid bits 'flags'r", + 'mask=%s,' % hex(self.fileFlagsMask), + '# Contains a bitmask that specifies the Boolean attributes of the file.', + 'flags=%s,' % hex(self.fileFlags), + '# The operating system for which this file was designed.', + '# 0x4 - NT and there is no need to change it.', + 'OS=%s,' % hex(self.fileOS), + '# The general type of file.', + '# 0x1 - the file is an application.', + 'fileType=%s,' % hex(self.fileType), + '# The function of the file.', + '# 0x0 - the function is not defined for this fileType', + 'subtype=%s,' % hex(self.fileSubtype), + '# Creation date and time stamp.', + 'date=%s' % (fd,), + ')', + ] + return f'\n{indent} '.join(tmp) + + def __repr__(self): + fv = ( + self.fileVersionMS >> 16, self.fileVersionMS & 0xffff, + self.fileVersionLS >> 16, self.fileVersionLS & 0xffff, + ) # yapf: disable + pv = ( + self.productVersionMS >> 16, self.productVersionMS & 0xffff, + self.productVersionLS >> 16, self.productVersionLS & 0xffff, + ) # yapf: disable + fd = (self.fileDateMS, self.fileDateLS) + return ( + 'versioninfo.FixedFileInfo(filevers=%r, prodvers=%r, ' + 'mask=0x%x, flags=0x%x, OS=0x%x, ' + 'fileType=%r, subtype=0x%x, date=%r)' % + (fv, pv, self.fileFlagsMask, self.fileFlags, self.fileOS, self.fileType, self.fileSubtype, fd) + ) + + +class StringFileInfo: + """ + WORD wLength; // length of the version resource + WORD wValueLength; // length of the Value member in the current + // VS_VERSION_INFO structure + WORD wType; // 1 means text, 0 means binary + WCHAR szKey[]; // Contains the Unicode string 'StringFileInfo'. + WORD Padding[]; + StringTable Children[]; // list of zero or more String structures + """ + def __init__(self, kids=None): + self.name = 'StringFileInfo' + self.kids = kids or [] + + def fromRaw(self, sublen, vallen, name, data, i, limit): + self.name = name + while i < limit: + st = StringTable() + j = st.fromRaw(data, i, limit) + self.kids.append(st) + i = j + return i + + def toRaw(self): + raw_name = getRaw(self.name) + vallen = 0 + typ = 1 + sublen = 6 + len(raw_name) + 2 + pad = b'' + if sublen % 4: + pad = b'\000\000' + tmp = b''.join([kid.toRaw() for kid in self.kids]) + sublen = sublen + len(pad) + len(tmp) + return struct.pack('hhh', sublen, vallen, typ) + raw_name + b'\000\000' + pad + tmp + + def __eq__(self, other): + return self.toRaw() == other + + def __str__(self, indent=''): + new_indent = indent + ' ' + tmp = ', \n'.join(kid.__str__(new_indent) for kid in self.kids) + return f'{indent}StringFileInfo(\n{new_indent}[\n{tmp}\n{new_indent}])' + + def __repr__(self): + return 'versioninfo.StringFileInfo(%r)' % self.kids + + +class StringTable: + """ + WORD wLength; + WORD wValueLength; + WORD wType; + WCHAR szKey[]; + String Children[]; // list of zero or more String structures. + """ + def __init__(self, name=None, kids=None): + self.name = name or '' + self.kids = kids or [] + + def fromRaw(self, data, i, limit): + i, (cpsublen, cpwValueLength, cpwType, self.name) = parseCodePage(data, i, limit) # should be code page junk + i = nextDWord(i) + while i < limit: + ss = StringStruct() + j = ss.fromRaw(data, i, limit) + i = j + self.kids.append(ss) + i = nextDWord(i) + return i + + def toRaw(self): + raw_name = getRaw(self.name) + vallen = 0 + typ = 1 + sublen = 6 + len(raw_name) + 2 + tmp = [] + for kid in self.kids: + raw = kid.toRaw() + if len(raw) % 4: + raw = raw + b'\000\000' + tmp.append(raw) + tmp = b''.join(tmp) + sublen += len(tmp) + return struct.pack('hhh', sublen, vallen, typ) + raw_name + b'\000\000' + tmp + + def __eq__(self, other): + return self.toRaw() == other + + def __str__(self, indent=''): + new_indent = indent + ' ' + tmp = (',\n' + new_indent).join(str(kid) for kid in self.kids) + return f"{indent}StringTable(\n{new_indent}'{self.name}',\n{new_indent}[{tmp}])" + + def __repr__(self): + return 'versioninfo.StringTable(%r, %r)' % (self.name, self.kids) + + +class StringStruct: + """ + WORD wLength; + WORD wValueLength; + WORD wType; + WCHAR szKey[]; + WORD Padding[]; + String Value[]; + """ + def __init__(self, name=None, val=None): + self.name = name or '' + self.val = val or '' + + def fromRaw(self, data, i, limit): + i, (sublen, vallen, typ, self.name) = parseCommon(data, i) + limit = i + sublen + i = nextDWord(i) + i, self.val = parseUString(data, i, limit) + return i + + def toRaw(self): + raw_name = getRaw(self.name) + raw_val = getRaw(self.val) + # TODO: document the size of vallen and sublen. + vallen = len(self.val) + 1 # Number of (wide-)characters, not bytes! + typ = 1 + sublen = 6 + len(raw_name) + 2 + pad = b'' + if sublen % 4: + pad = b'\000\000' + sublen = sublen + len(pad) + (vallen * 2) + return struct.pack('hhh', sublen, vallen, typ) + raw_name + b'\000\000' + pad + raw_val + b'\000\000' + + def __eq__(self, other): + return self.toRaw() == other + + def __str__(self, indent=''): + return "StringStruct(%r, %r)" % (self.name, self.val) + + def __repr__(self): + return 'versioninfo.StringStruct(%r, %r)' % (self.name, self.val) + + +def parseCodePage(data, i, limit): + i, (sublen, wValueLength, wType, nm) = parseCommon(data, i) + return i, (sublen, wValueLength, wType, nm) + + +class VarFileInfo: + """ + WORD wLength; // length of the version resource + WORD wValueLength; // length of the Value member in the current + // VS_VERSION_INFO structure + WORD wType; // 1 means text, 0 means binary + WCHAR szKey[]; // Contains the Unicode string 'VarFileInfo'. + WORD Padding[]; + Var Children[]; // list of zero or more Var structures + """ + def __init__(self, kids=None): + self.kids = kids or [] + + def fromRaw(self, sublen, vallen, name, data, i, limit): + self.sublen = sublen + self.vallen = vallen + self.name = name + i = nextDWord(i) + while i < limit: + vs = VarStruct() + j = vs.fromRaw(data, i, limit) + self.kids.append(vs) + i = j + return i + + def toRaw(self): + self.vallen = 0 + self.wType = 1 + self.name = 'VarFileInfo' + raw_name = getRaw(self.name) + sublen = 6 + len(raw_name) + 2 + pad = b'' + if sublen % 4: + pad = b'\000\000' + tmp = b''.join([kid.toRaw() for kid in self.kids]) + self.sublen = sublen + len(pad) + len(tmp) + return struct.pack('hhh', self.sublen, self.vallen, self.wType) + raw_name + b'\000\000' + pad + tmp + + def __eq__(self, other): + return self.toRaw() == other + + def __str__(self, indent=''): + return indent + "VarFileInfo([%s])" % ', '.join(str(kid) for kid in self.kids) + + def __repr__(self): + return 'versioninfo.VarFileInfo(%r)' % self.kids + + +class VarStruct: + """ + WORD wLength; // length of the version resource + WORD wValueLength; // length of the Value member in the current + // VS_VERSION_INFO structure + WORD wType; // 1 means text, 0 means binary + WCHAR szKey[]; // Contains the Unicode string 'Translation' + // or a user-defined key string value + WORD Padding[]; // + WORD Value[]; // list of one or more values that are language + // and code-page identifiers + """ + def __init__(self, name=None, kids=None): + self.name = name or '' + self.kids = kids or [] + + def fromRaw(self, data, i, limit): + i, (self.sublen, self.wValueLength, self.wType, self.name) = parseCommon(data, i) + i = nextDWord(i) + for j in range(0, self.wValueLength, 2): + kid = struct.unpack('h', data[i:i + 2])[0] + self.kids.append(kid) + i += 2 + return i + + def toRaw(self): + self.wValueLength = len(self.kids) * 2 + self.wType = 0 + raw_name = getRaw(self.name) + sublen = 6 + len(raw_name) + 2 + pad = b'' + if sublen % 4: + pad = b'\000\000' + self.sublen = sublen + len(pad) + self.wValueLength + tmp = b''.join([struct.pack('h', kid) for kid in self.kids]) + return struct.pack('hhh', self.sublen, self.wValueLength, self.wType) + raw_name + b'\000\000' + pad + tmp + + def __eq__(self, other): + return self.toRaw() == other + + def __str__(self, indent=''): + return "VarStruct('%s', %r)" % (self.name, self.kids) + + def __repr__(self): + return 'versioninfo.VarStruct(%r, %r)' % (self.name, self.kids) + + +def load_version_info_from_text_file(filename): + """ + Load the `VSVersionInfo` structure from its string-based (`VSVersionInfo.__str__`) serialization by reading the + text from the file and running it through `eval()`. + """ + + # Read and parse the version file. It may have a byte order marker or encoding cookie - respect it if it does. + import PyInstaller.utils.misc as miscutils + with open(filename, 'rb') as fp: + text = miscutils.decode(fp.read()) + + # Deserialize via eval() + try: + info = eval(text) + except Exception as e: + raise ValueError("Failed to deserialize VSVersionInfo from text-based representation!") from e + + # Sanity check + assert isinstance(info, VSVersionInfo), \ + f"Loaded incompatible structure type! Expected VSVersionInfo, got: {type(info)!r}" + + return info + + +def write_version_info_to_executable(exe_filename, info): + assert isinstance(info, VSVersionInfo) + + # Remember overlay + pe = pefile.PE(exe_filename, fast_load=True) + overlay_before = pe.get_overlay() + pe.close() + + hdst = win32api.BeginUpdateResource(exe_filename, 0) + win32api.UpdateResource(hdst, pefile.RESOURCE_TYPE['RT_VERSION'], 1, info.toRaw()) + win32api.EndUpdateResource(hdst, 0) + + if overlay_before: + # Check if the overlay is still present + pe = pefile.PE(exe_filename, fast_load=True) + overlay_after = pe.get_overlay() + pe.close() + + # If the update removed the overlay data, re-append it + if not overlay_after: + with open(exe_filename, 'ab') as exef: + exef.write(overlay_before) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/win32/winmanifest.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/win32/winmanifest.py new file mode 100755 index 000000000..9d75e4b2c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/win32/winmanifest.py @@ -0,0 +1,1083 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +# Development notes kept for documentation purposes. +# +# Currently not implemented in the Manifest class: +# * Validation (only very basic sanity checks are currently in place) +# * comClass, typelib, comInterfaceProxyStub and windowClass child elements of the file element +# * comInterfaceExternalProxyStub and windowClass child elements of the assembly element +# * Application Configuration File and Multilanguage User Interface (MUI) support when searching for assembly files +# +# Isolated Applications and Side-by-side Assemblies: +# http://msdn.microsoft.com/en-us/library/dd408052%28VS.85%29.aspx +# +# Changelog: +# 2009-12-17 fix: small glitch in toxml / toprettyxml methods (xml declaration wasn't replaced when a different +# encoding than UTF-8 was used) +# chg: catch xml.parsers.expat.ExpatError and re-raise as ManifestXMLParseError +# chg: support initialize option in parse method also +# +# 2009-12-13 fix: fixed os import +# fix: skip invalid / empty dependent assemblies +# +# 2009-08-21 fix: Corrected assembly searching sequence for localized assemblies +# fix: Allow assemblies with no dependent files +# +# 2009-07-31 chg: Find private assemblies even if unversioned +# add: Manifest.same_id method to check if two manifests have the same assemblyIdentity +# +# 2009-07-30 fix: Potential failure in File.calc_hash method if hash algorithm not supported +# add: Publisher configuration (policy) support when searching for assembly files +# fix: Private assemblies are now actually found if present (and no shared assembly exists) +# add: Python 2.3 compatibility (oldest version supported by pyinstaller) +# +# 2009-07-28 chg: Code cleanup, removed a bit of redundancy +# add: silent mode (set silent attribute on module) +# chg: Do not print messages in silent mode +# +# 2009-06-18 chg: Use glob instead of regular expression in Manifest.find_files +# +# 2009-05-04 fix: Don't fail if manifest has empty description +# fix: Manifests created by the toxml, toprettyxml, writexml or writeprettyxml methods are now correctly +# recognized by Windows, which expects the XML declaration to be ordered version-encoding-standalone +# (standalone being optional) +# add: 'encoding' keyword argument in toxml, toprettyxml, writexml and writeprettyxml methods +# chg: UpdateManifestResourcesFromXML and UpdateManifestResourcesFromXMLFile: set resource name depending on +# file type ie. exe or dll +# fix: typo in __main__: UpdateManifestResourcesFromDataFile +# should have been UpdateManifestResourcesFromXMLFile +# +# 2009-03-21 First version +""" +Create, parse and write MS Windows Manifest files. Find files which are part of an assembly, by searching shared and +private assemblies. Update or add manifest resources in Win32 PE files. + +Commandline usage: +winmanifest.py +Updates or adds manifest as resource in Win32 PE file . +""" + +import hashlib +import os +import sys +import xml +from glob import glob +from xml.dom import Node, minidom +from xml.dom.minidom import Document, Element + +from PyInstaller import compat +from PyInstaller import log as logging +from PyInstaller.utils.win32 import winresource + +logger = logging.getLogger(__name__) + +LANGUAGE_NEUTRAL_NT5 = "x-ww" +LANGUAGE_NEUTRAL_NT6 = "none" +RT_MANIFEST = 24 + +Document.aChild = Document.appendChild +Document.cE = Document.createElement +Document.cT = Document.createTextNode +Document.getEByTN = Document.getElementsByTagName +Element.aChild = Element.appendChild +Element.getA = Element.getAttribute +Element.getEByTN = Element.getElementsByTagName +Element.remA = Element.removeAttribute +Element.setA = Element.setAttribute + + +def getChildElementsByTagName(self, tagName): + """ + Return child elements of type tagName if found, else []. + """ + result = [] + for child in self.childNodes: + if isinstance(child, Element): + if child.tagName == tagName: + result.append(child) + return result + + +def getFirstChildElementByTagName(self, tagName): + """ + Return the first element of type tagName if found, else None. + """ + for child in self.childNodes: + if isinstance(child, Element): + if child.tagName == tagName: + return child + return None + + +Document.getCEByTN = getChildElementsByTagName +Document.getFCEByTN = getFirstChildElementByTagName +Element.getCEByTN = getChildElementsByTagName +Element.getFCEByTN = getFirstChildElementByTagName + + +class _Dummy: + pass + + +if winresource: + _File = winresource.File +else: + _File = _Dummy + + +class File(_File): + """ + A file referenced by an assembly inside a manifest. + """ + def __init__( + self, + filename="", + hashalg=None, + hash=None, + comClasses=None, + typelibs=None, + comInterfaceProxyStubs=None, + windowClasses=None + ): + if winresource: + winresource.File.__init__(self, filename) + else: + self.filename = filename + self.name = os.path.basename(filename) + if hashalg: + self.hashalg = hashalg.upper() + else: + self.hashalg = None + if os.path.isfile(filename) and hashalg and hashlib and hasattr(hashlib, hashalg.lower()): + self.calc_hash() + else: + self.hash = hash + self.comClasses = comClasses or [] # TODO: implement + self.typelibs = typelibs or [] # TODO: implement + self.comInterfaceProxyStubs = comInterfaceProxyStubs or [] # TODO: implement + self.windowClasses = windowClasses or [] # TODO: implement + + def calc_hash(self, hashalg=None): + """ + Calculate the hash of the file. + + Will be called automatically from the constructor if the file exists and hashalg is given (and supported), + but may also be called manually e.g. to update the hash if the file has changed. + """ + with open(self.filename, "rb") as fd: + buf = fd.read() + if hashalg: + self.hashalg = hashalg.upper() + self.hash = getattr(hashlib, self.hashalg.lower())(buf).hexdigest() + + def find(self, searchpath): + logger.info("Searching for file %s", self.name) + fn = os.path.join(searchpath, self.name) + if os.path.isfile(fn): + logger.info("Found file %s", fn) + return fn + else: + logger.warning("No such file %s", fn) + return None + + +class InvalidManifestError(Exception): + pass + + +class ManifestXMLParseError(InvalidManifestError): + pass + + +class Manifest: + # Manifests: + # http://msdn.microsoft.com/en-us/library/aa375365%28VS.85%29.aspx + """ + Manifest constructor. + + To build a basic manifest for your application: + mf = Manifest(type='win32', name='YourAppName', language='*', processorArchitecture='x86', version=[1, 0, 0, 0]) + + To write the XML to a manifest file: + mf.writexml("YourAppName.exe.manifest") + or + mf.writeprettyxml("YourAppName.exe.manifest") + """ + def __init__( + self, + manifestType="assembly", + manifestVersion=None, + noInheritable=False, + noInherit=False, + type_=None, + name=None, + language=None, + processorArchitecture=None, + version=None, + publicKeyToken=None, + description=None, + requestedExecutionLevel=None, + uiAccess=None, + dependentAssemblies=None, + files=None, + comInterfaceExternalProxyStubs=None + ): + self.filename = None + self.optional = None + self.manifestType = manifestType + self.manifestVersion = manifestVersion or [1, 0] + self.noInheritable = noInheritable + self.noInherit = noInherit + self.type = type_ + self.name = name + self.language = language + self.processorArchitecture = processorArchitecture + self.version = version + self.publicKeyToken = publicKeyToken + # publicKeyToken: a 16-character hexadecimal string that represents the last 8 bytes of the SHA-1 hash of the + # public key under which the assembly is signed. The public key used to sign the catalog must be 2048 bits or + # greater. Required for all shared side-by-side assemblies. + # http://msdn.microsoft.com/en-us/library/aa375692(VS.85).aspx + self.applyPublisherPolicy = None + self.description = None + self.requestedExecutionLevel = requestedExecutionLevel + self.uiAccess = uiAccess + self.dependentAssemblies = dependentAssemblies or [] + self.bindingRedirects = [] + self.files = files or [] + self.comInterfaceExternalProxyStubs = comInterfaceExternalProxyStubs or [] # TODO: implement + + def __eq__(self, other): + if isinstance(other, Manifest): + return self.toxml() == other.toxml() + if isinstance(other, str): + return self.toxml() == other + return False + + def __ne__(self, other): + return not self.__eq__(other) + + def __repr__(self): + return repr(self.toxml()) + + def add_dependent_assembly( + self, + manifestVersion=None, + noInheritable=False, + noInherit=False, + type_=None, + name=None, + language=None, + processorArchitecture=None, + version=None, + publicKeyToken=None, + description=None, + requestedExecutionLevel=None, + uiAccess=None, + dependentAssemblies=None, + files=None, + comInterfaceExternalProxyStubs=None + ): + """ + Shortcut for self.dependentAssemblies.append(Manifest(*args, **kwargs)) + """ + self.dependentAssemblies.append( + Manifest( + manifestVersion, + noInheritable, + noInherit, + type_, + name, + language, + processorArchitecture, + version, + publicKeyToken, + description, + requestedExecutionLevel, + uiAccess, + dependentAssemblies, + files, + comInterfaceExternalProxyStubs, + ) + ) + if self.filename: + # Enable search for private assembly by assigning bogus filename (only the directory has to be correct). + self.dependentAssemblies[-1].filename = ":".join((self.filename, name)) + + def add_file( + self, + name="", + hashalg="", + hash="", + comClasses=None, + typelibs=None, + comInterfaceProxyStubs=None, + windowClasses=None + ): + """ + Shortcut for manifest.files.append + """ + self.files.append(File(name, hashalg, hash, comClasses, typelibs, comInterfaceProxyStubs, windowClasses)) + + @classmethod + def get_winsxs_dir(cls): + return os.path.join(compat.getenv("SystemRoot"), "WinSxS") + + @classmethod + def get_manifest_dir(cls): + winsxs = cls.get_winsxs_dir() + if not os.path.isdir(winsxs): + logger.warning("No such dir %s", winsxs) + manifests = os.path.join(winsxs, "Manifests") + if not os.path.isdir(manifests): + logger.warning("No such dir %s", manifests) + return manifests + + @classmethod + def get_policy_dir(cls): + winsxs = os.path.join(compat.getenv("SystemRoot"), "WinSxS") + if sys.getwindowsversion() < (6,): + # Windows XP + pcfiles = os.path.join(winsxs, "Policies") + if not os.path.isdir(pcfiles): + logger.warning("No such dir %s", pcfiles) + else: + # Vista or later + pcfiles = cls.get_manifest_dir() + return pcfiles + + def get_policy_redirect(self, language=None, version=None): + # Publisher Configuration (aka policy) + # A publisher configuration file globally redirects applications and assemblies having a dependence on one + # version of a side-by-side assembly to use another version of the same assembly. This enables applications and + # assemblies to use the updated assembly without having to rebuild all of the affected applications. + # http://msdn.microsoft.com/en-us/library/aa375680%28VS.85%29.aspx + # + # Under Windows XP and 2003, policies are stored as + # .policy files inside + # %SystemRoot%\WinSxS\Policies\ + # Under Vista and later, policies are stored as + # .manifest files inside %SystemRoot%\winsxs\Manifests + redirected = False + pcfiles = self.get_policy_dir() + if version is None: + version = self.version + if language is None: + language = self.language + + if os.path.isdir(pcfiles): + logger.debug("Searching for publisher configuration %s ...", self.getpolicyid(True, language=language)) + if sys.getwindowsversion() < (6,): + # Windows XP + policies = os.path.join(pcfiles, self.getpolicyid(True, language=language) + ".policy") + else: + # Vista or later + policies = os.path.join(pcfiles, self.getpolicyid(True, language=language) + ".manifest") + for manifestpth in glob(policies): + if not os.path.isfile(manifestpth): + logger.warning("Not a file %s", manifestpth) + continue + logger.info("Found %s", manifestpth) + try: + policy = ManifestFromXMLFile(manifestpth) + except Exception: + logger.error("Could not parse file %s", manifestpth, exc_info=1) + else: + logger.debug("Checking publisher policy for binding redirects") + for assembly in policy.dependentAssemblies: + if not assembly.same_id(self, True) or assembly.optional: + continue + for redirect in assembly.bindingRedirects: + old = "-".join([".".join([str(i) for i in part]) for part in redirect[0]]) + new = ".".join([str(i) for i in redirect[1]]) + logger.debug("Found redirect for version(s) %s -> %s", old, new) + if redirect[0][0] <= version <= redirect[0][-1] and version != redirect[1]: + logger.debug("Applying redirect %s -> %s", ".".join([str(i) for i in version]), new) + version = redirect[1] + redirected = True + if not redirected: + logger.debug("Publisher configuration not used") + + return version + + def find_files(self, ignore_policies=True): + """ + Search shared and private assemblies and return a list of files. + + If any files are not found, return an empty list. + + IMPORTANT NOTE: On some Windows systems, the dependency listed in the manifest will not actually be present, + and finding its files will fail. This is because a newer version of the dependency is installed, + and the manifest's dependency is being redirected to a newer version. To properly bundle the newer version of + the assembly, you need to find the newer version by setting ignore_policies=False, and then either create a + .config file for each bundled assembly, or modify each bundled assembly to point to the newer version. + + This is important because Python 2.7's app manifest depends on version 21022 of the VC90 assembly, + but the Python 2.7.9 installer will install version 30729 of the assembly along with a policy file that + enacts the version redirect. + """ + + # Shared Assemblies: + # http://msdn.microsoft.com/en-us/library/aa375996%28VS.85%29.aspx + # + # Private Assemblies: + # http://msdn.microsoft.com/en-us/library/aa375674%28VS.85%29.aspx + # + # Assembly Searching Sequence: + # http://msdn.microsoft.com/en-us/library/aa374224%28VS.85%29.aspx + # + # NOTE: + # Multilanguage User Interface (MUI) support not yet implemented + + files = [] + + languages = [] + if self.language not in (None, "", "*", "neutral"): + languages.append(self.getlanguage()) + if "-" in self.language: + # language-culture syntax, e.g., en-us + # Add only the language part + languages.append(self.language.split("-")[0]) + if self.language not in ("en-us", "en"): + languages.append("en-us") + if self.language != "en": + languages.append("en") + languages.append(self.getlanguage("*")) + + manifests = self.get_manifest_dir() + winsxs = self.get_winsxs_dir() + + for language in languages: + version = self.version + + # Search for publisher configuration + if not ignore_policies and version: + version = self.get_policy_redirect(language, version) + + # Search for assemblies according to assembly searching sequence + paths = [] + if os.path.isdir(manifests): + # Add winsxs search paths + # Search for manifests in Windows\WinSxS\Manifests + paths.extend( + glob(os.path.join(manifests, + self.getid(language=language, version=version) + "_*.manifest")) + ) + if self.filename: + # Add private assembly search paths + # Search for manifests inside assembly folders that are in the same folder as the depending manifest. + dirnm = os.path.dirname(self.filename) + if language in (LANGUAGE_NEUTRAL_NT5, LANGUAGE_NEUTRAL_NT6): + for ext in (".dll", ".manifest"): + paths.extend(glob(os.path.join(dirnm, self.name + ext))) + paths.extend(glob(os.path.join(dirnm, self.name, self.name + ext))) + else: + for ext in (".dll", ".manifest"): + paths.extend(glob(os.path.join(dirnm, language, self.name + ext))) + for ext in (".dll", ".manifest"): + paths.extend(glob(os.path.join(dirnm, language, self.name, self.name + ext))) + logger.info("Searching for assembly %s ...", self.getid(language=language, version=version)) + for manifestpth in paths: + if not os.path.isfile(manifestpth): + logger.warning("Not a file %s", manifestpth) + continue + assemblynm = os.path.basename(os.path.splitext(manifestpth)[0]) + try: + if manifestpth.endswith(".dll"): + logger.info("Found manifest in %s", manifestpth) + manifest = ManifestFromResFile(manifestpth, [1]) + else: + logger.info("Found manifest %s", manifestpth) + manifest = ManifestFromXMLFile(manifestpth) + except Exception: + logger.error("Could not parse manifest %s", manifestpth, exc_info=1) + else: + if manifestpth.startswith(winsxs): + # Manifest is in Windows\WinSxS\Manifests, so assembly dir is in Windows\WinSxS + assemblydir = os.path.join(winsxs, assemblynm) + if not os.path.isdir(assemblydir): + logger.warning("No such dir %s", assemblydir) + logger.warning("Assembly incomplete") + return [] + else: + # Manifest is inside assembly dir. + assemblydir = os.path.dirname(manifestpth) + files.append(manifestpth) + for file_ in self.files or manifest.files: + fn = file_.find(assemblydir) + if fn: + files.append(fn) + else: + # If any of our files does not exist, the assembly is incomplete. + logger.warning("Assembly incomplete") + return [] + return files + + logger.warning("Assembly not found") + return [] + + def getid(self, language=None, version=None): + """ + Return an identification string which uniquely names a manifest. + + This string is a combination of the manifest's processorArchitecture, name, publicKeyToken, version and + language. + + Arguments: + version (tuple or list of integers) - If version is given, use it instead of the manifest's version. + """ + if not self.name: + logger.warning("Assembly metadata incomplete") + return "" + id = [] + if self.processorArchitecture: + id.append(self.processorArchitecture) + id.append(self.name) + if self.publicKeyToken: + id.append(self.publicKeyToken) + if version or self.version: + id.append(".".join([str(i) for i in version or self.version])) + if not language: + language = self.getlanguage() + if language: + id.append(language) + return "_".join(id) + + def getlanguage(self, language=None, windowsversion=None): + """ + Get and return the manifest's language as string. + + Can be either language-culture e.g. 'en-us' or a string indicating language neutrality, e.g. 'x-ww' on + Windows XP or 'none' on Vista and later. + """ + if not language: + language = self.language + if language in (None, "", "*", "neutral"): + return (LANGUAGE_NEUTRAL_NT5, LANGUAGE_NEUTRAL_NT6)[(windowsversion or sys.getwindowsversion()) >= (6,)] + return language + + def getpolicyid(self, fuzzy=True, language=None, windowsversion=None): + """ + Return an identification string which can be used to find a policy. + + This string is a combination of the manifest's processorArchitecture, major and minor version, name, + publicKeyToken and language. + + Arguments: + fuzzy (boolean): + If False, insert the full version in the id string. Default is True (omit). + windowsversion (tuple or list of integers or None): + If not specified (or None), default to sys.getwindowsversion(). + """ + if not self.name: + logger.warning("Assembly metadata incomplete") + return "" + id = [] + if self.processorArchitecture: + id.append(self.processorArchitecture) + name = [] + name.append("policy") + if self.version: + name.append(str(self.version[0])) + name.append(str(self.version[1])) + name.append(self.name) + id.append(".".join(name)) + if self.publicKeyToken: + id.append(self.publicKeyToken) + if self.version and (windowsversion or sys.getwindowsversion()) >= (6,): + # Vista and later + if fuzzy: + id.append("*") + else: + id.append(".".join([str(i) for i in self.version])) + if not language: + language = self.getlanguage(windowsversion=windowsversion) + if language: + id.append(language) + id.append("*") + id = "_".join(id) + if self.version and (windowsversion or sys.getwindowsversion()) < (6,): + # Windows XP + if fuzzy: + id = os.path.join(id, "*") + else: + id = os.path.join(id, ".".join([str(i) for i in self.version])) + return id + + def load_dom(self, domtree, initialize=True): + """ + Load manifest from DOM tree. + + If initialize is True (default), reset existing attributes first. + """ + if domtree.nodeType == Node.DOCUMENT_NODE: + rootElement = domtree.documentElement + elif domtree.nodeType == Node.ELEMENT_NODE: + rootElement = domtree + else: + raise InvalidManifestError( + "Invalid root element node type %s - has to be one of (DOCUMENT_NODE, ELEMENT_NODE)" % + rootElement.nodeType + ) + allowed_names = ("assembly", "assemblyBinding", "configuration", "dependentAssembly") + if rootElement.tagName not in allowed_names: + raise InvalidManifestError( + "Invalid root element <%s> - has to be one of <%s>" % (rootElement.tagName, ">, <".join(allowed_names)) + ) + # logger.info("loading manifest metadata from element <%s>", rootElement.tagName) + if rootElement.tagName == "configuration": + for windows in rootElement.getCEByTN("windows"): + for assemblyBinding in windows.getCEByTN("assemblyBinding"): + self.load_dom(assemblyBinding, initialize) + else: + if initialize: + self.__init__() + self.manifestType = rootElement.tagName + self.manifestVersion = [int(i) for i in (rootElement.getA("manifestVersion") or "1.0").split(".")] + self.noInheritable = bool(rootElement.getFCEByTN("noInheritable")) + self.noInherit = bool(rootElement.getFCEByTN("noInherit")) + for assemblyIdentity in rootElement.getCEByTN("assemblyIdentity"): + self.type = assemblyIdentity.getA("type") or None + self.name = assemblyIdentity.getA("name") or None + self.language = assemblyIdentity.getA("language") or None + self.processorArchitecture = assemblyIdentity.getA("processorArchitecture") or None + version = assemblyIdentity.getA("version") + if version: + self.version = tuple(int(i) for i in version.split(".")) + self.publicKeyToken = assemblyIdentity.getA("publicKeyToken") or None + for publisherPolicy in rootElement.getCEByTN("publisherPolicy"): + self.applyPublisherPolicy = (publisherPolicy.getA("apply") or "").lower() == "yes" + for description in rootElement.getCEByTN("description"): + if description.firstChild: + self.description = description.firstChild.wholeText + for trustInfo in rootElement.getCEByTN("trustInfo"): + for security in trustInfo.getCEByTN("security"): + for reqPriv in security.getCEByTN("requestedPrivileges"): + for reqExeLev in reqPriv.getCEByTN("requestedExecutionLevel"): + self.requestedExecutionLevel = reqExeLev.getA("level") + self.uiAccess = (reqExeLev.getA("uiAccess") or "").lower() == "true" + if rootElement.tagName == "assemblyBinding": + dependencies = [rootElement] + else: + dependencies = rootElement.getCEByTN("dependency") + for dependency in dependencies: + for dependentAssembly in dependency.getCEByTN("dependentAssembly"): + manifest = ManifestFromDOM(dependentAssembly) + if not manifest.name: + # invalid, skip + continue + manifest.optional = (dependency.getA("optional") or "").lower() == "yes" + self.dependentAssemblies.append(manifest) + if self.filename: + # Enable search for private assembly by assigning bogus filename + # (only the directory has to be correct). + self.dependentAssemblies[-1].filename = ":".join((self.filename, manifest.name)) + for bindingRedirect in rootElement.getCEByTN("bindingRedirect"): + oldVersion = tuple( + tuple(int(i) for i in part.split(".")) for part in bindingRedirect.getA("oldVersion").split("-") + ) + newVersion = tuple(int(i) for i in bindingRedirect.getA("newVersion").split(".")) + self.bindingRedirects.append((oldVersion, newVersion)) + for file_ in rootElement.getCEByTN("file"): + self.add_file(name=file_.getA("name"), hashalg=file_.getA("hashalg"), hash=file_.getA("hash")) + + def parse(self, filename_or_file, initialize=True): + """ + Load manifest from file or file object. + """ + if isinstance(filename_or_file, str): + filename = filename_or_file + else: + filename = filename_or_file.name + try: + domtree = minidom.parse(filename_or_file) + except xml.parsers.expat.ExpatError as e: + args = ['\n File "%r"\n ' % filename, str(e.args[0])] + raise ManifestXMLParseError(" ".join(args)) from e + if initialize: + self.__init__() + self.filename = filename + self.load_dom(domtree, False) + + def parse_string(self, xmlstr, initialize=True): + """ + Load manifest from XML string. + """ + try: + domtree = minidom.parseString(xmlstr) + except xml.parsers.expat.ExpatError as e: + raise ManifestXMLParseError(e) from e + self.load_dom(domtree, initialize) + + def same_id(self, manifest, skip_version_check=False): + """ + Return a bool indicating if another manifest has the same identitiy. + + This is done by comparing language, name, processorArchitecture, publicKeyToken, type and version. + """ + if skip_version_check: + version_check = True + else: + version_check = self.version == manifest.version + return ( + self.language == manifest.language and self.name == manifest.name + and self.processorArchitecture == manifest.processorArchitecture + and self.publicKeyToken == manifest.publicKeyToken and self.type == manifest.type and version_check + ) + + def todom(self): + """ + Return the manifest as DOM tree. + """ + doc = Document() + docE = doc.cE(self.manifestType) + if self.manifestType == "assemblyBinding": + cfg = doc.cE("configuration") + win = doc.cE("windows") + win.aChild(docE) + cfg.aChild(win) + doc.aChild(cfg) + else: + doc.aChild(docE) + if self.manifestType != "dependentAssembly": + docE.setA("xmlns", "urn:schemas-microsoft-com:asm.v1") + if self.manifestType != "assemblyBinding": + docE.setA("manifestVersion", ".".join([str(i) for i in self.manifestVersion])) + if self.noInheritable: + docE.aChild(doc.cE("noInheritable")) + if self.noInherit: + docE.aChild(doc.cE("noInherit")) + aId = doc.cE("assemblyIdentity") + if self.type: + aId.setAttribute("type", self.type) + if self.name: + aId.setAttribute("name", self.name) + if self.language: + aId.setAttribute("language", self.language) + if self.processorArchitecture: + aId.setAttribute("processorArchitecture", self.processorArchitecture) + if self.version: + aId.setAttribute("version", ".".join([str(i) for i in self.version])) + if self.publicKeyToken: + aId.setAttribute("publicKeyToken", self.publicKeyToken) + if aId.hasAttributes(): + docE.aChild(aId) + else: + aId.unlink() + if self.applyPublisherPolicy is not None: + ppE = doc.cE("publisherPolicy") + if self.applyPublisherPolicy: + ppE.setA("apply", "yes") + else: + ppE.setA("apply", "no") + docE.aChild(ppE) + if self.description: + descE = doc.cE("description") + descE.aChild(doc.cT(self.description)) + docE.aChild(descE) + if self.requestedExecutionLevel in ("asInvoker", "highestAvailable", "requireAdministrator"): + tE = doc.cE("trustInfo") + tE.setA("xmlns", "urn:schemas-microsoft-com:asm.v3") + sE = doc.cE("security") + rpE = doc.cE("requestedPrivileges") + relE = doc.cE("requestedExecutionLevel") + relE.setA("level", self.requestedExecutionLevel) + if self.uiAccess: + relE.setA("uiAccess", "true") + else: + relE.setA("uiAccess", "false") + rpE.aChild(relE) + sE.aChild(rpE) + tE.aChild(sE) + docE.aChild(tE) + if self.dependentAssemblies: + for assembly in self.dependentAssemblies: + if self.manifestType != "assemblyBinding": + dE = doc.cE("dependency") + if assembly.optional: + dE.setAttribute("optional", "yes") + daE = doc.cE("dependentAssembly") + adom = assembly.todom() + for child in adom.documentElement.childNodes: + daE.aChild(child.cloneNode(False)) + adom.unlink() + if self.manifestType != "assemblyBinding": + dE.aChild(daE) + docE.aChild(dE) + else: + docE.aChild(daE) + if self.bindingRedirects: + for bindingRedirect in self.bindingRedirects: + brE = doc.cE("bindingRedirect") + brE.setAttribute( + "oldVersion", "-".join([".".join([str(i) for i in part]) for part in bindingRedirect[0]]) + ) + brE.setAttribute("newVersion", ".".join([str(i) for i in bindingRedirect[1]])) + docE.aChild(brE) + if self.files: + for file_ in self.files: + fE = doc.cE("file") + for attr in ("name", "hashalg", "hash"): + val = getattr(file_, attr) + if val: + fE.setA(attr, val) + docE.aChild(fE) + + # Add compatibility section: http://stackoverflow.com/a/10158920 + if self.manifestType == "assembly": + cE = doc.cE("compatibility") + cE.setAttribute("xmlns", "urn:schemas-microsoft-com:compatibility.v1") + caE = doc.cE("application") + supportedOS_guids = { + "Vista": "{e2011457-1546-43c5-a5fe-008deee3d3f0}", + "7": "{35138b9a-5d96-4fbd-8e2d-a2440225f93a}", + "8": "{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}", + "8.1": "{1f676c76-80e1-4239-95bb-83d0f6d0da78}", + "10": "{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" + } + for guid in supportedOS_guids.values(): + sosE = doc.cE("supportedOS") + sosE.setAttribute("Id", guid) + caE.aChild(sosE) + cE.aChild(caE) + docE.aChild(cE) + + # Add application.windowsSettings section to enable longPathAware + # option (issue #5423). + if self.manifestType == "assembly": + aE = doc.cE("application") + aE.setAttribute("xmlns", "urn:schemas-microsoft-com:asm.v3") + wsE = doc.cE("windowsSettings") + lpaE = doc.cE("longPathAware") + lpaE.setAttribute("xmlns", "http://schemas.microsoft.com/SMI/2016/WindowsSettings") + lpaT = doc.cT("true") + lpaE.aChild(lpaT) + wsE.aChild(lpaE) + aE.aChild(wsE) + docE.aChild(aE) + + return doc + + def toprettyxml(self, indent=" ", newl=os.linesep, encoding="UTF-8"): + """ + Return the manifest as pretty-printed XML. + """ + domtree = self.todom() + # WARNING: The XML declaration has to follow the order version-encoding-standalone (standalone being optional), + # otherwise if it is embedded in an exe the exe will fail to launch! ('application configuration incorrect') + xmlstr = domtree.toprettyxml(indent, newl, encoding) + xmlstr = xmlstr.decode(encoding).strip(os.linesep).replace( + '' % encoding, + '' % encoding + ) + domtree.unlink() + return xmlstr + + def toxml(self, encoding="UTF-8"): + """ + Return the manifest as XML. + """ + domtree = self.todom() + # WARNING: The XML declaration has to follow the order version-encoding-standalone (standalone being optional), + # otherwise if it is embedded in an exe the exe will fail to launch! ('application configuration incorrect') + xmlstr = domtree.toxml(encoding).decode().replace( + '' % encoding, + '' % encoding + ) + domtree.unlink() + return xmlstr + + def update_resources(self, dstpath, names=None, languages=None): + """ + Update or add manifest resource in dll/exe file dstpath. + """ + UpdateManifestResourcesFromXML(dstpath, self.toprettyxml().encode("UTF-8"), names, languages) + + def writeprettyxml(self, filename_or_file=None, indent=" ", newl=os.linesep, encoding="UTF-8"): + """ + Write the manifest as XML to a file or file object. + """ + if not filename_or_file: + filename_or_file = self.filename + if isinstance(filename_or_file, str): + filename_or_file = open(filename_or_file, "wb") + xmlstr = self.toprettyxml(indent, newl, encoding) + with filename_or_file: + filename_or_file.write(xmlstr.encode()) + + def writexml(self, filename_or_file=None, indent=" ", newl=os.linesep, encoding="UTF-8"): + """ + Write the manifest as XML to a file or file object. + """ + if not filename_or_file: + filename_or_file = self.filename + if isinstance(filename_or_file, str): + filename_or_file = open(filename_or_file, "wb") + xmlstr = self.toxml(encoding) + with filename_or_file: + filename_or_file.write(xmlstr.encode()) + + +def ManifestFromResFile(filename, names=None, languages=None): + """ + Create and return manifest instance from resource in dll/exe file. + """ + res = GetManifestResources(filename, names, languages) + pth = [] + if res and res[RT_MANIFEST]: + while isinstance(res, dict) and res.keys(): + key, res = next(iter(res.items())) + pth.append(str(key)) + if isinstance(res, dict): + raise InvalidManifestError("No matching manifest resource found in '%s'" % filename) + manifest = Manifest() + manifest.filename = ":".join([filename] + pth) + manifest.parse_string(res, False) + return manifest + + +def ManifestFromDOM(domtree): + """ + Create and return manifest instance from DOM tree. + """ + manifest = Manifest() + manifest.load_dom(domtree) + return manifest + + +def ManifestFromXML(xmlstr): + """ + Create and return manifest instance from XML. + """ + manifest = Manifest() + manifest.parse_string(xmlstr) + return manifest + + +def ManifestFromXMLFile(filename_or_file): + """ + Create and return manifest instance from file. + """ + manifest = Manifest() + manifest.parse(filename_or_file) + return manifest + + +def GetManifestResources(filename, names=None, languages=None): + """ + Get manifest resources from file. + """ + return winresource.GetResources(filename, [RT_MANIFEST], names, languages) + + +def UpdateManifestResourcesFromXML(dstpath, xmlstr, names=None, languages=None): + """ + Update or add manifest XML as resource in dstpath. + """ + logger.info("Updating manifest in %s", dstpath) + if dstpath.lower().endswith(".exe"): + name = 1 + else: + name = 2 + winresource.UpdateResources(dstpath, xmlstr, RT_MANIFEST, names or [name], languages or [0, "*"]) + + +def UpdateManifestResourcesFromXMLFile(dstpath, srcpath, names=None, languages=None): + """ + Update or add manifest XML from srcpath as resource in dstpath. + """ + logger.info("Updating manifest from %s in %s", srcpath, dstpath) + if dstpath.lower().endswith(".exe"): + name = 1 + else: + name = 2 + winresource.UpdateResourcesFromDataFile(dstpath, srcpath, RT_MANIFEST, names or [name], languages or [0, "*"]) + + +def create_manifest(filename, manifest, console, uac_admin=False, uac_uiaccess=False): + """ + Create assembly manifest. + """ + if not manifest: + manifest = ManifestFromXMLFile(filename) + # /path/NAME.exe.manifest - split extension twice to get NAME. + name = os.path.basename(filename) + manifest.name = os.path.splitext(os.path.splitext(name)[0])[0] + elif isinstance(manifest, str) and "<" in manifest: + # Assume XML string + manifest = ManifestFromXML(manifest) + elif not isinstance(manifest, Manifest): + # Assume filename + manifest = ManifestFromXMLFile(manifest) + dep_names = set([dep.name for dep in manifest.dependentAssemblies]) + if manifest.filename != filename: + # Update dependent assemblies. + depmanifest = ManifestFromXMLFile(filename) + for assembly in depmanifest.dependentAssemblies: + if assembly.name not in dep_names: + manifest.dependentAssemblies.append(assembly) + dep_names.add(assembly.name) + if "Microsoft.Windows.Common-Controls" not in dep_names: + # Add Microsoft.Windows.Common-Controls to dependent assemblies. + manifest.dependentAssemblies.append( + Manifest( + manifestType='dependentAssembly', + type_="win32", + name="Microsoft.Windows.Common-Controls", + language="*", + processorArchitecture=processor_architecture(), + version=(6, 0, 0, 0), + publicKeyToken="6595b64144ccf1df", + ) + ) + if uac_admin: + manifest.requestedExecutionLevel = 'requireAdministrator' + else: + manifest.requestedExecutionLevel = 'asInvoker' + if uac_uiaccess: + manifest.uiAccess = True + + # Only write a new manifest if it is different from the old. + need_new = not os.path.exists(filename) + if not need_new: + old_xml = ManifestFromXMLFile(filename).toprettyxml().replace('\r', '') + new_xml = manifest.toprettyxml().replace('\r', '') + + # This only works if PYTHONHASHSEED is set in environment. + need_new = (old_xml != new_xml) + if need_new: + manifest.writeprettyxml(filename) + + return manifest + + +def processor_architecture(): + """ + Detect processor architecture for assembly manifest. + + According to: + http://msdn.microsoft.com/en-us/library/windows/desktop/aa374219(v=vs.85).aspx + item processorArchitecture in assembly manifest is + + 'x86' - 32bit Windows + 'amd64' - 64bit Windows + """ + if compat.architecture == '32bit': + return 'x86' + else: + return 'amd64' + + +if __name__ == "__main__": + dstpath = sys.argv[1] + srcpath = sys.argv[2] + UpdateManifestResourcesFromXMLFile(dstpath, srcpath) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/win32/winresource.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/win32/winresource.py new file mode 100755 index 000000000..133354e6c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/win32/winresource.py @@ -0,0 +1,245 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Read and write resources from/to Win32 PE files. + +Commandline usage: +winresource.py +Updates or adds resources from file in file . +""" + +import PyInstaller.log as logging +from PyInstaller.compat import pywintypes, win32api + +logger = logging.getLogger(__name__) + +LOAD_LIBRARY_AS_DATAFILE = 2 +ERROR_BAD_EXE_FORMAT = 193 +ERROR_RESOURCE_DATA_NOT_FOUND = 1812 +ERROR_RESOURCE_TYPE_NOT_FOUND = 1813 +ERROR_RESOURCE_NAME_NOT_FOUND = 1814 +ERROR_RESOURCE_LANG_NOT_FOUND = 1815 + + +class File: + """ + Win32 PE file class. + """ + def __init__(self, filename): + self.filename = filename + + def get_resources(self, types=None, names=None, languages=None): + """ + Get resources. + + types = a list of resource types to search for (None = all) + names = a list of resource names to search for (None = all) + languages = a list of resource languages to search for (None = all) + Return a dict of the form {type_: {name: {language: data}}}, which might also be empty if no matching resources + were found. + """ + return GetResources(self.filename, types, names, languages) + + def update_resources(self, data, type_, names=None, languages=None): + """ + Update or add resource data. + + type_ = resource type to update + names = a list of resource names to update (None = all) + languages = a list of resource languages to update (None = all) + """ + UpdateResources(self.filename, data, type_, names, languages) + + def update_resources_from_datafile(self, srcpath, type_, names=None, languages=None): + """ + Update or add resource data from file srcpath. + + type_ = resource type to update + names = a list of resource names to update (None = all) + languages = a list of resource languages to update (None = all) + """ + UpdateResourcesFromDataFile(self.filename, srcpath, type_, names, languages) + + def update_resources_from_dict(self, res, types=None, names=None, languages=None): + """ + Update or add resources from resource dict. + + types = a list of resource types to update (None = all) + names = a list of resource names to update (None = all) + languages = a list of resource languages to update (None = all) + """ + UpdateResourcesFromDict(self.filename, res, types, names, languages) + + def update_resources_from_resfile(self, srcpath, types=None, names=None, languages=None): + """ + Update or add resources from dll/exe file srcpath. + + types = a list of resource types to update (None = all) + names = a list of resource names to update (None = all) + languages = a list of resource languages to update (None = all) + """ + UpdateResourcesFromResFile(self.filename, srcpath, types, names, languages) + + +def _GetResources(hsrc, types=None, names=None, languages=None): + """ + Get resources from hsrc. + + types = a list of resource types to search for (None = all) + names = a list of resource names to search for (None = all) + languages = a list of resource languages to search for (None = all) + Return a dict of the form {type_: {name: {language: data}}}, which might also be empty if no matching resources + were found. + """ + if types: + types = set(types) + if names: + names = set(names) + if languages: + languages = set(languages) + res = {} + try: + # logger.debug("Enumerating resource types") + enum_types = win32api.EnumResourceTypes(hsrc) + if types and "*" not in types: + enum_types = filter(lambda type_: type_ in types, enum_types) + for type_ in enum_types: + # logger.debug("Enumerating resources of type %s", type_) + enum_names = win32api.EnumResourceNames(hsrc, type_) + if names and "*" not in names: + enum_names = filter(lambda name: name in names, enum_names) + for name in enum_names: + # logger.debug("Enumerating resources of type %s name %s", type_, name) + enum_languages = win32api.EnumResourceLanguages(hsrc, type_, name) + if languages and "*" not in languages: + enum_languages = filter(lambda language: language in languages, enum_languages) + for language in enum_languages: + data = win32api.LoadResource(hsrc, type_, name, language) + if type_ not in res: + res[type_] = {} + if name not in res[type_]: + res[type_][name] = {} + res[type_][name][language] = data + except pywintypes.error as exception: + if exception.args[0] in ( + ERROR_RESOURCE_DATA_NOT_FOUND, + ERROR_RESOURCE_TYPE_NOT_FOUND, + ERROR_RESOURCE_NAME_NOT_FOUND, + ERROR_RESOURCE_LANG_NOT_FOUND, + ): + # logger.info('%s: %s', exception.args[1:3]) + pass + else: + raise exception + return res + + +def GetResources(filename, types=None, names=None, languages=None): + """ + Get resources from dll/exe file. + + types = a list of resource types to search for (None = all) + names = a list of resource names to search for (None = all) + languages = a list of resource languages to search for (None = all) + Return a dict of the form {type_: {name: {language: data}}}, which might also be empty if no matching resources + were found. + """ + hsrc = win32api.LoadLibraryEx(filename, 0, LOAD_LIBRARY_AS_DATAFILE) + res = _GetResources(hsrc, types, names, languages) + win32api.FreeLibrary(hsrc) + return res + + +def UpdateResources(dstpath, data, type_, names=None, languages=None): + """ + Update or add resource data in dll/exe file dstpath. + + type_ = resource type to update + names = a list of resource names to update (None = all) + languages = a list of resource languages to update (None = all) + """ + # Look for existing resources. + res = GetResources(dstpath, [type_], names, languages) + # add type_, names and languages not already present in existing resources + if type_ not in res and type_ != "*": + res[type_] = {} + if names: + for name in names: + if name not in res[type_] and name != "*": + res[type_][name] = [] + if languages: + for language in languages: + if language not in res[type_][name] and language != "*": + res[type_][name].append(language) + # add resource to destination, overwriting existing resources + hdst = win32api.BeginUpdateResource(dstpath, 0) + for type_ in res: + for name in res[type_]: + for language in res[type_][name]: + logger.info("Updating resource type %s name %s language %s", type_, name, language) + win32api.UpdateResource(hdst, type_, name, data, language) + win32api.EndUpdateResource(hdst, 0) + + +def UpdateResourcesFromDataFile(dstpath, srcpath, type_, names=None, languages=None): + """ + Update or add resource data from file srcpath in dll/exe file dstpath. + + type_ = resource type to update + names = a list of resource names to update (None = all) + languages = a list of resource languages to update (None = all) + """ + with open(srcpath, "rb") as src: + data = src.read() + UpdateResources(dstpath, data, type_, names, languages) + + +def UpdateResourcesFromDict(dstpath, res, types=None, names=None, languages=None): + """ + Update or add resources from resource dict in dll/exe file dstpath. + + types = a list of resource types to update (None = all) + names = a list of resource names to update (None = all) + languages = a list of resource languages to update (None = all) + """ + if types: + types = set(types) + if names: + names = set(names) + if languages: + languages = set(languages) + for type_ in res: + if not types or type_ in types: + for name in res[type_]: + if not names or name in names: + for language in res[type_][name]: + if not languages or language in languages: + UpdateResources(dstpath, res[type_][name][language], type_, [name], [language]) + + +def UpdateResourcesFromResFile(dstpath, srcpath, types=None, names=None, languages=None): + """ + Update or add resources from dll/exe file srcpath in dll/exe file dstpath. + + types = a list of resource types to update (None = all) + names = a list of resource names to update (None = all) + languages = a list of resource languages to update (None = all) + """ + res = GetResources(srcpath, types, names, languages) + UpdateResourcesFromDict(dstpath, res) + + +def RemoveAllResources(filename): + """ + Remove all resources from the dll/exe file. + """ + hsrc = win32api.BeginUpdateResource(filename, True) # bDeleteExistingResources=True + win32api.EndUpdateResource(hsrc, False) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/win32/winutils.py b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/win32/winutils.py new file mode 100755 index 000000000..1fe01120b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/PyInstaller/utils/win32/winutils.py @@ -0,0 +1,358 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Utilities for Windows platform. +""" + +import os +import sys + +import PyInstaller.log as logging +from PyInstaller import compat + +logger = logging.getLogger(__name__) + + +def get_windows_dir(): + """ + Return the Windows directory, e.g., C:\\Windows. + """ + # Imported here to avoid circular import. + from PyInstaller import compat + windir = compat.win32api.GetWindowsDirectory() + if not windir: + raise SystemExit("Error: Cannot determine Windows directory!") + return windir + + +def get_system_path(): + """ + Return the required Windows system paths. + """ + # Imported here to avoid circular import. + from PyInstaller import compat + _bpath = [] + sys_dir = compat.win32api.GetSystemDirectory() + # Ensure C:\Windows\system32 and C:\Windows directories are always present in PATH variable. + # C:\Windows\system32 is valid even for 64-bit Windows. Access do DLLs are transparently redirected to + # C:\Windows\syswow64 for 64bit applactions. + # See http://msdn.microsoft.com/en-us/library/aa384187(v=vs.85).aspx + _bpath = [sys_dir, get_windows_dir()] + return _bpath + + +def extend_system_path(paths): + """ + Add new paths at the beginning of environment variable PATH. + + Some hooks might extend PATH where PyInstaller should look for dlls. + """ + # imported here to avoid circular import + from PyInstaller import compat + old_path = compat.getenv('PATH', '') + paths.append(old_path) + new_path = os.pathsep.join(paths) + compat.setenv('PATH', new_path) + + +def import_pywin32_module(module_name): + """ + Import and return the PyWin32 module with the passed name. + + When imported, the `pywintypes` and `pythoncom` modules both internally import dynamic libraries + (e.g., `pywintypes.py` imports `pywintypes34.dll` under Python 3.4). The Anaconda Python distribution for Windows + installs these libraries to non-standard directories, resulting in + `"ImportError: No system module 'pywintypes' (pywintypes34.dll)"` + exceptions. This function catches these exceptions, searches for these libraries, adds their directories to + `sys.path`, and retries. + + Parameters + ---------- + module_name : str + Fully-qualified name of this module. + + Returns + ---------- + types.ModuleType + The desired module. + """ + module = None + + try: + module = __import__(module_name, globals={}, locals={}, fromlist=['']) + except ImportError as exc: + if str(exc).startswith('No system module'): + # True if "sys.frozen" is currently set. + is_sys_frozen = hasattr(sys, 'frozen') + + # Current value of "sys.frozen" if any. + sys_frozen = getattr(sys, 'frozen', None) + + # Force PyWin32 to search "sys.path" for DLLs. By default, PyWin32 only searches "site-packages\win32\lib", + # "sys.prefix", and Windows system directories (e.g., "C:\Windows\System32"). This is an ugly hack, but + # there is no other way. + sys.frozen = '|_|GLYH@CK' + + # If isolated to a venv, the preferred site.getsitepackages() function is unreliable. Fall back to searching + # "sys.path" instead. + if compat.is_venv: + sys_paths = sys.path + else: + sys_paths = compat.getsitepackages() + + for sys_path in sys_paths: + # Absolute path of the directory containing PyWin32 DLLs. + pywin32_dll_dir = os.path.join(sys_path, 'pywin32_system32') + if os.path.isdir(pywin32_dll_dir): + sys.path.append(pywin32_dll_dir) + try: + module = __import__(name=module_name, globals={}, locals={}, fromlist=['']) + break + except ImportError: + pass + + # If "sys.frozen" was previously set, restore its prior value. + if is_sys_frozen: + sys.frozen = sys_frozen + # Else, undo this hack entirely. + else: + del sys.frozen + + # If this module remains unimportable, PyWin32 is not installed. Fail. + if module is None: + raise + + return module + + +def convert_dll_name_to_str(dll_name): + """ + Convert dll names from 'bytes' to 'str'. + + Latest pefile returns type 'bytes'. + :param dll_name: + :return: + """ + # Imported here to avoid circular import. + if isinstance(dll_name, bytes): + return str(dll_name, encoding='UTF-8') + else: + return dll_name + + +def set_exe_build_timestamp(exe_path, timestamp): + """ + Modifies the executable's build timestamp by updating values in the corresponding PE headers. + """ + import pefile + + with pefile.PE(exe_path, fast_load=True) as pe: + # Manually perform a full load. We need it to load all headers, but specifying it in the constructor triggers + # byte statistics gathering that takes forever with large files. So we try to go around that... + pe.full_load() + + # Set build timestamp. + # See: https://0xc0decafe.com/malware-analyst-guide-to-pe-timestamps + timestamp = int(timestamp) + # Set timestamp field in FILE_HEADER + pe.FILE_HEADER.TimeDateStamp = timestamp + # MSVC-compiled executables contain (at least?) one DIRECTORY_ENTRY_DEBUG entry that also contains timestamp + # with same value as set in FILE_HEADER. So modify that as well, as long as it is set. + debug_entries = getattr(pe, 'DIRECTORY_ENTRY_DEBUG', []) + for debug_entry in debug_entries: + if debug_entry.struct.TimeDateStamp: + debug_entry.struct.TimeDateStamp = timestamp + + # Generate updated EXE data + data = pe.write() + + # Rewrite the exe + with open(exe_path, 'wb') as fp: + fp.write(data) + + +def update_exe_pe_checksum(exe_path): + """ + Compute the executable's PE checksum, and write it to PE headers. + + This optional checksum is supposed to protect the executable against corruption but some anti-viral software have + taken to flagging anything without it set correctly as malware. See issue #5579. + """ + import pefile + + # Compute checksum using our equivalent of the MapFileAndCheckSumW - for large files, it is significantly faster + # than pure-pyton pefile.PE.generate_checksum(). However, it requires the file to be on disk (i.e., cannot operate + # on a memory buffer). + try: + checksum = compute_exe_pe_checksum(exe_path) + except Exception as e: + raise RuntimeError("Failed to compute PE checksum!") from e + + # Update the checksum + with pefile.PE(exe_path, fast_load=True) as pe: + pe.OPTIONAL_HEADER.CheckSum = checksum + + # Generate updated EXE data + data = pe.write() + + # Rewrite the exe + with open(exe_path, 'wb') as fp: + fp.write(data) + + +def compute_exe_pe_checksum(exe_path): + """ + This is a replacement for the MapFileAndCheckSumW function. As noted in MSDN documentation, the Microsoft's + implementation of MapFileAndCheckSumW internally calls its ASCII variant (MapFileAndCheckSumA), and therefore + cannot handle paths that contain characters that are not representable in the current code page. + See: https://docs.microsoft.com/en-us/windows/win32/api/imagehlp/nf-imagehlp-mapfileandchecksumw + + This function is based on Wine's implementation of MapFileAndCheckSumW, and due to being based entirely on + the pure widechar-API functions, it is not limited by the current code page. + """ + # ctypes bindings for relevant win32 API functions + import ctypes + from ctypes import windll, wintypes + + INVALID_HANDLE = wintypes.HANDLE(-1).value + + GetLastError = ctypes.windll.kernel32.GetLastError + GetLastError.argtypes = () + GetLastError.restype = wintypes.DWORD + + CloseHandle = windll.kernel32.CloseHandle + CloseHandle.argtypes = ( + wintypes.HANDLE, # hObject + ) + CloseHandle.restype = wintypes.BOOL + + CreateFileW = windll.kernel32.CreateFileW + CreateFileW.argtypes = ( + wintypes.LPCWSTR, # lpFileName + wintypes.DWORD, # dwDesiredAccess + wintypes.DWORD, # dwShareMode + wintypes.LPVOID, # lpSecurityAttributes + wintypes.DWORD, # dwCreationDisposition + wintypes.DWORD, # dwFlagsAndAttributes + wintypes.HANDLE, # hTemplateFile + ) + CreateFileW.restype = wintypes.HANDLE + + CreateFileMappingW = windll.kernel32.CreateFileMappingW + CreateFileMappingW.argtypes = ( + wintypes.HANDLE, # hFile + wintypes.LPVOID, # lpSecurityAttributes + wintypes.DWORD, # flProtect + wintypes.DWORD, # dwMaximumSizeHigh + wintypes.DWORD, # dwMaximumSizeLow + wintypes.LPCWSTR, # lpName + ) + CreateFileMappingW.restype = wintypes.HANDLE + + MapViewOfFile = windll.kernel32.MapViewOfFile + MapViewOfFile.argtypes = ( + wintypes.HANDLE, # hFileMappingObject + wintypes.DWORD, # dwDesiredAccess + wintypes.DWORD, # dwFileOffsetHigh + wintypes.DWORD, # dwFileOffsetLow + wintypes.DWORD, # dwNumberOfBytesToMap + ) + MapViewOfFile.restype = wintypes.LPVOID + + UnmapViewOfFile = windll.kernel32.UnmapViewOfFile + UnmapViewOfFile.argtypes = ( + wintypes.LPCVOID, # lpBaseAddress + ) + UnmapViewOfFile.restype = wintypes.BOOL + + GetFileSizeEx = windll.kernel32.GetFileSizeEx + GetFileSizeEx.argtypes = ( + wintypes.HANDLE, # hFile + wintypes.PLARGE_INTEGER, # lpFileSize + ) + + CheckSumMappedFile = windll.imagehlp.CheckSumMappedFile + CheckSumMappedFile.argtypes = ( + wintypes.LPVOID, # BaseAddress + wintypes.DWORD, # FileLength + wintypes.PDWORD, # HeaderSum + wintypes.PDWORD, # CheckSum + ) + CheckSumMappedFile.restype = wintypes.LPVOID + + # Open file + hFile = CreateFileW( + ctypes.c_wchar_p(exe_path), + 0x80000000, # dwDesiredAccess = GENERIC_READ + 0x00000001 | 0x00000002, # dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE, + None, # lpSecurityAttributes = NULL + 3, # dwCreationDisposition = OPEN_EXISTING + 0x80, # dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL + None # hTemplateFile = NULL + ) + if hFile == INVALID_HANDLE: + err = GetLastError() + raise RuntimeError(f"Failed to open file {exe_path}! Error code: {err}") + + # Query file size + fileLength = wintypes.LARGE_INTEGER(0) + if GetFileSizeEx(hFile, fileLength) == 0: + err = GetLastError() + CloseHandle(hFile) + raise RuntimeError(f"Failed to query file size file! Error code: {err}") + fileLength = fileLength.value + if fileLength > (2**32 - 1): + raise RuntimeError("Executable size exceeds maximum allowed executable size on Windows (4 GiB)!") + + # Map the file + hMapping = CreateFileMappingW( + hFile, + None, # lpFileMappingAttributes = NULL + 0x02, # flProtect = PAGE_READONLY + 0, # dwMaximumSizeHigh = 0 + 0, # dwMaximumSizeLow = 0 + None # lpName = NULL + ) + if not hMapping: + err = GetLastError() + CloseHandle(hFile) + raise RuntimeError(f"Failed to map file! Error code: {err}") + + # Create map view + baseAddress = MapViewOfFile( + hMapping, + 4, # dwDesiredAccess = FILE_MAP_READ + 0, # dwFileOffsetHigh = 0 + 0, # dwFileOffsetLow = 0 + 0 # dwNumberOfBytesToMap = 0 + ) + if baseAddress == 0: + err = GetLastError() + CloseHandle(hMapping) + CloseHandle(hFile) + raise RuntimeError(f"Failed to create map view! Error code: {err}") + + # Finally, compute the checksum + headerSum = wintypes.DWORD(0) + checkSum = wintypes.DWORD(0) + ret = CheckSumMappedFile(baseAddress, fileLength, ctypes.byref(headerSum), ctypes.byref(checkSum)) + if ret is None: + err = GetLastError() + + # Cleanup + UnmapViewOfFile(baseAddress) + CloseHandle(hMapping) + CloseHandle(hFile) + + if ret is None: + raise RuntimeError(f"CheckSumMappedFile failed! Error code: {err}") + + return checkSum.value diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/__editable__.inbm_lib-0.0.0.pth b/inbm/venv-3.11/lib/python3.11/site-packages/__editable__.inbm_lib-0.0.0.pth new file mode 100644 index 000000000..3214442ac --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/__editable__.inbm_lib-0.0.0.pth @@ -0,0 +1 @@ +import __editable___inbm_lib_0_0_0_finder; __editable___inbm_lib_0_0_0_finder.install() \ No newline at end of file diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/__editable___inbm_lib_0_0_0_finder.py b/inbm/venv-3.11/lib/python3.11/site-packages/__editable___inbm_lib_0_0_0_finder.py new file mode 100644 index 000000000..4891b49ec --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/__editable___inbm_lib_0_0_0_finder.py @@ -0,0 +1,79 @@ +import sys +from importlib.machinery import ModuleSpec, PathFinder +from importlib.machinery import all_suffixes as module_suffixes +from importlib.util import spec_from_file_location +from itertools import chain +from pathlib import Path + +MAPPING = {'inbm_common_lib': '/home/labadmin/inbm/intel-inb-manageability/inbm-lib/inbm_common_lib', 'inbm_lib': '/home/labadmin/inbm/intel-inb-manageability/inbm-lib/inbm_lib'} +NAMESPACES = {} +PATH_PLACEHOLDER = '__editable__.inbm_lib-0.0.0.finder' + ".__path_hook__" + + +class _EditableFinder: # MetaPathFinder + @classmethod + def find_spec(cls, fullname, path=None, target=None): + extra_path = [] + + # Top-level packages and modules (we know these exist in the FS) + if fullname in MAPPING: + pkg_path = MAPPING[fullname] + return cls._find_spec(fullname, Path(pkg_path)) + + # Handle immediate children modules (required for namespaces to work) + # To avoid problems with case sensitivity in the file system we delegate + # to the importlib.machinery implementation. + parent, _, child = fullname.rpartition(".") + if parent and parent in MAPPING: + return PathFinder.find_spec(fullname, path=[MAPPING[parent], *extra_path]) + + # Other levels of nesting should be handled automatically by importlib + # using the parent path. + return None + + @classmethod + def _find_spec(cls, fullname, candidate_path): + init = candidate_path / "__init__.py" + candidates = (candidate_path.with_suffix(x) for x in module_suffixes()) + for candidate in chain([init], candidates): + if candidate.exists(): + return spec_from_file_location(fullname, candidate) + + +class _EditableNamespaceFinder: # PathEntryFinder + @classmethod + def _path_hook(cls, path): + if path == PATH_PLACEHOLDER: + return cls + raise ImportError + + @classmethod + def _paths(cls, fullname): + # Ensure __path__ is not empty for the spec to be considered a namespace. + return NAMESPACES[fullname] or MAPPING.get(fullname) or [PATH_PLACEHOLDER] + + @classmethod + def find_spec(cls, fullname, target=None): + if fullname in NAMESPACES: + spec = ModuleSpec(fullname, None, is_package=True) + spec.submodule_search_locations = cls._paths(fullname) + return spec + return None + + @classmethod + def find_module(cls, fullname): + return None + + +def install(): + if not any(finder == _EditableFinder for finder in sys.meta_path): + sys.meta_path.append(_EditableFinder) + + if not NAMESPACES: + return + + if not any(hook == _EditableNamespaceFinder._path_hook for hook in sys.path_hooks): + # PathEntryFinder is needed to create NamespaceSpec without private APIS + sys.path_hooks.append(_EditableNamespaceFinder._path_hook) + if PATH_PLACEHOLDER not in sys.path: + sys.path.append(PATH_PLACEHOLDER) # Used just to trigger the path hook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_cffi_backend.cpython-311-x86_64-linux-gnu.so b/inbm/venv-3.11/lib/python3.11/site-packages/_cffi_backend.cpython-311-x86_64-linux-gnu.so new file mode 100755 index 000000000..7e46426f7 Binary files /dev/null and b/inbm/venv-3.11/lib/python3.11/site-packages/_cffi_backend.cpython-311-x86_64-linux-gnu.so differ diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_distutils_hack/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/_distutils_hack/__init__.py new file mode 100644 index 000000000..f987a5367 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_distutils_hack/__init__.py @@ -0,0 +1,222 @@ +# don't import any costly modules +import sys +import os + + +is_pypy = '__pypy__' in sys.builtin_module_names + + +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 + import warnings + + warnings.warn( + "Distutils was imported before Setuptools, but importing Setuptools " + "also replaces the `distutils` module in `sys.modules`. This may lead " + "to undesirable behaviors or errors. To avoid these issues, avoid " + "using distutils directly, ensure that setuptools is installed in the " + "traditional way (e.g. not an editable install), and/or make sure " + "that setuptools is always imported before distutils." + ) + + +def clear_distutils(): + if 'distutils' not in sys.modules: + return + import warnings + + warnings.warn("Setuptools is replacing distutils.") + mods = [ + name + for name in sys.modules + if name == "distutils" or name.startswith("distutils.") + ] + for name in mods: + del sys.modules[name] + + +def enabled(): + """ + Allow selection of distutils by environment variable. + """ + which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'local') + return which == 'local' + + +def ensure_local_distutils(): + import importlib + + clear_distutils() + + # With the DistutilsMetaFinder in place, + # perform an import to cause distutils to be + # loaded from setuptools._distutils. Ref #2906. + with shim(): + importlib.import_module('distutils') + + # check that submodules load as expected + core = importlib.import_module('distutils.core') + assert '_distutils' in core.__file__, core.__file__ + assert 'setuptools._distutils.log' not in sys.modules + + +def do_override(): + """ + Ensure that the local copy of distutils is preferred over stdlib. + + See https://github.com/pypa/setuptools/issues/417#issuecomment-392298401 + for more motivation. + """ + if enabled(): + warn_distutils_present() + ensure_local_distutils() + + +class _TrivialRe: + def __init__(self, *patterns): + self._patterns = patterns + + def match(self, string): + return all(pat in string for pat in self._patterns) + + +class DistutilsMetaFinder: + def find_spec(self, fullname, path, target=None): + # optimization: only consider top level modules and those + # found in the CPython test suite. + if path is not None and not fullname.startswith('test.'): + return + + method_name = 'spec_for_{fullname}'.format(**locals()) + method = getattr(self, method_name, lambda: None) + return method() + + def spec_for_distutils(self): + if self.is_cpython(): + return + + import importlib + import importlib.abc + import importlib.util + + try: + mod = importlib.import_module('setuptools._distutils') + except Exception: + # There are a couple of cases where setuptools._distutils + # may not be present: + # - An older Setuptools without a local distutils is + # taking precedence. Ref #2957. + # - Path manipulation during sitecustomize removes + # setuptools from the path but only after the hook + # has been loaded. Ref #2980. + # In either case, fall back to stdlib behavior. + return + + class DistutilsLoader(importlib.abc.Loader): + def create_module(self, spec): + mod.__name__ = 'distutils' + return mod + + def exec_module(self, module): + pass + + return importlib.util.spec_from_loader( + 'distutils', DistutilsLoader(), origin=mod.__file__ + ) + + @staticmethod + def is_cpython(): + """ + Suppress supplying distutils for CPython (build and tests). + Ref #2965 and #3007. + """ + return os.path.isfile('pybuilddir.txt') + + def spec_for_pip(self): + """ + Ensure stdlib distutils when running under pip. + See pypa/pip#8761 for rationale. + """ + if self.pip_imported_during_build(): + return + clear_distutils() + self.spec_for_distutils = lambda: None + + @classmethod + def pip_imported_during_build(cls): + """ + Detect if pip is being imported in a build script. Ref #2355. + """ + import traceback + + return any( + cls.frame_file_is_setup(frame) for frame, line in traceback.walk_stack(None) + ) + + @staticmethod + def frame_file_is_setup(frame): + """ + Return True if the indicated frame suggests a setup.py file. + """ + # some frames may not have __file__ (#2940) + return frame.f_globals.get('__file__', '').endswith('setup.py') + + def spec_for_sensitive_tests(self): + """ + Ensure stdlib distutils when running select tests under CPython. + + python/cpython#91169 + """ + clear_distutils() + self.spec_for_distutils = lambda: None + + sensitive_tests = ( + [ + 'test.test_distutils', + 'test.test_peg_generator', + 'test.test_importlib', + ] + if sys.version_info < (3, 10) + else [ + 'test.test_distutils', + ] + ) + + +for name in DistutilsMetaFinder.sensitive_tests: + setattr( + DistutilsMetaFinder, + f'spec_for_{name}', + DistutilsMetaFinder.spec_for_sensitive_tests, + ) + + +DISTUTILS_FINDER = DistutilsMetaFinder() + + +def add_shim(): + DISTUTILS_FINDER in sys.meta_path or insert_shim() + + +class shim: + def __enter__(self): + insert_shim() + + def __exit__(self, exc, value, tb): + remove_shim() + + +def insert_shim(): + sys.meta_path.insert(0, DISTUTILS_FINDER) + + +def remove_shim(): + try: + sys.meta_path.remove(DISTUTILS_FINDER) + except ValueError: + pass diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_distutils_hack/override.py b/inbm/venv-3.11/lib/python3.11/site-packages/_distutils_hack/override.py new file mode 100644 index 000000000..2cc433a4a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_distutils_hack/override.py @@ -0,0 +1 @@ +__import__('_distutils_hack').do_override() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/__init__.py new file mode 100644 index 000000000..1ab37dfe4 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/__init__.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +__version__ = '2023.11' +__maintainer__ = 'Legorooj, bwoodsend' +__uri__ = 'https://github.com/pyinstaller/pyinstaller-hooks-contrib' diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/__init__.py new file mode 100644 index 000000000..d7d7ff23f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/__init__.py @@ -0,0 +1,24 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +import os +from . import stdhooks +from . import rthooks + +_FILE_DIR = os.path.dirname(__file__) + + +def get_hook_dirs(): + return [ + *stdhooks.get_hook_dirs(), + *rthooks.get_hook_dirs(), + _FILE_DIR # pre_* hooks + ] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/pre_find_module_path/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/pre_find_module_path/__init__.py new file mode 100644 index 000000000..a72a9a61f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/pre_find_module_path/__init__.py @@ -0,0 +1,11 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/pre_safe_import_module/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/pre_safe_import_module/__init__.py new file mode 100644 index 000000000..a72a9a61f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/pre_safe_import_module/__init__.py @@ -0,0 +1,11 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/pre_safe_import_module/hook-tensorflow.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/pre_safe_import_module/hook-tensorflow.py new file mode 100644 index 000000000..f371cc08d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/pre_safe_import_module/hook-tensorflow.py @@ -0,0 +1,23 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2022, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import is_module_satisfies + + +def pre_safe_import_module(api): + # As of tensorflow 2.8.0, the `tensorflow.keras` is entirely gone, replaced by a lazy-loaded alias for + # `keras.api._v2.keras`. Without us registering the alias here, a program that imports only from + # `tensorflow.keras` fails to collect `tensorflow`. + # See: https://github.com/pyinstaller/pyinstaller/discussions/6890 + # The alias was already present in earlier releases, but it does not seem to be causing problems there, + # so keep this specific to tensorflow >= 2.8.0 to avoid accidentally breaking something else. + if is_module_satisfies("tensorflow >= 2.8.0"): + api.add_alias_module('keras.api._v2.keras', 'tensorflow.keras') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/pre_safe_import_module/hook-win32com.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/pre_safe_import_module/hook-win32com.py new file mode 100644 index 000000000..4a67a7911 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/pre_safe_import_module/hook-win32com.py @@ -0,0 +1,45 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2020, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +PyWin32 package 'win32com' extends it's __path__ attribute with win32comext +directory and thus PyInstaller is not able to find modules in it. For example +module 'win32com.shell' is in reality 'win32comext.shell'. + +>>> win32com.__path__ +['win32com', 'C:\\Python27\\Lib\\site-packages\\win32comext'] + +""" + +import os + +from PyInstaller.utils.hooks import logger, exec_statement +from PyInstaller.compat import is_win, is_cygwin + + +def pre_safe_import_module(api): + if not (is_win or is_cygwin): + return + win32com_file = exec_statement( + """ + try: + from win32com import __file__ + print(__file__) + except Exception: + pass + """).strip() + if not win32com_file: + logger.debug('win32com: module not available') + return # win32com unavailable + win32com_dir = os.path.dirname(win32com_file) + comext_dir = os.path.join(os.path.dirname(win32com_dir), 'win32comext') + logger.debug('win32com: extending __path__ with dir %r' % comext_dir) + # Append the __path__ where PyInstaller will look for 'win32com' modules.' + api.append_package_path(comext_dir) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks.dat b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks.dat new file mode 100644 index 000000000..25fd8edc6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks.dat @@ -0,0 +1,14 @@ +{ + 'enchant': ['pyi_rth_enchant.py'], + 'ffpyplayer': ['pyi_rth_ffpyplayer.py'], + 'osgeo': ['pyi_rth_osgeo.py'], + 'traitlets': ['pyi_rth_traitlets.py'], + 'usb': ['pyi_rth_usb.py'], + 'nltk': ['pyi_rth_nltk.py'], + 'pyproj': ['pyi_rth_pyproj.py'], + 'pygraphviz': ['pyi_rth_pygraphviz.py'], + 'pythoncom': ['pyi_rth_pythoncom.py'], + 'pyqtgraph': ['pyi_rth_pyqtgraph_multiprocess.py'], + 'pywintypes': ['pyi_rth_pywintypes.py'], + 'tensorflow': ['pyi_rth_tensorflow.py'], +} diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/__init__.py new file mode 100644 index 000000000..894980411 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/__init__.py @@ -0,0 +1,26 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the Apache License 2.0 +# +# The full license is available in LICENSE.APL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: Apache-2.0 +# ------------------------------------------------------------------ +import os + +DIR = os.path.dirname(__file__) +""" +This sub-package includes runtime hooks for pyinstaller. +""" + + +def get_hook_dirs(): + dirs = [] + # For every directory and sub directory (including cwd) + for path, _, _ in os.walk(DIR): + # Add the norm'd path to dirs + dirs.append(os.path.normpath(path)) + + return dirs diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_enchant.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_enchant.py new file mode 100644 index 000000000..21018c7de --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_enchant.py @@ -0,0 +1,22 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2020, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +import os +import sys + +# On Mac OS X tell enchant library where to look for enchant backends (aspell, myspell, ...). +# Enchant is looking for backends in directory 'PREFIX/lib/enchant' +# Note: env. var. ENCHANT_PREFIX_DIR is implemented only in the development version: +# https://github.com/AbiWord/enchant +# https://github.com/AbiWord/enchant/pull/2 +# TODO Test this rthook. +if sys.platform.startswith('darwin'): + os.environ['ENCHANT_PREFIX_DIR'] = os.path.join(sys._MEIPASS, 'enchant') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_ffpyplayer.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_ffpyplayer.py new file mode 100644 index 000000000..01f96889b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_ffpyplayer.py @@ -0,0 +1,19 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +# Starting with v4.3.5, the `ffpyplayer` package attempts to use `site.USER_BASE` in path manipulation functions. +# As frozen application runs with disabled `site`, the value of this variable is `None`, and causes path manipulation +# functions to raise an error. As a work-around, we set `site.USER_BASE` to an empty string, which is also what the +# fake `site` module available in PyInstaller prior to v5.5 did. +import site + +if site.USER_BASE is None: + site.USER_BASE = '' diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_nltk.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_nltk.py new file mode 100644 index 000000000..0180a4f5a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_nltk.py @@ -0,0 +1,17 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2020, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +import sys +import os +import nltk + +#add the path to nltk_data +nltk.data.path.insert(0, os.path.join(sys._MEIPASS, "nltk_data")) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_osgeo.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_osgeo.py new file mode 100644 index 000000000..bd8eff5b4 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_osgeo.py @@ -0,0 +1,32 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2015-2020, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +import os +import sys + +# Installing `osgeo` Conda packages requires to set `GDAL_DATA` + +is_win = sys.platform.startswith('win') +if is_win: + + gdal_data = os.path.join(sys._MEIPASS, 'data', 'gdal') + if not os.path.exists(gdal_data): + + gdal_data = os.path.join(sys._MEIPASS, 'Library', 'share', 'gdal') + # last attempt, check if one of the required file is in the generic folder Library/data + if not os.path.exists(os.path.join(gdal_data, 'gcs.csv')): + gdal_data = os.path.join(sys._MEIPASS, 'Library', 'data') + +else: + gdal_data = os.path.join(sys._MEIPASS, 'share', 'gdal') + +if os.path.exists(gdal_data): + os.environ['GDAL_DATA'] = gdal_data diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_pygraphviz.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_pygraphviz.py new file mode 100644 index 000000000..cbdd6c9d1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_pygraphviz.py @@ -0,0 +1,32 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2021, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +import pygraphviz + +# Override pygraphviz.AGraph._which method to search for graphviz executables inside sys._MEIPASS +if hasattr(pygraphviz.AGraph, '_which'): + + def _pygraphviz_override_which(self, name): + import os + import sys + import platform + + program_name = name + if platform.system() == "Windows": + program_name += ".exe" + + program_path = os.path.join(sys._MEIPASS, program_name) + if not os.path.isfile(program_path): + raise ValueError(f"Prog {name} not found in the PyInstaller-frozen application bundle!") + + return program_path + + pygraphviz.AGraph._which = _pygraphviz_override_which diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_pyproj.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_pyproj.py new file mode 100644 index 000000000..e083a3727 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_pyproj.py @@ -0,0 +1,26 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2015-2020, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +import os +import sys + +# Installing `pyproj` Conda packages requires to set `PROJ_LIB` + +is_win = sys.platform.startswith('win') +if is_win: + + proj_data = os.path.join(sys._MEIPASS, 'Library', 'share', 'proj') + +else: + proj_data = os.path.join(sys._MEIPASS, 'share', 'proj') + +if os.path.exists(proj_data): + os.environ['PROJ_LIB'] = proj_data diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_pyqtgraph_multiprocess.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_pyqtgraph_multiprocess.py new file mode 100644 index 000000000..c29f9e8d4 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_pyqtgraph_multiprocess.py @@ -0,0 +1,51 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2022, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +import sys +import os + + +def _setup_pyqtgraph_multiprocess_hook(): + # NOTE: pyqtgraph.multiprocess spawns the sub-process using subprocess.Popen (or equivalent). This means that in + # onefile builds, the executable in subprocess will unpack itself again, into different sys._MEIPASS, because + # the _MEIPASS2 environment variable is not set (bootloader / bootstrap script cleans it up). This will make the + # argv[1] check below fail, due to different sys._MEIPASS value in the subprocess. + # + # To work around this, at the time of writing (PyInstaller 5.5), the user needs to set _MEIPASS2 environment + # variable to sys._MEIPASS before using `pyqtgraph.multiprocess` in onefile builds. And stlib's + # `multiprocessing.freeze_support` needs to be called in the entry-point program, due to `pyqtgraph.multiprocess` + # internally using stdlib's `multiprocessing` primitives. + if len(sys.argv) == 2 and sys.argv[1] == os.path.join(sys._MEIPASS, 'pyqtgraph', 'multiprocess', 'bootstrap.py'): + # Load as module; this requires --hiddenimport pyqtgraph.multiprocess.bootstrap + try: + mod_name = 'pyqtgraph.multiprocess.bootstrap' + mod = __import__(mod_name) + bootstrap_co = mod.__loader__.get_code(mod_name) + except Exception: + bootstrap_co = None + + if bootstrap_co: + exec(bootstrap_co) + sys.exit(0) + + # Load from file; requires pyqtgraph/multiprocess/bootstrap.py collected as data file + bootstrap_file = os.path.join(sys._MEIPASS, 'pyqtgraph', 'multiprocess', 'bootstrap.py') + if os.path.isfile(bootstrap_file): + with open(bootstrap_file, 'r') as fp: + bootstrap_code = fp.read() + exec(bootstrap_code) + sys.exit(0) + + raise RuntimeError("Could not find pyqtgraph.multiprocess bootstrap code or script!") + + +_setup_pyqtgraph_multiprocess_hook() +del _setup_pyqtgraph_multiprocess_hook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_pythoncom.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_pythoncom.py new file mode 100644 index 000000000..4886759b7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_pythoncom.py @@ -0,0 +1,24 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2022, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +# Unfortunately, __import_pywin32_system_module__ from pywintypes module assumes that in a frozen application, the +# pythoncom3X.dll and pywintypes3X.dll that are normally found in site-packages/pywin32_system32, are located +# directly in the sys.path, without bothering to check first if they are actually available in the standard location. +# This obviously runs afoul of our attempts at preserving the directory layout and placing them in the pywin32_system32 +# sub-directory instead of the top-level application directory. So as a work-around, add the sub-directory to sys.path +# to keep pywintypes happy... +import sys +import os + +pywin32_system32_path = os.path.join(sys._MEIPASS, 'pywin32_system32') +if os.path.isdir(pywin32_system32_path) and pywin32_system32_path not in sys.path: + sys.path.append(pywin32_system32_path) +del pywin32_system32_path diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_pywintypes.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_pywintypes.py new file mode 100644 index 000000000..4886759b7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_pywintypes.py @@ -0,0 +1,24 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2022, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +# Unfortunately, __import_pywin32_system_module__ from pywintypes module assumes that in a frozen application, the +# pythoncom3X.dll and pywintypes3X.dll that are normally found in site-packages/pywin32_system32, are located +# directly in the sys.path, without bothering to check first if they are actually available in the standard location. +# This obviously runs afoul of our attempts at preserving the directory layout and placing them in the pywin32_system32 +# sub-directory instead of the top-level application directory. So as a work-around, add the sub-directory to sys.path +# to keep pywintypes happy... +import sys +import os + +pywin32_system32_path = os.path.join(sys._MEIPASS, 'pywin32_system32') +if os.path.isdir(pywin32_system32_path) and pywin32_system32_path not in sys.path: + sys.path.append(pywin32_system32_path) +del pywin32_system32_path diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_tensorflow.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_tensorflow.py new file mode 100644 index 000000000..c967f4895 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_tensorflow.py @@ -0,0 +1,19 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2023, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +# `tensorflow` versions prior to 2.3.0 attempt to use `site.USER_SITE` in path/string manipulation functions. +# As frozen application runs with disabled `site`, the value of this variable is `None`, and causes path/string +# manipulation functions to raise an error. As a work-around, we set `site.USER_SITE` to an empty string, which is +# also what the fake `site` module available in PyInstaller prior to v5.5 did. +import site + +if site.USER_SITE is None: + site.USER_SITE = '' diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_traitlets.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_traitlets.py new file mode 100644 index 000000000..820515365 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_traitlets.py @@ -0,0 +1,25 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2020, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +# 'traitlets' uses module 'inspect' from default Python library to inspect +# source code of modules. However, frozen app does not contain source code +# of Python modules. +# +# hook-IPython depends on module 'traitlets'. + +import traitlets.traitlets + + +def _disabled_deprecation_warnings(method, cls, method_name, msg): + pass + + +traitlets.traitlets._deprecated_method = _disabled_deprecation_warnings diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_usb.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_usb.py new file mode 100644 index 000000000..af016a9c9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/rthooks/pyi_rth_usb.py @@ -0,0 +1,75 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2013-2020, PyInstaller Development Team. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: Apache-2.0 +#----------------------------------------------------------------------------- + +import ctypes +import glob +import os +import sys +# Pyusb changed these libusb module names in commit 2082e7. +try: + import usb.backend.libusb10 as libusb10 +except ImportError: + import usb.backend.libusb1 as libusb10 +try: + import usb.backend.libusb01 as libusb01 +except ImportError: + import usb.backend.libusb0 as libusb01 +import usb.backend.openusb as openusb + + +def get_load_func(type, candidates): + + def _load_library(find_library=None): + exec_path = sys._MEIPASS + + library = None + for candidate in candidates: + # Do linker's path lookup work to force load bundled copy. + if os.name == 'posix' and sys.platform == 'darwin': + libs = glob.glob("%s/%s*.dylib*" % (exec_path, candidate)) + elif sys.platform == 'win32' or sys.platform == 'cygwin': + libs = glob.glob("%s\\%s*.dll" % (exec_path, candidate)) + else: + libs = glob.glob("%s/%s*.so*" % (exec_path, candidate)) + for libname in libs: + try: + # NOTE: libusb01 is using CDLL under win32. + # (see usb.backends.libusb01) + if sys.platform == 'win32' and type != 'libusb01': + library = ctypes.WinDLL(libname) + else: + library = ctypes.CDLL(libname) + if library is not None: + break + except OSError: + library = None + if library is not None: + break + else: + raise OSError('USB library could not be found') + + if type == 'libusb10': + if not hasattr(library, 'libusb_init'): + raise OSError('USB library could not be found') + return library + + return _load_library + + +# NOTE: Need to keep in sync with future PyUSB updates. +if sys.platform == 'cygwin': + libusb10._load_library = get_load_func('libusb10', ('cygusb-1.0', )) + libusb01._load_library = get_load_func('libusb01', ('cygusb0', )) + openusb._load_library = get_load_func('openusb', ('openusb', )) +else: + libusb10._load_library = get_load_func('libusb10', ('usb-1.0', 'libusb-1.0', 'usb')) + libusb01._load_library = get_load_func('libusb01', ('usb-0.1', 'usb', 'libusb0', 'libusb')) + openusb._load_library = get_load_func('openusb', ('openusb', )) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/__init__.py new file mode 100644 index 000000000..84c32b0d0 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/__init__.py @@ -0,0 +1,31 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +import os + +DIR = os.path.dirname(__file__) +""" +All sub folders in this folder - "stdhooks" - are considered hook directories. + +All sub folders MUST define an `__init__.py` file. +We recommend that it contains the copyright header, and nothing else. +""" + + +def get_hook_dirs(): + + dirs = [] + # For every directory and sub directory (including cwd) + for path, _, _ in os.walk(DIR): + # Add the norm'd path to dirs + dirs.append(os.path.normpath(path)) + + return dirs diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-BTrees.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-BTrees.py new file mode 100644 index 000000000..8e6ab68d7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-BTrees.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for BTrees: https://pypi.org/project/BTrees/4.5.1/ + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules('BTrees') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-CTkMessagebox.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-CTkMessagebox.py new file mode 100644 index 000000000..905ce2fe2 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-CTkMessagebox.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# A fully customizable messagebox for customtkinter! +# (extension/add-on) +# ------------------------------------------------------------------ +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("CTkMessagebox") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-Crypto.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-Crypto.py new file mode 100644 index 000000000..c21f191e9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-Crypto.py @@ -0,0 +1,62 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for PyCryptodome library: https://pypi.python.org/pypi/pycryptodome + +PyCryptodome is an almost drop-in replacement for the now unmaintained +PyCrypto library. The two are mutually exclusive as they live under +the same package ("Crypto"). + +PyCryptodome distributes dynamic libraries and builds them as if they were +Python C extensions (even though they are not extensions - as they can't be +imported by Python). It might sound a bit weird, but this decision is rooted +in PyPy and its partial and slow support for C extensions. However, this also +invalidates several of the existing methods used by PyInstaller to decide the +right files to pull in. + +Even though this hook is meant to help with PyCryptodome only, it will be +triggered also when PyCrypto is installed, so it must be tested with both. + +Tested with PyCryptodome 3.5.1, PyCrypto 2.6.1, Python 2.7 & 3.6, Fedora & Windows +""" + +import os +import glob + +from PyInstaller.compat import EXTENSION_SUFFIXES +from PyInstaller.utils.hooks import get_module_file_attribute + +# Include the modules as binaries in a subfolder named like the package. +# Cryptodome's loader expects to find them inside the package directory for +# the main module. We cannot use hiddenimports because that would add the +# modules outside the package. + +binaries = [] +binary_module_names = [ + 'Crypto.Math', # First in the list + 'Crypto.Cipher', + 'Crypto.Util', + 'Crypto.Hash', + 'Crypto.Protocol', + 'Crypto.PublicKey', +] + +try: + for module_name in binary_module_names: + m_dir = os.path.dirname(get_module_file_attribute(module_name)) + for ext in EXTENSION_SUFFIXES: + module_bin = glob.glob(os.path.join(m_dir, '_*%s' % ext)) + for f in module_bin: + binaries.append((f, module_name.replace('.', os.sep))) +except ImportError: + # Do nothing for PyCrypto (Crypto.Math does not exist there) + pass diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-Cryptodome.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-Cryptodome.py new file mode 100644 index 000000000..e4b45064c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-Cryptodome.py @@ -0,0 +1,44 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for Cryptodome module: https://pypi.python.org/pypi/pycryptodomex + +Tested with Cryptodomex 3.4.2, Python 2.7 & 3.5, Windows +""" + +import os +import glob + +from PyInstaller.compat import EXTENSION_SUFFIXES +from PyInstaller.utils.hooks import get_module_file_attribute + +# Include the modules as binaries in a subfolder named like the package. +# Cryptodome's loader expects to find them inside the package directory for +# the main module. We cannot use hiddenimports because that would add the +# modules outside the package. + +binaries = [] +binary_module_names = [ + 'Cryptodome.Cipher', + 'Cryptodome.Util', + 'Cryptodome.Hash', + 'Cryptodome.Protocol', + 'Cryptodome.Math', + 'Cryptodome.PublicKey', +] + +for module_name in binary_module_names: + m_dir = os.path.dirname(get_module_file_attribute(module_name)) + for ext in EXTENSION_SUFFIXES: + module_bin = glob.glob(os.path.join(m_dir, '_*%s' % ext)) + for f in module_bin: + binaries.append((f, module_name.replace('.', '/'))) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-HtmlTestRunner.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-HtmlTestRunner.py new file mode 100644 index 000000000..cd0ee425b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-HtmlTestRunner.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for HtmlTestRunner: https://pypi.org/project/html-testRunner//1.2.1 + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('HtmlTestRunner') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-IPython.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-IPython.py new file mode 100644 index 000000000..a09712bcc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-IPython.py @@ -0,0 +1,33 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Tested with IPython 4.0.0. + +from PyInstaller.compat import is_win, is_darwin +from PyInstaller.utils.hooks import collect_data_files + +# Ignore 'matplotlib'. IPython contains support for matplotlib. +# Ignore GUI libraries. IPython supports integration with GUI frameworks. +# Assume that it will be imported by any other module when the user really +# uses it. +excludedimports = ['gtk', 'matplotlib', 'PyQt4', 'PyQt5', 'PySide'] + +# IPython uses 'tkinter' for clipboard access on Linux/Unix. Exclude it on Windows and OS X. +if is_win or is_darwin: + excludedimports.append('tkinter') + +datas = collect_data_files('IPython') + +# IPython imports extensions by changing to the extensions directory and using +# importlib.import_module, so we need to copy over the extensions as if they +# were data files. +datas += collect_data_files('IPython.extensions', include_py_files=True) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-OpenGL.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-OpenGL.py new file mode 100644 index 000000000..85548c78c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-OpenGL.py @@ -0,0 +1,65 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for PyOpenGL 3.x versions from 3.0.0b6 up. Previous versions have a +plugin system based on pkg_resources which is problematic to handle correctly +under pyinstaller; 2.x versions used to run fine without hooks, so this one +shouldn't hurt. +""" + +from PyInstaller.compat import is_win, is_darwin +from PyInstaller.utils.hooks import collect_data_files, exec_statement +import os +import glob + + +def opengl_arrays_modules(): + """ + Return list of array modules for OpenGL module. + e.g. 'OpenGL.arrays.vbo' + """ + statement = 'import OpenGL; print(OpenGL.__path__[0])' + opengl_mod_path = exec_statement(statement) + arrays_mod_path = os.path.join(opengl_mod_path, 'arrays') + files = glob.glob(arrays_mod_path + '/*.py') + modules = [] + + for f in files: + mod = os.path.splitext(os.path.basename(f))[0] + # Skip __init__ module. + if mod == '__init__': + continue + modules.append('OpenGL.arrays.' + mod) + + return modules + + +# PlatformPlugin performs a conditional import based on os.name and +# sys.platform. PyInstaller misses this so let's add it ourselves... +if is_win: + hiddenimports = ['OpenGL.platform.win32'] +elif is_darwin: + hiddenimports = ['OpenGL.platform.darwin'] +# Use glx for other platforms (Linux, ...) +else: + hiddenimports = ['OpenGL.platform.glx'] + +# Arrays modules are needed too. +hiddenimports += opengl_arrays_modules() + +# PyOpenGL 3.x uses ctypes to load DLL libraries. PyOpenGL windows installer +# adds necessary dll files to +# DLL_DIRECTORY = os.path.join( os.path.dirname( OpenGL.__file__ ), 'DLLS') +# PyInstaller is not able to find these dlls. Just include them all as data +# files. +if is_win: + datas = collect_data_files('OpenGL') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-OpenGL_accelerate.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-OpenGL_accelerate.py new file mode 100644 index 000000000..aedba7ee1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-OpenGL_accelerate.py @@ -0,0 +1,22 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +OpenGL_accelerate contais modules written in cython. This module +should speed up some functions from OpenGL module. The following +hiddenimports are not resolved by PyInstaller because OpenGL_accelerate +is compiled to native Python modules. +""" + +hiddenimports = [ + 'OpenGL_accelerate.wrapper', + 'OpenGL_accelerate.formathandler', +] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-Xlib.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-Xlib.py new file mode 100644 index 000000000..b627408bc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-Xlib.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules('Xlib') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-_mssql.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-_mssql.py new file mode 100644 index 000000000..2f4da28c6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-_mssql.py @@ -0,0 +1,13 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = ['uuid'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-_mysql.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-_mysql.py new file mode 100644 index 000000000..0cf0d0f9b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-_mysql.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for _mysql, required if higher-level pure python module is not imported +""" + +hiddenimports = ['_mysql_exceptions'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-accessible_output2.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-accessible_output2.py new file mode 100644 index 000000000..91d16c55c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-accessible_output2.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +accessible_output2: http://hg.q-continuum.net/accessible_output2 +""" + +from PyInstaller.utils.hooks import collect_dynamic_libs + +binaries = collect_dynamic_libs('accessible_output2') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-adbutils.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-adbutils.py new file mode 100644 index 000000000..04c4ec932 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-adbutils.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +# adb.exe is not automatically collected by collect_dynamic_libs() +datas = collect_data_files("adbutils", subdir="binaries", includes=["adb*"]) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-adios.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-adios.py new file mode 100644 index 000000000..d3ff6bb41 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-adios.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for http://pypi.python.org/pypi/adios/ +""" + +hiddenimports = ['adios._hl.selections'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-afmformats.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-afmformats.py new file mode 100644 index 000000000..f46b46b23 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-afmformats.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for afmformats: https://pypi.python.org/pypi/afmformats + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('afmformats') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-aliyunsdkcore.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-aliyunsdkcore.py new file mode 100644 index 000000000..6475963aa --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-aliyunsdkcore.py @@ -0,0 +1,14 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("aliyunsdkcore") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-altair.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-altair.py new file mode 100644 index 000000000..4be3bc188 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-altair.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("altair") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-amazonproduct.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-amazonproduct.py new file mode 100644 index 000000000..da9bf6742 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-amazonproduct.py @@ -0,0 +1,26 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for Python bindings for Amazon's Product Advertising API. +https://bitbucket.org/basti/python-amazon-product-api +""" + +hiddenimports = ['amazonproduct.processors.__init__', + 'amazonproduct.processors._lxml', + 'amazonproduct.processors.objectify', + 'amazonproduct.processors.elementtree', + 'amazonproduct.processors.etree', + 'amazonproduct.processors.minidom', + 'amazonproduct.contrib.__init__', + 'amazonproduct.contrib.cart', + 'amazonproduct.contrib.caching', + 'amazonproduct.contrib.retry'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-anyio.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-anyio.py new file mode 100644 index 000000000..37d675eb6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-anyio.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +AnyIO contains a number of back-ends as dynamically imported modules. +This hook was tested against AnyIO v1.4.0. +""" + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules('anyio._backends') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-appdirs.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-appdirs.py new file mode 100644 index 000000000..f13961308 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-appdirs.py @@ -0,0 +1,21 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Import hook for appdirs. + +On Windows, appdirs tries 2 different methods to get well-known directories +from the system: First with win32com, then with ctypes. Excluding win32com here +avoids including all the win32com related DLLs in programs that don't include +them otherwise. +""" + +excludedimports = ['win32com'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-appy.pod.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-appy.pod.py new file mode 100644 index 000000000..a4bfb195e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-appy.pod.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for appy.pod: https://pypi.python.org/pypi/appy/0.9.1 + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('appy.pod', True) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-apscheduler.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-apscheduler.py new file mode 100644 index 000000000..014f93f3b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-apscheduler.py @@ -0,0 +1,27 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +APScheduler uses entry points to dynamically load executors, job +stores and triggers. +This hook was tested against APScheduler 3.6.3. +""" + +from PyInstaller.utils.hooks import (collect_submodules, copy_metadata, + is_module_satisfies) + +if is_module_satisfies("apscheduler < 4"): + if is_module_satisfies("pyinstaller >= 4.4"): + datas = copy_metadata('APScheduler', recursive=True) + else: + datas = copy_metadata('APScheduler') + + hiddenimports = collect_submodules('apscheduler') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-argon2.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-argon2.py new file mode 100644 index 000000000..e532b2082 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-argon2.py @@ -0,0 +1,13 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = ["_cffi_backend"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-astor.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-astor.py new file mode 100644 index 000000000..1175d9b2b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-astor.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('astor') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-astroid.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-astroid.py new file mode 100644 index 000000000..80035fbcc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-astroid.py @@ -0,0 +1,48 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# +# *************************************************** +# hook-astriod.py - PyInstaller hook file for astriod +# *************************************************** +# The astriod package, in __pkginfo__.py, is version 1.1.1. Looking at its +# source: +# +# From __init__.py, starting at line 111:: +# +# BRAIN_MODULES_DIR = join(dirname(__file__), 'brain') +# if BRAIN_MODULES_DIR not in sys.path: +# # add it to the end of the list so user path take precedence +# sys.path.append(BRAIN_MODULES_DIR) +# # load modules in this directory +# for module in listdir(BRAIN_MODULES_DIR): +# if module.endswith('.py'): +# __import__(module[:-3]) +# +# So, we need all the Python source in the ``brain/`` subdirectory, +# since this is run-time discovered and loaded. Therefore, these +# files are all data files. + +from PyInstaller.utils.hooks import collect_data_files, collect_submodules, \ + is_module_or_submodule + +# Note that brain/ isn't a module (it lacks an __init__.py, so it can't be +# referred to as astroid.brain; instead, locate it as package astriod, +# subdirectory brain/. +datas = collect_data_files('astroid', True, 'brain') + +# Update: in astroid v 1.4.1, the brain/ module import parts of astroid. Since +# everything in brain/ is dynamically imported, these are hidden imports. For +# simplicity, include everything in astroid. Exclude all the test/ subpackage +# contents and the test_util module. +hiddenimports = ['six'] + collect_submodules('astroid', + lambda name: (not is_module_or_submodule(name, 'astroid.tests')) and + (not name == 'test_util')) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-astropy.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-astropy.py new file mode 100644 index 000000000..b04854cc9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-astropy.py @@ -0,0 +1,42 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files, collect_submodules, \ + copy_metadata, is_module_satisfies + +# Astropy includes a number of non-Python files that need to be present +# at runtime, so we include these explicitly here. +datas = collect_data_files('astropy') + +# In a number of places, astropy imports other sub-modules in a way that is not +# always auto-discovered by pyinstaller, so we always include all submodules. +hiddenimports = collect_submodules('astropy') + +# We now need to include the *_parsetab.py and *_lextab.py files for unit and +# coordinate parsing, since these are loaded as files rather than imported as +# sub-modules. We leverage collect_data_files to get all files in astropy then +# filter these. +ply_files = [] +for path, target in collect_data_files('astropy', include_py_files=True): + if path.endswith(('_parsetab.py', '_lextab.py')): + ply_files.append((path, target)) + +datas += ply_files + +# Astropy version >= 5.0 queries metadata to get version information. +if is_module_satisfies('astropy >= 5.0'): + datas += copy_metadata('astropy') + datas += copy_metadata('numpy') + +# In the Cython code, Astropy imports numpy.lib.recfunctions which isn't +# automatically discovered by pyinstaller, so we add this as a hidden import. +hiddenimports += ['numpy.lib.recfunctions'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-astropy_iers_data.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-astropy_iers_data.py new file mode 100644 index 000000000..27af5d2fb --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-astropy_iers_data.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for https://github.com/astropy/astropy-iers-data + +from PyInstaller.utils.hooks import collect_data_files +datas = collect_data_files("astropy_iers_data") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-av.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-av.py new file mode 100644 index 000000000..f1e528483 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-av.py @@ -0,0 +1,34 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +import os + +from PyInstaller.compat import is_win +from PyInstaller.utils.hooks import collect_submodules, is_module_satisfies, get_package_paths + +hiddenimports = ['fractions'] + collect_submodules("av") + +# Starting with av 9.1.1, the DLLs shipped with Windows PyPI wheels are stored +# in site-packages/av.libs instead of directly in the site-packages/av. +if is_module_satisfies("av >= 9.1.1") and is_win: + pkg_base, pkg_dir = get_package_paths("av") + lib_dir = os.path.join(pkg_base, "av.libs") + if os.path.isdir(lib_dir): + # We collect DLLs as data files instead of binaries to suppress binary + # analysis, which would result in duplicates (because it collects a copy + # into the top-level directory instead of preserving the original layout). + # In addition to DLls, this also collects .load-order* file (required on + # python < 3.8), and ensures that Shapely.libs directory exists (required + # on python >= 3.8 due to os.add_dll_directory call). + datas = [ + (os.path.join(lib_dir, lib_file), 'av.libs') + for lib_file in os.listdir(lib_dir) + ] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-avro.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-avro.py new file mode 100644 index 000000000..74153d35a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-avro.py @@ -0,0 +1,27 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Avro is a serialization and RPC framework. +""" + +import os +from PyInstaller.utils.hooks import get_module_file_attribute + +res_loc = os.path.dirname(get_module_file_attribute("avro")) +# see https://github.com/apache/avro/blob/master/lang/py3/setup.py +datas = [ + # Include the version.txt file, used to set __version__ + (os.path.join(res_loc, "VERSION.txt"), "avro"), + # The handshake schema is needed for IPC communication + (os.path.join(res_loc, "HandshakeRequest.avsc"), "avro"), + (os.path.join(res_loc, "HandshakeResponse.avsc"), "avro"), +] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-azurerm.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-azurerm.py new file mode 100644 index 000000000..599e839f8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-azurerm.py @@ -0,0 +1,22 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# Azurerm is a lite api to microsoft azure. +# Azurerm is using pkg_resources internally which is not supported by py-installer. +# This hook will collect the module metadata. +# Tested with Azurerm 0.10.0 + +from PyInstaller.utils.hooks import copy_metadata, is_module_satisfies + +if is_module_satisfies("pyinstaller >= 4.4"): + datas = copy_metadata("azurerm", recursive=True) +else: + datas = copy_metadata("azurerm") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-backports.zoneinfo.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-backports.zoneinfo.py new file mode 100644 index 000000000..93730f471 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-backports.zoneinfo.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.compat import is_win + +# On Windows, timezone data is provided by the tzdata package that is +# not directly loaded. +if is_win: + hiddenimports = ['tzdata'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-bacon.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-bacon.py new file mode 100644 index 000000000..449a9ba4c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-bacon.py @@ -0,0 +1,50 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for Bacon (https://github.com/aholkner/bacon) +# Bacon requires its native DLLs to be copied alongside frozen executable. + +import os +import ctypes + +from PyInstaller.compat import is_win, is_darwin +from PyInstaller.utils.hooks import get_package_paths + + +def collect_native_files(package, files): + pkg_base, pkg_dir = get_package_paths(package) + return [(os.path.join(pkg_dir, file), '.') for file in files] + + +if is_win: + files = ['Bacon.dll', + 'd3dcompiler_46.dll', + 'libEGL.dll', + 'libGLESv2.dll', + 'msvcp110.dll', + 'msvcr110.dll', + 'vccorllib110.dll'] + if ctypes.sizeof(ctypes.c_void_p) == 4: + hiddenimports = ["bacon.windows32"] + datas = collect_native_files('bacon.windows32', files) + else: + hiddenimports = ["bacon.windows64"] + datas = collect_native_files('bacon.windows64', files) +elif is_darwin: + if ctypes.sizeof(ctypes.c_void_p) == 4: + hiddenimports = ["bacon.darwin32"] + files = ['Bacon.dylib'] + datas = collect_native_files('bacon.darwin32', files) + else: + hiddenimports = ["bacon.darwin64"] + files = ['Bacon64.dylib'] + datas = collect_native_files('bacon.darwin64', files) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-bcrypt.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-bcrypt.py new file mode 100644 index 000000000..d73e9f09b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-bcrypt.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for https://pypi.org/project/bcrypt/ +""" + +hiddenimports = ['_cffi_backend'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-bleak.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-bleak.py new file mode 100644 index 000000000..c9ce04a07 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-bleak.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# hook for https://github.com/hbldh/bleak + +from PyInstaller.utils.hooks import collect_data_files, collect_dynamic_libs +from PyInstaller.compat import is_win + +if is_win: + datas = collect_data_files('bleak', subdir=r'backends\dotnet') + binaries = collect_dynamic_libs('bleak') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-blspy.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-blspy.py new file mode 100644 index 000000000..fb1c8d75b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-blspy.py @@ -0,0 +1,35 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +import os +import glob + +from PyInstaller.utils.hooks import get_module_file_attribute +from PyInstaller.compat import is_win + +# blspy comes as a stand-alone extension module that's placed directly +# in site-packages. +# +# On macOS and Linux, it is linked against the GMP library, whose shared +# library is stored in blspy.libs and .dylibsblspy, respectively. As this +# is a linked dependency, it is collected properly by PyInstaller and +# no further work is needed. +# +# On Windows, however, the blspy extension is linked against MPIR library, +# whose DLLs are placed directly into site-packages. The mpir.dll is +# linked dependency and is picked up automatically, but it in turn +# dynamically loads CPU-specific backends that are named mpir_*.dll. +# We need to colllect these manually. +if is_win: + blspy_dir = os.path.dirname(get_module_file_attribute('blspy')) + mpir_dlls = glob.glob(os.path.join(blspy_dir, 'mpir_*.dll')) + binaries = [(mpir_dll, '.') for mpir_dll in mpir_dlls] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-bokeh.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-bokeh.py new file mode 100644 index 000000000..8f7db4388 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-bokeh.py @@ -0,0 +1,27 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files, copy_metadata, is_module_satisfies + +# core/_templates/* +# server/static/**/* +# subcommands/*.py +# bokeh/_sri.json + +datas = collect_data_files('bokeh.core') + \ + collect_data_files('bokeh.server') + \ + collect_data_files('bokeh.command.subcommands', include_py_files=True) + \ + collect_data_files('bokeh') + +# bokeh >= 3.0.0 sets its __version__ from metadata +if is_module_satisfies('bokeh >= 3.0.0'): + datas += copy_metadata('bokeh') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-boto.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-boto.py new file mode 100644 index 000000000..f96b9e26d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-boto.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# +# Boto3, the next version of Boto, is now stable and recommended for general +# use. +# +# Boto is an integrated interface to current and future infrastructural +# services offered by Amazon Web Services. +# +# http://boto.readthedocs.org/en/latest/ +# +# Tested with boto 2.38.0 + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('boto') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-boto3.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-boto3.py new file mode 100644 index 000000000..3eeb974bd --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-boto3.py @@ -0,0 +1,29 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# +# Boto is the Amazon Web Services (AWS) SDK for Python, which allows Python +# developers to write software that makes use of Amazon services like S3 and +# EC2. Boto provides an easy to use, object-oriented API as well as low-level +# direct service access. +# +# http://boto3.readthedocs.org/en/latest/ +# +# Tested with boto3 1.2.1 + +from PyInstaller.utils.hooks import collect_data_files, collect_submodules + +hiddenimports = ( + collect_submodules('boto3.dynamodb') + + collect_submodules('boto3.ec2') + + collect_submodules('boto3.s3') +) +datas = collect_data_files('boto3') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-botocore.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-botocore.py new file mode 100644 index 000000000..59c0f1624 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-botocore.py @@ -0,0 +1,30 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# +# Botocore is a low-level interface to a growing number of Amazon Web Services. +# Botocore serves as the foundation for the AWS-CLI command line utilities. It +# will also play an important role in the boto3.x project. +# +# The botocore package is compatible with Python versions 2.6.5, Python 2.7.x, +# and Python 3.3.x and higher. +# +# https://botocore.readthedocs.org/en/latest/ +# +# Tested with botocore 1.4.36 + +from PyInstaller.utils.hooks import collect_data_files +from PyInstaller.utils.hooks import is_module_satisfies + +if is_module_satisfies('botocore >= 1.4.36'): + hiddenimports = ['html.parser'] + +datas = collect_data_files('botocore') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-branca.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-branca.py new file mode 100644 index 000000000..4c5bd24bc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-branca.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("branca") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cairocffi.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cairocffi.py new file mode 100644 index 000000000..523d8a67e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cairocffi.py @@ -0,0 +1,45 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +import ctypes.util +import os + +from PyInstaller.depend.utils import _resolveCtypesImports +from PyInstaller.utils.hooks import collect_data_files, is_module_satisfies, logger + +datas = collect_data_files("cairocffi") + +binaries = [] + +# NOTE: Update this if cairocffi requires more libraries +libs = ["cairo-2", "cairo", "libcairo-2"] + +try: + lib_basenames = [] + for lib in libs: + libname = ctypes.util.find_library(lib) + if libname is not None: + lib_basenames += [os.path.basename(libname)] + + if lib_basenames: + resolved_libs = _resolveCtypesImports(lib_basenames) + for resolved_lib in resolved_libs: + binaries.append((resolved_lib[1], '.')) +except Exception as e: + logger.warning("Error while trying to find system-installed Cairo library: %s", e) + +if not binaries: + logger.warning("Cairo library not found - cairocffi will likely fail to work!") + +# cairocffi 1.6.0 requires cairocffi/constants.py source file, so make sure it is collected. +# The module collection mode setting requires PyInstaller >= 5.3. +if is_module_satisfies('cairocffi >= 1.6.0'): + module_collection_mode = {'cairocffi.constants': 'pyz+py'} diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cairosvg.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cairosvg.py new file mode 100644 index 000000000..649254b77 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cairosvg.py @@ -0,0 +1,40 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +import ctypes.util +import os + +from PyInstaller.depend.utils import _resolveCtypesImports +from PyInstaller.utils.hooks import collect_data_files, logger + +datas = collect_data_files("cairosvg") + +binaries = [] + +# NOTE: Update this if cairosvg requires more libraries +libs = ["cairo-2", "cairo", "libcairo-2"] + +try: + lib_basenames = [] + for lib in libs: + libname = ctypes.util.find_library(lib) + if libname is not None: + lib_basenames += [os.path.basename(libname)] + + if lib_basenames: + resolved_libs = _resolveCtypesImports(lib_basenames) + for resolved_lib in resolved_libs: + binaries.append((resolved_lib[1], '.')) +except Exception as e: + logger.warning("Error while trying to find system-installed Cairo library: %s", e) + +if not binaries: + logger.warning("Cairo library not found - cairosvg will likely fail to work!") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cassandra.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cassandra.py new file mode 100644 index 000000000..97cd4c786 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cassandra.py @@ -0,0 +1,22 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# +# A modern, feature-rich and highly-tunable Python client library for Apache Cassandra (2.1+) and +# DataStax Enterprise (4.7+) using exclusively Cassandra's binary protocol and Cassandra Query Language v3. +# +# http://datastax.github.io/python-driver/api/index.html +# +# Tested with cassandra-driver 3.25.0 + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules('cassandra') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-certifi.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-certifi.py new file mode 100644 index 000000000..79229be5a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-certifi.py @@ -0,0 +1,21 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Certifi is a 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. + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('certifi') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cf_units.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cf_units.py new file mode 100644 index 000000000..13edf03b5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cf_units.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +# Include data files from cf_units/etc sub-directory. +datas = collect_data_files('cf_units', includes=['etc/**']) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cftime.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cftime.py new file mode 100644 index 000000000..b87bbe1b3 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cftime.py @@ -0,0 +1,21 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# The cftime._cftime is a cython exension with following hidden imports: +hiddenimports = [ + 're', + 'time', + 'datetime', + 'warnings', + 'numpy', + 'cftime._strptime', +] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-charset_normalizer.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-charset_normalizer.py new file mode 100644 index 000000000..9a94c2159 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-charset_normalizer.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies + +if is_module_satisfies("charset_normalizer >= 3.0.1"): + hiddenimports = ["charset_normalizer.md__mypyc"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cloudscraper.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cloudscraper.py new file mode 100644 index 000000000..91664a6d5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cloudscraper.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('cloudscraper') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-clr.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-clr.py new file mode 100644 index 000000000..2610f94f2 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-clr.py @@ -0,0 +1,60 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# There is a name clash between pythonnet's clr module/extension (which this hooks is for) and clr package that provides +# the terminal styling library (https://pypi.org/project/clr/). Therefore, we must first check if pythonnet is actually +# available... +from PyInstaller.utils.hooks import is_module_satisfies +from PyInstaller.compat import is_win + +if is_module_satisfies("pythonnet"): + # pythonnet requires both clr.pyd and Python.Runtime.dll, but the latter isn't found by PyInstaller. + import ctypes.util + from PyInstaller.log import logger + + try: + import importlib.metadata as importlib_metadata + except ImportError: + import importlib_metadata + + collected_runtime_files = [] + + # Try finding Python.Runtime.dll via distribution's file list + dist_files = importlib_metadata.files('pythonnet') + if dist_files is not None: + runtime_dll_files = [f for f in dist_files if f.match('Python.Runtime.dll')] + if len(runtime_dll_files) == 1: + runtime_dll_file = runtime_dll_files[0] + collected_runtime_files = [(runtime_dll_file.locate(), runtime_dll_file.parent.as_posix())] + logger.debug("hook-clr: Python.Runtime.dll discovered via metadata.") + elif len(runtime_dll_files) > 1: + logger.warning("hook-clr: multiple instances of Python.Runtime.dll listed in metadata - cannot resolve.") + + # Fall back to the legacy way + if not collected_runtime_files: + runtime_dll_file = ctypes.util.find_library('Python.Runtime') + if runtime_dll_file: + collected_runtime_files = [(runtime_dll_file, '.')] + logger.debug('hook-clr: Python.Runtime.dll discovered via legacy method.') + + if not collected_runtime_files: + raise Exception('Python.Runtime.dll not found') + + # On Windows, collect runtime DLL file(s) as binaries; on other OSes, collect them as data files, to prevent fatal + # errors in binary dependency analysis. + if is_win: + binaries = collected_runtime_files + else: + datas = collected_runtime_files + + # These modules are imported inside Python.Runtime.dll + hiddenimports = ["platform", "warnings"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-clr_loader.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-clr_loader.py new file mode 100644 index 000000000..dc5837a2d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-clr_loader.py @@ -0,0 +1,22 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.compat import is_win, is_cygwin +from PyInstaller.utils.hooks import collect_dynamic_libs + +# The clr-loader is used by pythonnet 3.x to load CLR (.NET) runtime. +# On Windows, the default runtime is the .NET Framework, and its corresponding +# loader requires DLLs from clr_loader\ffi\dlls to be collected. This runtime +# is supported only on Windows, so we do not have to worry about it on other +# OSes (where Mono or .NET Core are supported). +if is_win or is_cygwin: + binaries = collect_dynamic_libs("clr_loader") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-compliance_checker.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-compliance_checker.py new file mode 100644 index 000000000..df39703ef --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-compliance_checker.py @@ -0,0 +1,22 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_submodules, copy_metadata, collect_data_files + +# Collect submodules to ensure that checker plugins are collected. but avoid collecting tests sub-package. +hiddenimports = collect_submodules('compliance_checker', filter=lambda name: name != 'compliance_checker.tests') + +# Copy metadata, because checker plugins are discovered via entry-points +datas = copy_metadata('compliance_checker') + +# Include data files from compliance_checker/data sub-directory. +datas += collect_data_files('compliance_checker', includes=['data/**']) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-countrycode.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-countrycode.py new file mode 100644 index 000000000..cbaf4250d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-countrycode.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('countrycode') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-countryinfo.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-countryinfo.py new file mode 100644 index 000000000..da97625d6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-countryinfo.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata, collect_data_files + +datas = copy_metadata("countryinfo") + collect_data_files("countryinfo") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cryptography.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cryptography.py new file mode 100644 index 000000000..7edc4ed5b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cryptography.py @@ -0,0 +1,42 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for cryptography module from the Python Cryptography Authority. +""" + +import os.path +import glob + +from PyInstaller.compat import EXTENSION_SUFFIXES +from PyInstaller.utils.hooks import collect_submodules, get_module_file_attribute +from PyInstaller.utils.hooks import copy_metadata + +# get the package data so we can load the backends +datas = copy_metadata('cryptography') + +# Add the backends as hidden imports +hiddenimports = collect_submodules('cryptography.hazmat.backends') + +# Add the OpenSSL FFI binding modules as hidden imports +hiddenimports += collect_submodules('cryptography.hazmat.bindings.openssl') + ['_cffi_backend'] + + +# Include the cffi extensions as binaries in a subfolder named like the package. +# The cffi verifier expects to find them inside the package directory for +# the main module. We cannot use hiddenimports because that would add the modules +# outside the package. +binaries = [] +cryptography_dir = os.path.dirname(get_module_file_attribute('cryptography')) +for ext in EXTENSION_SUFFIXES: + ffimods = glob.glob(os.path.join(cryptography_dir, '*_cffi_*%s*' % ext)) + for f in ffimods: + binaries.append((f, 'cryptography')) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-customtkinter.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-customtkinter.py new file mode 100644 index 000000000..e4d4f7448 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-customtkinter.py @@ -0,0 +1,14 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("customtkinter") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cv2.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cv2.py new file mode 100644 index 000000000..40e40afbc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cv2.py @@ -0,0 +1,168 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +import sys +import os +import glob +import pathlib + +import PyInstaller.utils.hooks as hookutils +from PyInstaller import compat + +hiddenimports = ['numpy'] + +# On Windows, make sure that opencv_videoio_ffmpeg*.dll is bundled +binaries = [] +if compat.is_win: + # If conda is active, look for the DLL in its library path + if compat.is_conda: + libdir = os.path.join(compat.base_prefix, 'Library', 'bin') + pattern = os.path.join(libdir, 'opencv_videoio_ffmpeg*.dll') + for f in glob.glob(pattern): + + binaries.append((f, '.')) + + # Include any DLLs from site-packages/cv2 (opencv_videoio_ffmpeg*.dll + # can be found there in the PyPI version) + binaries += hookutils.collect_dynamic_libs('cv2') + +# Collect auxiliary sub-packages, such as `cv2.gapi`, `cv2.mat_wrapper`, `cv2.misc`, and `cv2.utils`. This also +# picks up submodules with valid module names, such as `cv2.config`, `cv2.load_config_py2`, and `cv2.load_config_py3`. +# Therefore, filter out `cv2.load_config_py2`. +hiddenimports += hookutils.collect_submodules('cv2', filter=lambda name: name != 'cv2.load_config_py2') + +# We also need to explicitly exclude `cv2.load_config_py2` due to it being imported in `cv2.__init__`. +excludedimports = ['cv2.load_config_py2'] + +# OpenCV loader from 4.5.4.60 requires extra config files and modules. +# We need to collect `config.py` and `load_config_py3`; to improve compatibility with PyInstaller < 5.2, where +# `module_collection_mode` (see below) is not implemented. +# We also need to collect `config-3.py` or `config-3.X.py`, whichever is available (the former is usually +# provided by PyPI wheels, while the latter seems to be used when user builds OpenCV from source). +datas = hookutils.collect_data_files( + 'cv2', + include_py_files=True, + includes=[ + 'config.py', + f'config-{sys.version_info[0]}.{sys.version_info[1]}.py', + 'config-3.py', + 'load_config_py3.py', + ], +) + + +# The OpenCV versions that attempt to perform module substitution via sys.path manipulation (== 4.5.4.58, >= 4.6.0.66) +# do not directly import the cv2.cv2 extension anymore, so in order to ensure it is collected, we would need to add it +# to hidden imports. However, when OpenCV is built by user from source, the extension is not located in the package's +# root directory, but in python-3.X sub-directory, which precludes referencing via module name due to sub-directory +# not being a valid subpackage name. Hence, emulate the OpenCV's loader and execute `config-3.py` or `config-3.X.py` +# to obtain the search path. +def find_cv2_extension(config_file): + # Prepare environment + PYTHON_EXTENSIONS_PATHS = [] + LOADER_DIR = os.path.dirname(os.path.abspath(os.path.realpath(config_file))) + + global_vars = globals().copy() + local_vars = locals().copy() + + # Exec the config file + with open(config_file) as fp: + code = compile(fp.read(), os.path.basename(config_file), 'exec') + exec(code, global_vars, local_vars) + + # Read the modified PYTHON_EXTENSIONS_PATHS + PYTHON_EXTENSIONS_PATHS = local_vars['PYTHON_EXTENSIONS_PATHS'] + if not PYTHON_EXTENSIONS_PATHS: + return None + + # Search for extension file + for extension_path in PYTHON_EXTENSIONS_PATHS: + extension_path = pathlib.Path(extension_path) + if compat.is_win: + extension_files = list(extension_path.glob('cv2*.pyd')) + else: + extension_files = list(extension_path.glob('cv2*.so')) + if extension_files: + if len(extension_files) > 1: + hookutils.logger.warning("Found multiple cv2 extension candidates: %s", extension_files) + extension_file = extension_files[0] # Take first (or hopefully the only one) + + hookutils.logger.debug("Found cv2 extension module: %s", extension_file) + + # Compute path relative to parent of config file (which should be the package's root) + dest_dir = pathlib.Path("cv2") / extension_file.parent.relative_to(LOADER_DIR) + return str(extension_file), str(dest_dir) + + hookutils.logger.warning( + "Could not find cv2 extension module! Config file: %s, search paths: %s", + config_file, PYTHON_EXTENSIONS_PATHS) + + return None + + +config_file = [ + src_path for src_path, _ in datas + if os.path.basename(src_path) in (f'config-{sys.version_info[0]}.{sys.version_info[1]}.py', 'config-3.py') +] + +if config_file: + try: + extension_info = find_cv2_extension(config_file[0]) + if extension_info: + ext_src, ext_dst = extension_info + # Due to bug in PyInstaller's TOC structure implementation (affecting PyInstaller up to latest version at + # the time of writing, 5.9), we fail to properly resolve `cv2.cv2` EXTENSION entry's destination name if + # we already have a BINARY entry with the same destination name. This results in verbatim `cv2.cv2` file + # created in application directory in addition to the proper copy in the `cv2` sub-directoy. + # Therefoe, if destination directory of the cv2 extension module is the top-level package directory, fall + # back to using hiddenimports instead. + if ext_dst == 'cv2': + # Extension found in top-level package directory; likely a PyPI wheel. + hiddenimports += ['cv2.cv2'] + else: + # Extension found in sub-directory; use BINARY entry + binaries += [extension_info] + except Exception: + hookutils.logger.warning("Failed to determine location of cv2 extension module!", exc_info=True) + + +# Mark the cv2 package to be collected in source form, bypassing PyInstaller's PYZ archive and FrozenImporter. This is +# necessary because recent versions of cv2 package attempt to perform module substritution via sys.path manipulation, +# which is incompatible with the way that FrozenImporter works. This requires pyinstaller/pyinstaller#6945, i.e., +# PyInstaller >= 5.3. On earlier versions, the following statement does nothing, and problematic cv2 versions +# (== 4.5.4.58, >= 4.6.0.66) will not work. +# +# Note that the collect_data_files() above is still necessary, because some of the cv2 loader's config scripts are not +# valid module names (e.g., config-3.py). So the two collection approaches are complementary, and any overlap in files +# (e.g., __init__.py) is handled gracefully due to PyInstaller's uniqueness constraints on collected files. +module_collection_mode = 'py' + +# In linux PyPI opencv-python wheels, the cv2 extension is linked against Qt, and the wheel bundles a basic subset of Qt +# shared libraries, plugins, and font files. This is not the case on other OSes (presumably native UI APIs are used by +# OpenCV HighGUI module), nor in the headless PyPI wheels (opencv-python-headless). +# The bundled Qt shared libraries should be picked up automatically due to binary dependency analysis, but we need to +# collect plugins and font files from the `qt` subdirectory. +if compat.is_linux: + pkg_path = pathlib.Path(hookutils.get_module_file_attribute('cv2')).parent + # Collect .ttf files fron fonts directory. + # NOTE: since we are using glob, we can skip checks for (sub)directories' existence. + qt_fonts_dir = pkg_path / 'qt' / 'fonts' + datas += [ + (str(font_file), str(font_file.parent.relative_to(pkg_path.parent))) + for font_file in qt_fonts_dir.rglob('*.ttf') + ] + # Collect .so files from plugins directory. + qt_plugins_dir = pkg_path / 'qt' / 'plugins' + binaries += [ + (str(plugin_file), str(plugin_file.parent.relative_to(pkg_path.parent))) + for plugin_file in qt_plugins_dir.rglob('*.so') + ] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cx_Oracle.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cx_Oracle.py new file mode 100644 index 000000000..37258c0a3 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cx_Oracle.py @@ -0,0 +1,13 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = ['decimal'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cytoolz.itertoolz.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cytoolz.itertoolz.py new file mode 100644 index 000000000..737c02413 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-cytoolz.itertoolz.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for the cytoolz package: https://pypi.python.org/pypi/cytoolz +# Tested with cytoolz 0.9.0 and Python 3.5.2, on Ubuntu Linux x64 + +hiddenimports = ['cytoolz.utils', 'cytoolz._signatures'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash.py new file mode 100644 index 000000000..3e3551683 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('dash') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash_bootstrap_components.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash_bootstrap_components.py new file mode 100644 index 000000000..5dc1852ed --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash_bootstrap_components.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('dash_bootstrap_components') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash_core_components.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash_core_components.py new file mode 100644 index 000000000..8147e58ec --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash_core_components.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('dash_core_components') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash_html_components.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash_html_components.py new file mode 100644 index 000000000..f85af5ea7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash_html_components.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('dash_html_components') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash_renderer.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash_renderer.py new file mode 100644 index 000000000..029dc4e24 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash_renderer.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('dash_renderer') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash_table.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash_table.py new file mode 100644 index 000000000..79b70a141 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash_table.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('dash_table') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash_uploader.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash_uploader.py new file mode 100644 index 000000000..9d7d8f267 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dash_uploader.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('dash_uploader') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dask.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dask.py new file mode 100644 index 000000000..39a6ed008 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dask.py @@ -0,0 +1,17 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2020, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Collects in-repo dask.yaml and dask-schema.yaml data files. +""" + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('dask', includes=['*.yml', '*.yaml']) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dateparser.utils.strptime.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dateparser.utils.strptime.py new file mode 100644 index 000000000..11f2b5fc3 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dateparser.utils.strptime.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for dateparser: https://pypi.org/project/dateparser/ + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = ["_strptime"] + collect_submodules('dateparser.data') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dclab.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dclab.py new file mode 100644 index 000000000..df7ef9007 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dclab.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for dclab: https://pypi.python.org/pypi/dclab + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('dclab') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-discid.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-discid.py new file mode 100644 index 000000000..fc189ce43 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-discid.py @@ -0,0 +1,40 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +import os + +from PyInstaller.utils.hooks import get_module_attribute, logger +from PyInstaller.depend.utils import _resolveCtypesImports + +binaries = [] + +# Use the _LIB_NAME attribute of discid.libdiscid to resolve the shared library name. This saves us from having to +# duplicate the name guessing logic from discid.libdiscid. +# On error, PyInstaller >= 5.0 raises exception, earlier versions return an empty string. +try: + lib_name = get_module_attribute("discid.libdiscid", "_LIB_NAME") +except Exception: + lib_name = None + +if lib_name: + lib_name = os.path.basename(lib_name) + try: + resolved_binary = _resolveCtypesImports([lib_name]) + lib_file = resolved_binary[0][1] + except Exception as e: + lib_file = None + logger.warning("Error while trying to resolve %s: %s", lib_name, e) + + if lib_file: + binaries += [(lib_file, '.')] +else: + logger.warning("Failed to determine name of libdiscid shared library from _LIB_NAME attribute of discid.libdiscid!") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-distorm3.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-distorm3.py new file mode 100644 index 000000000..d92012944 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-distorm3.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for the diStorm3 module: https://pypi.python.org/pypi/distorm3 +# Tested with distorm3 3.3.0, Python 2.7, Windows + +from PyInstaller.utils.hooks import collect_dynamic_libs + +# distorm3 dynamic library should be in the path with other dynamic libraries. +binaries = collect_dynamic_libs('distorm3', destdir='.') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dns.rdata.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dns.rdata.py new file mode 100644 index 000000000..b79ec4791 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dns.rdata.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This is hook for DNS python package dnspython. + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules('dns.rdtypes') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-docutils.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-docutils.py new file mode 100644 index 000000000..0f63de7a2 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-docutils.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_submodules, collect_data_files + +hiddenimports = (collect_submodules('docutils.languages') + + collect_submodules('docutils.writers') + + collect_submodules('docutils.parsers.rst.languages') + + collect_submodules('docutils.parsers.rst.directives')) +datas = collect_data_files('docutils') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-docx.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-docx.py new file mode 100644 index 000000000..f2a63214c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-docx.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("docx") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-docx2pdf.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-docx2pdf.py new file mode 100644 index 000000000..58ba54a11 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-docx2pdf.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later. +# ------------------------------------------------------------------ + +# Hook for docx2pdf: https://pypi.org/project/docx2pdf/ + +from PyInstaller.utils.hooks import copy_metadata, collect_data_files + +datas = copy_metadata('docx2pdf') +datas += collect_data_files('docx2pdf') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dynaconf.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dynaconf.py new file mode 100644 index 000000000..06f9b1c6f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-dynaconf.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = ['dynaconf.loaders.env_loader', + 'dynaconf.loaders.redis_loader', + 'dynaconf.loaders.vault.loader'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-easyocr.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-easyocr.py new file mode 100644 index 000000000..a868875e4 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-easyocr.py @@ -0,0 +1,18 @@ +from PyInstaller.utils.hooks import collect_data_files, get_hook_config + +# Recognition backends are imported with `importlib.import_module()`. +hiddenimports = ['easyocr.model.vgg_model', 'easyocr.model.model'] + + +def hook(hook_api): + lang_codes = get_hook_config(hook_api, 'easyocr', 'lang_codes') + if not lang_codes: + lang_codes = ['*'] + + extra_datas = list() + extra_datas += collect_data_files('easyocr', include_py_files=False, subdir='character', + includes=[f'{lang_code}_char.txt' for lang_code in lang_codes]) + extra_datas += collect_data_files('easyocr', include_py_files=False, subdir='dict', + includes=[f'{lang_code}.txt' for lang_code in lang_codes]) + + hook_api.add_datas(extra_datas) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eel.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eel.py new file mode 100644 index 000000000..1b2cb9552 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eel.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('eel') +hiddenimports = ['bottle_websocket'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-enchant.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-enchant.py new file mode 100644 index 000000000..bc9111560 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-enchant.py @@ -0,0 +1,65 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Import hook for PyEnchant. + +Tested with PyEnchant 1.6.6. +""" + +import os + +from PyInstaller.compat import is_darwin +from PyInstaller.utils.hooks import exec_statement, collect_data_files, \ + collect_dynamic_libs, get_installer + +# TODO Add Linux support +# Collect first all files that were installed directly into pyenchant +# package directory and this includes: +# - Windows: libenchat-1.dll, libenchat_ispell.dll, libenchant_myspell.dll, other +# dependent dlls and dictionaries for several languages (de, en, fr) +# - Mac OS X: usually libenchant.dylib and several dictionaries when installed via pip. +binaries = collect_dynamic_libs('enchant') +datas = collect_data_files('enchant') +excludedimports = ['enchant.tests'] + +# On OS X try to find files from Homebrew or Macports environments. +if is_darwin: + # Note: env. var. ENCHANT_PREFIX_DIR is implemented only in the development version: + # https://github.com/AbiWord/enchant + # https://github.com/AbiWord/enchant/pull/2 + # TODO Test this hook with development version of enchant. + libenchant = exec_statement(""" + from enchant._enchant import e + print(e._name) + """).strip() + + installer = get_installer('enchant') + if installer != 'pip': + # Note: Name of detected enchant library is 'libenchant.dylib'. However, it + # is just symlink to 'libenchant.1.dylib'. + binaries.append((libenchant, '.')) + + # Collect enchant backends from Macports. Using same file structure as on Windows. + backends = exec_statement(""" + from enchant import Broker + for provider in Broker().describe(): + print(provider.file)""").strip().split() + binaries.extend([(b, 'enchant/lib/enchant') for b in backends]) + + # Collect all available dictionaries from Macports. Using same file structure as on Windows. + # In Macports are available mostly hunspell (myspell) and aspell dictionaries. + libdir = os.path.dirname(libenchant) # e.g. /opt/local/lib + sharedir = os.path.join(os.path.dirname(libdir), 'share') # e.g. /opt/local/share + if os.path.exists(os.path.join(sharedir, 'enchant')): + datas.append((os.path.join(sharedir, 'enchant'), 'enchant/share/enchant')) + if os.path.exists(os.path.join(sharedir, 'enchant-2')): + datas.append((os.path.join(sharedir, 'enchant-2'), 'enchant/share/enchant-2')) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eng_to_ipa.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eng_to_ipa.py new file mode 100644 index 000000000..d57cabdb0 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eng_to_ipa.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('eng_to_ipa') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ens.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ens.py new file mode 100644 index 000000000..d524d46fe --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ens.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("ens") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-enzyme.parsers.ebml.core.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-enzyme.parsers.ebml.core.py new file mode 100644 index 000000000..ba6d4cd24 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-enzyme.parsers.ebml.core.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +enzyme: +https://github.com/Diaoul/enzyme +""" + +import os +from PyInstaller.utils.hooks import get_package_paths + +# get path of enzyme +ep = get_package_paths('enzyme') + +# add the data +data = os.path.join(ep[1], 'parsers', 'ebml', 'specs', 'matroska.xml') +datas = [(data, "enzyme/parsers/ebml/specs")] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_abi.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_abi.py new file mode 100644 index 000000000..c4e626a26 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_abi.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata("eth_abi") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_account.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_account.py new file mode 100644 index 000000000..9994b72e5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_account.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata("eth_account") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_hash.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_hash.py new file mode 100644 index 000000000..1b22c286f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_hash.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_submodules + +# The ``eth_hash.utils.load_backend`` function does a dynamic import. +hiddenimports = collect_submodules('eth_hash.backends') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_keyfile.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_keyfile.py new file mode 100644 index 000000000..8b46d42ca --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_keyfile.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata("eth_keyfile") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_rlp.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_rlp.py new file mode 100644 index 000000000..d6b8c0c9a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_rlp.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies, copy_metadata + +# Starting with v1.0.0, `eth_rlp` queries its version from metadata. +if is_module_satisfies("eth-rlp >= 1.0.0"): + datas = copy_metadata('eth-rlp') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_typing.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_typing.py new file mode 100644 index 000000000..85c2e0ee5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_typing.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +# eth-typing queries it's own version using importlib.metadata/pkg_resources. +datas = copy_metadata("eth-typing") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_utils.network.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_utils.network.py new file mode 100644 index 000000000..fcf6432ae --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_utils.network.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("eth_utils") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_utils.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_utils.py new file mode 100644 index 000000000..82e916a81 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-eth_utils.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata("eth_utils") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-exchangelib.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-exchangelib.py new file mode 100644 index 000000000..9ca618010 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-exchangelib.py @@ -0,0 +1,12 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +hiddenimports = ['tzdata'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-fabric.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-fabric.py new file mode 100644 index 000000000..c4b88635e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-fabric.py @@ -0,0 +1,22 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# +# Fabric is a high level Python (2.7, 3.4+) library designed to execute shell commands remotely over SSH, +# yielding useful Python objects in return +# +# https://docs.fabfile.org/en/latest +# +# Tested with fabric 2.6.0 + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('fabric') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-faker.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-faker.py new file mode 100644 index 000000000..7a54b482f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-faker.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_submodules, collect_data_files + +hiddenimports = collect_submodules('faker.providers') +datas = ( + collect_data_files('text_unidecode') + # noqa: W504 + collect_data_files('faker.providers', include_py_files=True) +) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-fastparquet.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-fastparquet.py new file mode 100644 index 000000000..9c8e9835f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-fastparquet.py @@ -0,0 +1,32 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +import os + +from PyInstaller.compat import is_win +from PyInstaller.utils.hooks import get_package_paths + +# In all versions for which fastparquet provides Windows wheels (>= 0.7.0), delvewheel is used, +# so we need to collect the external site-packages/fastparquet.libs directory. +if is_win: + pkg_base, pkg_dir = get_package_paths("fastparquet") + lib_dir = os.path.join(pkg_base, "fastparquet.libs") + if os.path.isdir(lib_dir): + # We collect DLLs as data files instead of binaries to suppress binary + # analysis, which would result in duplicates (because it collects a copy + # into the top-level directory instead of preserving the original layout). + # In addition to DLls, this also collects .load-order* file (required on + # python < 3.8), and ensures that fastparquet.libs directory exists (required + # on python >= 3.8 due to os.add_dll_directory call). + datas = [ + (os.path.join(lib_dir, lib_file), 'fastparquet.libs') + for lib_file in os.listdir(lib_dir) + ] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ffpyplayer.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ffpyplayer.py new file mode 100644 index 000000000..493a5c12f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ffpyplayer.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import eval_statement, collect_submodules + +hiddenimports = collect_submodules("ffpyplayer") +binaries = [] +# ffpyplayer has an internal variable tells us where the libraries it was using +for bin in eval_statement("import ffpyplayer; print(ffpyplayer.dep_bins)"): + binaries += [(bin, '.')] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-fiona.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-fiona.py new file mode 100644 index 000000000..7dcbef522 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-fiona.py @@ -0,0 +1,26 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files, is_module_satisfies + +hiddenimports = [ + "fiona._shim", + "fiona.schema", + "json", +] + +# As of fiona 1.9.0, `fiona.enums` is also a hidden import, made in cythonized `fiona.crs`. +if is_module_satisfies("fiona >= 1.9.0"): + hiddenimports.append("fiona.enums") + +# Collect data files that are part of the package (e.g., projections database) +datas = collect_data_files("fiona") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-flask_compress.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-flask_compress.py new file mode 100644 index 000000000..3343f2222 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-flask_compress.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('flask_compress') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-flask_restx.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-flask_restx.py new file mode 100644 index 000000000..4d2faaed6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-flask_restx.py @@ -0,0 +1,13 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2005-2020, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +# ----------------------------------------------------------------------------- +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('flask_restx') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-flex.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-flex.py new file mode 100644 index 000000000..ef728b9e9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-flex.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# hook for https://github.com/pipermerriam/flex + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('flex') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-flirpy.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-flirpy.py new file mode 100644 index 000000000..77348449f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-flirpy.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for flirpy, a library to interact with FLIR thermal imaging cameras and images. +https://github.com/LJMUAstroEcology/flirpy +""" + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('flirpy') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-fmpy.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-fmpy.py new file mode 100644 index 000000000..8d9622765 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-fmpy.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for FMPy, a library to simulate Functional Mockup Units (FMUs) +https://github.com/CATIA-Systems/FMPy + +Adds the data files that are required at runtime: + +- XSD schema files +- dynamic libraries for the CVode solver +- source and header files for the compilation of c-code FMUs +""" + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('fmpy') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-folium.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-folium.py new file mode 100644 index 000000000..7261987f8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-folium.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +# Collect data files (templates) +datas = collect_data_files("folium") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-freetype.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-freetype.py new file mode 100644 index 000000000..397055851 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-freetype.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_dynamic_libs + +# Collect the bundled freetype shared library, if available. +binaries = collect_dynamic_libs('freetype') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gadfly.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gadfly.py new file mode 100644 index 000000000..348f7ff27 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gadfly.py @@ -0,0 +1,13 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = ["sql_mar"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gcloud.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gcloud.py new file mode 100644 index 000000000..5af7750af --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gcloud.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('gcloud') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-geopandas.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-geopandas.py new file mode 100644 index 000000000..996190ebd --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-geopandas.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("geopandas", subdir="datasets") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gitlab.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gitlab.py new file mode 100644 index 000000000..a721ab0db --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gitlab.py @@ -0,0 +1,22 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# +# python-gitlab is a Python package providing access to the GitLab server API. +# It supports the v4 API of GitLab, and provides a CLI tool (gitlab). +# +# https://python-gitlab.readthedocs.io +# +# Tested with gitlab 3.2.0 + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('gitlab') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gmplot.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gmplot.py new file mode 100644 index 000000000..23582021e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gmplot.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2005-2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('gmplot') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gmsh.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gmsh.py new file mode 100644 index 000000000..2bed023fd --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gmsh.py @@ -0,0 +1,28 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +import os + +from PyInstaller.utils.hooks import logger, get_module_attribute + +# Query the `libpath` attribute of the `gmsh` module to obtain the path to shared library. This way, we do not need to +# duplicate the discovery logic. +try: + lib_file = get_module_attribute('gmsh', 'libpath') +except Exception: + logger.warning("Failed to query gmsh.libpath!", exc_info=True) + lib_file = None + +if lib_file and os.path.isfile(lib_file): + binaries = [(lib_file, '.')] +else: + logger.warning("Could not find gmsh shared library - gmsh will likely fail to load at run-time!") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gooey.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gooey.py new file mode 100644 index 000000000..cac2f3bbc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gooey.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Gooey GUI carries some language and images for it's UI to function. +""" + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('gooey') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.api.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.api.py new file mode 100644 index 000000000..045357730 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.api.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('google-api-core') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.api_core.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.api_core.py new file mode 100644 index 000000000..045357730 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.api_core.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('google-api-core') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.bigquery.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.bigquery.py new file mode 100644 index 000000000..08fdb8cdd --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.bigquery.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata +datas = (copy_metadata('google-cloud-bigquery') + + # the pakcage queries meta-data about ``request`` + copy_metadata('requests')) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.core.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.core.py new file mode 100644 index 000000000..2c1ee75ed --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.core.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('google-cloud-core') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.kms_v1.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.kms_v1.py new file mode 100644 index 000000000..c25db50e4 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.kms_v1.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Client library URL: https://googleapis.dev/python/cloudkms/latest/ +# Import Example for client library: +# https://cloud.google.com/kms/docs/reference/libraries#client-libraries-install-python + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('google-cloud-kms') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.pubsub_v1.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.pubsub_v1.py new file mode 100644 index 000000000..e9792908e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.pubsub_v1.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('google-cloud-pubsub') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.speech.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.speech.py new file mode 100644 index 000000000..22d15a58f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.speech.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('google-cloud-speech') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.storage.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.storage.py new file mode 100644 index 000000000..bb72e3168 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.storage.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('google-cloud-storage') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.translate.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.translate.py new file mode 100644 index 000000000..e126d2a0e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-google.cloud.translate.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('google-cloud-translate') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-googleapiclient.model.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-googleapiclient.model.py new file mode 100644 index 000000000..ce03a6977 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-googleapiclient.model.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata +from PyInstaller.utils.hooks import collect_data_files + +# googleapiclient.model queries the library version via +# pkg_resources.get_distribution("google-api-python-client").version, +# so we need to collect that package's metadata +datas = copy_metadata('google_api_python_client') +datas += collect_data_files('googleapiclient.discovery_cache', excludes=['*.txt', '**/__pycache__']) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-graphql_query.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-graphql_query.py new file mode 100755 index 000000000..2e665fc26 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-graphql_query.py @@ -0,0 +1,17 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +PyInstaller hook file for graphql_query. Tested with version 1.0.3. +""" + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('graphql_query') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-great_expectations.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-great_expectations.py new file mode 100644 index 000000000..380a2ae78 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-great_expectations.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('great_expectations') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-grpc.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-grpc.py new file mode 100644 index 000000000..0912b7fe9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-grpc.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('grpc') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gst._gst.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gst._gst.py new file mode 100644 index 000000000..e6a97a54a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gst._gst.py @@ -0,0 +1,45 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# GStreamer contains a lot of plugins. We need to collect them and bundle +# them wih the exe file. +# We also need to resolve binary dependencies of these GStreamer plugins. + +import glob +import os +from PyInstaller.compat import is_win +from PyInstaller.utils.hooks import exec_statement + +hiddenimports = ['gmodule', 'gobject'] + +statement = """ +import os +import gst +reg = gst.registry_get_default() +plug = reg.find_plugin('coreelements') +path = plug.get_filename() +print(os.path.dirname(path)) +""" + +plugin_path = exec_statement(statement) + +if is_win: + # TODO Verify that on Windows gst plugins really end with .dll. + pattern = os.path.join(plugin_path, '*.dll') +else: + # Even on OSX plugins end with '.so'. + pattern = os.path.join(plugin_path, '*.so') + +binaries = [ + (os.path.join('gst_plugins', os.path.basename(f)), f) + # 'f' contains the absolute path + for f in glob.glob(pattern)] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gtk.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gtk.py new file mode 100644 index 000000000..30d72194f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-gtk.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = ['gtkglext', 'gdkgl', 'gdkglext', 'gdk', 'gtk.gdk', 'gtk.gtkgl', + 'gtk.gtkgl._gtkgl', 'gtkgl', 'pangocairo', 'pango', 'atk', + 'gobject', 'gtk.glade', 'cairo', 'gio', + 'gtk.keysyms'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-h5py.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-h5py.py new file mode 100644 index 000000000..e76d82456 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-h5py.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for http://pypi.python.org/pypi/h5py/ +""" + +hiddenimports = ['h5py._proxy', 'h5py.utils', 'h5py.defs', 'h5py.h5ac'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-hdf5plugin.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-hdf5plugin.py new file mode 100644 index 000000000..14384f798 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-hdf5plugin.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for hdf5plugin: https://pypi.org/project/hdf5plugin/ + +from PyInstaller.utils.hooks import collect_dynamic_libs + +datas = collect_dynamic_libs("hdf5plugin") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-httplib2.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-httplib2.py new file mode 100644 index 000000000..7abfa4d6b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-httplib2.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This is needed to bundle cacerts.txt that comes with httplib2 module + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('httplib2') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-humanize.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-humanize.py new file mode 100644 index 000000000..24423c74b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-humanize.py @@ -0,0 +1,23 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +This modest package contains various common humanization utilities, like turning a number into a fuzzy human +readable duration ("3 minutes ago") or into a human readable size or throughput. + +https://pypi.org/project/humanize + +This hook was tested against humanize 3.5.0. +""" + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('humanize') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-hydra.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-hydra.py new file mode 100644 index 000000000..68c958095 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-hydra.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_submodules, collect_data_files + +# Collect core plugins. +hiddenimports = collect_submodules('hydra._internal.core_plugins') + +# Collect package's data files, such as default configuration files. +datas = collect_data_files('hydra') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ijson.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ijson.py new file mode 100644 index 000000000..87ad2b9b6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ijson.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules("ijson.backends") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-imageio.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-imageio.py new file mode 100644 index 000000000..8fbf12793 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-imageio.py @@ -0,0 +1,21 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for imageio: http://imageio.github.io/ + +from PyInstaller.utils.hooks import collect_data_files, collect_submodules + +datas = collect_data_files('imageio', subdir="resources") + +# imageio plugins are imported lazily since ImageIO version 2.11.0. +# They are very light-weight, so we can safely include all of them. +hiddenimports = collect_submodules('imageio.plugins') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-imageio_ffmpeg.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-imageio_ffmpeg.py new file mode 100644 index 000000000..ec28154fa --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-imageio_ffmpeg.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for imageio: http://imageio.github.io/ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('imageio_ffmpeg', subdir="binaries") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-iminuit.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-iminuit.py new file mode 100644 index 000000000..8dcc96b05 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-iminuit.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# add hooks for iminuit: https://github.com/scikit-hep/iminuit + +# iminuit imports subpackages through a cython module which aren't +# found by default + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = [] + +# the iminuit package contains tests which aren't needed when distributing +for mod in collect_submodules('iminuit'): + if not mod.startswith('iminuit.tests'): + hiddenimports.append(mod) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jaraco.text.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jaraco.text.py new file mode 100644 index 000000000..13573da91 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jaraco.text.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for jaraco: https://pypi.python.org/pypi/jaraco.text/3.2.0 + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('jaraco.text') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jedi.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jedi.py new file mode 100644 index 000000000..b40a45c70 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jedi.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for Jedi, a static analysis tool https://pypi.org/project/jedi/ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('jedi') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jieba.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jieba.py new file mode 100644 index 000000000..e45f2fd50 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jieba.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('jieba') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jinja2.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jinja2.py new file mode 100644 index 000000000..20453af13 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jinja2.py @@ -0,0 +1,13 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = ['jinja2.ext'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jinxed.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jinxed.py new file mode 100644 index 000000000..fe8a61a76 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jinxed.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = [ + 'jinxed.terminfo.ansicon', 'jinxed.terminfo.vtwin10' +] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jira.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jira.py new file mode 100644 index 000000000..b5179c80b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jira.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for https://pypi.python.org/pypi/jira/ +""" + +from PyInstaller.utils.hooks import copy_metadata, collect_submodules + +datas = copy_metadata('jira') +hiddenimports = collect_submodules('jira') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jsonpath_rw_ext.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jsonpath_rw_ext.py new file mode 100644 index 000000000..11c01ef61 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jsonpath_rw_ext.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('jsonpath_rw_ext') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jsonrpcserver.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jsonrpcserver.py new file mode 100644 index 000000000..016447c4d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jsonrpcserver.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This is needed to bundle request-schema.json file needed by +# jsonrpcserver package + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('jsonrpcserver') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jsonschema.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jsonschema.py new file mode 100644 index 000000000..17a612324 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jsonschema.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This is needed to bundle draft3.json and draft4.json files that come with jsonschema module. +# NOTE: with jsonschema >= 4.18.0, the specification files are part of jsonschema_specifications package, and are +# handled by the corresponding hook-jsonschema. + +from PyInstaller.utils.hooks import collect_data_files, copy_metadata + +datas = collect_data_files('jsonschema') +datas += copy_metadata('jsonschema') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jsonschema_specifications.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jsonschema_specifications.py new file mode 100644 index 000000000..036e74fca --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jsonschema_specifications.py @@ -0,0 +1,14 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files +datas = collect_data_files('jsonschema_specifications') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jupyterlab.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jupyterlab.py new file mode 100644 index 000000000..125426ff5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-jupyterlab.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('jupyterlab') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-kaleido.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-kaleido.py new file mode 100644 index 000000000..6f2ccef47 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-kaleido.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('kaleido') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-khmernltk.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-khmernltk.py new file mode 100644 index 000000000..12235b35c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-khmernltk.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('khmernltk') +hiddenimports = ['sklearn_crfsuite'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-kinterbasdb.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-kinterbasdb.py new file mode 100644 index 000000000..b8a7431da --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-kinterbasdb.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# kinterbasdb +hiddenimports = ['k_exceptions', 'services', 'typeconv_naked', + 'typeconv_backcompat', 'typeconv_23plus', + 'typeconv_datetime_stdlib', 'typeconv_datetime_mx', + 'typeconv_datetime_naked', 'typeconv_fixed_fixedpoint', + 'typeconv_fixed_stdlib', 'typeconv_text_unicode', + 'typeconv_util_isinstance', '_kinterbasdb', '_kiservices'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-langcodes.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-langcodes.py new file mode 100644 index 000000000..73e808f5d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-langcodes.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('langcodes') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-langdetect.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-langdetect.py new file mode 100644 index 000000000..636ac2d99 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-langdetect.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("langdetect") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-laonlp.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-laonlp.py new file mode 100644 index 000000000..347c63cdd --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-laonlp.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('laonlp') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lark.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lark.py new file mode 100644 index 000000000..bdcebca32 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lark.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("lark") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ldfparser.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ldfparser.py new file mode 100644 index 000000000..3d2bd0e9d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ldfparser.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +#----------------------------------------------------------------------------- + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('ldfparser') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lensfunpy.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lensfunpy.py new file mode 100644 index 000000000..abb9d614f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lensfunpy.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files +# bundle xml DB files, skip other files (like DLL files on Windows) +datas = list(filter(lambda p: p[0].endswith('.xml'), collect_data_files('lensfunpy'))) +hiddenimports = ['numpy', 'enum'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-libaudioverse.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-libaudioverse.py new file mode 100644 index 000000000..107a0ea71 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-libaudioverse.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Libaudioverse: https://github.com/libaudioverse/libaudioverse +""" + +from PyInstaller.utils.hooks import collect_dynamic_libs + +binaries = collect_dynamic_libs('libaudioverse') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-librosa.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-librosa.py new file mode 100644 index 000000000..5bd79800f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-librosa.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files, collect_submodules + +# Collect all data files from the package. These include: +# - package's and subpackages' .pyi files for `lazy_loader` +# - example data in librosa/util, required by `librosa.util.files` +# - librosa/core/intervals.msgpack, required by `librosa.core.intervals` +# +# We explicitly exclude `__pycache__` because it might contain .nbi and .nbc files from `numba` cache, which are not +# re-used by `numba` codepaths in the frozen application and are instead re-compiled in user-global cache directory. +datas = collect_data_files("librosa", excludes=['**/__pycache__']) + +# And because modules are lazily loaded, we need to collect them all. +hiddenimports = collect_submodules("librosa") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lightgbm.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lightgbm.py new file mode 100644 index 000000000..9c23a6812 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lightgbm.py @@ -0,0 +1,27 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# +# A fast, distributed, high performance gradient boosting +# (GBT, GBDT, GBRT, GBM or MART) framework based on decision +# tree algorithms, used for ranking, classification and +# many other machine learning tasks. +# +# https://github.com/microsoft/LightGBM +# +# Tested with: +# Tested on Windows 10 & macOS 10.14 with Python 3.7.5 + +from PyInstaller.utils.hooks import collect_dynamic_libs + +binaries = collect_dynamic_libs('lightgbm') +binaries += collect_dynamic_libs('sklearn') +binaries += collect_dynamic_libs('scipy') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-limits.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-limits.py new file mode 100644 index 000000000..a3e07bec4 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-limits.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("limits") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lingua.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lingua.py new file mode 100644 index 000000000..1f0e9927a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lingua.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('lingua') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-litestar.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-litestar.py new file mode 100644 index 000000000..0f9da84c6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-litestar.py @@ -0,0 +1,14 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_submodules +hiddenimports = collect_submodules('litestar.logging') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-llvmlite.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-llvmlite.py new file mode 100644 index 000000000..ef5a841ed --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-llvmlite.py @@ -0,0 +1,21 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# +# A lightweight LLVM python binding for writing JIT compilers +# https://github.com/numba/llvmlite +# +# Tested with: +# llvmlite 0.11 (Anaconda 4.1.1, Windows), llvmlite 0.13 (Linux) + +from PyInstaller.utils.hooks import collect_dynamic_libs + +binaries = collect_dynamic_libs("llvmlite") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-logilab.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-logilab.py new file mode 100644 index 000000000..07d467f18 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-logilab.py @@ -0,0 +1,26 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# +# *************************************************** +# hook-logilab.py - PyInstaller hook file for logilab +# *************************************************** +# The following was written about logilab, version 1.1.0, based on executing +# ``pip show logilab-common``. +# +# In logilab.common, line 33:: +# +# __version__ = pkg_resources.get_distribution('logilab-common').version +# +# Therefore, we need metadata for logilab. +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('logilab-common') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lxml.etree.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lxml.etree.py new file mode 100644 index 000000000..cae263635 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lxml.etree.py @@ -0,0 +1,13 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = ['lxml._elementpath', 'gzip', 'contextlib'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lxml.isoschematron.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lxml.isoschematron.py new file mode 100644 index 000000000..7e6924a90 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lxml.isoschematron.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files +import os + +# Auxiliary data for isoschematron +datas = collect_data_files('lxml', subdir=os.path.join('isoschematron', 'resources')) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lxml.objectify.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lxml.objectify.py new file mode 100644 index 000000000..138bf0780 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lxml.objectify.py @@ -0,0 +1,13 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = ['lxml.etree'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lxml.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lxml.py new file mode 100644 index 000000000..8f39d7f94 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lxml.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# +# lxml is not fully embedded when using standard hiddenimports +# see https://github.com/pyinstaller/pyinstaller/issues/5306 +# +# Tested with lxml 4.6.1 + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules('lxml') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lz4.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lz4.py new file mode 100644 index 000000000..d31195618 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-lz4.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# hook for https://github.com/python-lz4/python-lz4 + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('lz4') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-magic.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-magic.py new file mode 100644 index 000000000..bda4c2ad8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-magic.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# hook for https://pypi.org/project/python-magic-bin + +from PyInstaller.utils.hooks import collect_data_files, collect_dynamic_libs + +datas = collect_data_files('magic') +binaries = collect_dynamic_libs('magic') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mako.codegen.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mako.codegen.py new file mode 100644 index 000000000..3d85be440 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mako.codegen.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +codegen generates Python code that is then executed through exec(). +This Python code imports the following modules. +""" + +hiddenimports = ['mako.cache', 'mako.runtime', 'mako.filters'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mariadb.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mariadb.py new file mode 100644 index 000000000..a6f204a63 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mariadb.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies, collect_submodules + +# The MariaDB uses a .pyd file that imports ``decimal`` module within its +# module initialization function. On recent python versions (> 3.8), the decimal +# module seems to be picked up nevertheless (presumably due to import in some +# other module), but it is better not to rely on that, and ensure it is always +# collected as a hidden import. +hiddenimports = ['decimal'] + +# mariadb >= 1.1.0 requires several hidden imports from mariadb.constants. +# Collect them all, just to be on the safe side... +if is_module_satisfies("mariadb >= 1.1.0"): + hiddenimports += collect_submodules("mariadb.constants") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-markdown.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-markdown.py new file mode 100644 index 000000000..f0a5628cb --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-markdown.py @@ -0,0 +1,28 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import ( + collect_submodules, + copy_metadata, + is_module_satisfies, +) + +hiddenimports = collect_submodules('markdown.extensions') + +# Markdown 3.3 introduced markdown.htmlparser submodule with hidden +# dependency on html.parser +if is_module_satisfies("markdown >= 3.3"): + hiddenimports += ['html.parser'] + +# Extensions can be referenced by short names, e.g. "extra", through a mechanism +# using entry-points. Thus we need to collect the package metadata as well. +datas = copy_metadata("markdown") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mecab.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mecab.py new file mode 100644 index 000000000..cc0e78d47 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mecab.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('mecab') +datas += collect_data_files('mecab_ko_dic') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-metpy.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-metpy.py new file mode 100644 index 000000000..d184d285f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-metpy.py @@ -0,0 +1,21 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata, collect_data_files + +# MetPy requires metadata, because it queries its version via +# pkg_resources.get_distribution(__package__).version or, in newer +# versions, importlib.metadata.version(__package__) +datas = copy_metadata('metpy') + +# Collect data files +datas += collect_data_files('metpy') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-migrate.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-migrate.py new file mode 100644 index 000000000..02c52a4d8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-migrate.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# hook for https://github.com/openstack/sqlalchemy-migrate +# Since v0.12.0 importing migrate requires metadata to resolve __version__ +# attribute + +from PyInstaller.utils.hooks import copy_metadata, is_module_satisfies + +if is_module_satisfies('sqlalchemy-migrate >= 0.12.0'): + datas = copy_metadata('sqlalchemy-migrate') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mimesis.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mimesis.py new file mode 100644 index 000000000..a5d425461 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mimesis.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# The bundled 'data/' directory containing locale .json files needs to be collected (as data file). + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('mimesis') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-minecraft_launcher_lib.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-minecraft_launcher_lib.py new file mode 100644 index 000000000..71685c1ba --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-minecraft_launcher_lib.py @@ -0,0 +1,14 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("minecraft_launcher_lib") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mistune.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mistune.py new file mode 100644 index 000000000..7ac27adda --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mistune.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for nanite: https://pypi.python.org/pypi/nanite + +from PyInstaller.utils.hooks import is_module_satisfies, collect_submodules + +# As of version 3.0.0, mistune loads its plugins indirectly (but does so during package import nevertheless). +if is_module_satisfies("mistune >= 3.0.0"): + hiddenimports = collect_submodules("mistune.plugins") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mnemonic.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mnemonic.py new file mode 100644 index 000000000..4ac0cf37b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mnemonic.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('mnemonic') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-moviepy.audio.fx.all.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-moviepy.audio.fx.all.py new file mode 100644 index 000000000..19e890a77 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-moviepy.audio.fx.all.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the Apache License 2.0 +# +# The full license is available in LICENSE.APL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: Apache-2.0 +# ------------------------------------------------------------------ + +# `moviepy.audio.fx.all` programmatically imports and forwards all submodules of `moviepy.audio.fx`, so we need to +# collect those as hidden imports. +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules('moviepy.audio.fx') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-moviepy.video.fx.all.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-moviepy.video.fx.all.py new file mode 100644 index 000000000..60b2b1c3d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-moviepy.video.fx.all.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the Apache License 2.0 +# +# The full license is available in LICENSE.APL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: Apache-2.0 +# ------------------------------------------------------------------ + +# `moviepy.video.fx.all` programmatically imports and forwards all submodules of `moviepy.video.fx`, so we need to +# collect those as hidden imports. +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules('moviepy.video.fx') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mpl_toolkits.basemap.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mpl_toolkits.basemap.py new file mode 100644 index 000000000..895921dbd --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-mpl_toolkits.basemap.py @@ -0,0 +1,36 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files +from PyInstaller.compat import is_win, base_prefix + +import os + +# mpl_toolkits.basemap (tested with v.1.0.7) is shipped with auxiliary data, +# usually stored in mpl_toolkits\basemap\data and used to plot maps +datas = collect_data_files('mpl_toolkits.basemap', subdir='data') + +# check if the data has been effectively found +if len(datas) == 0: + + # - conda-specific + + if is_win: + tgt_basemap_data = os.path.join('Library', 'share', 'basemap') + src_basemap_data = os.path.join(base_prefix, 'Library', 'share', 'basemap') + + else: # both linux and darwin + tgt_basemap_data = os.path.join('share', 'basemap') + src_basemap_data = os.path.join(base_prefix, 'share', 'basemap') + + if os.path.exists(src_basemap_data): + datas.append((src_basemap_data, tgt_basemap_data)) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-msoffcrypto.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-msoffcrypto.py new file mode 100644 index 000000000..f02d57e41 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-msoffcrypto.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the Apache License 2.0 +# +# The full license is available in LICENSE.APL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: Apache-2.0 +# ------------------------------------------------------------------ +""" +msoffcrypto contains hidden metadata as of v4.12.0 +""" + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('msoffcrypto-tool') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nacl.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nacl.py new file mode 100644 index 000000000..338b6b1fd --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nacl.py @@ -0,0 +1,30 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Tested with PyNaCl 0.3.0 on Mac OS X. + +import os.path +import glob + +from PyInstaller.compat import EXTENSION_SUFFIXES +from PyInstaller.utils.hooks import collect_data_files, get_module_file_attribute + +datas = collect_data_files('nacl') + +# Include the cffi extensions as binaries in a subfolder named like the package. +binaries = [] +nacl_dir = os.path.dirname(get_module_file_attribute('nacl')) +for ext in EXTENSION_SUFFIXES: + ffimods = glob.glob(os.path.join(nacl_dir, '_lib', '*_cffi_*%s*' % ext)) + dest_dir = os.path.join('nacl', '_lib') + for f in ffimods: + binaries.append((f, dest_dir)) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-names.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-names.py new file mode 100644 index 000000000..80157a0a8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-names.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# names: generate random names +# Module PyPI Homepage: https://pypi.python.org/pypi/names/0.3.0 + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('names') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nanite.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nanite.py new file mode 100644 index 000000000..3b7794972 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nanite.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for nanite: https://pypi.python.org/pypi/nanite + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('nanite') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nbconvert.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nbconvert.py new file mode 100644 index 000000000..15b4295e6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nbconvert.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files, copy_metadata + +datas = collect_data_files('nbconvert') + +# nbconvert uses entrypoints to read nbconvert.exporters from metadata file entry_points.txt. +datas += copy_metadata('nbconvert') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nbdime.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nbdime.py new file mode 100644 index 000000000..4dac3387c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nbdime.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('nbdime') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nbformat.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nbformat.py new file mode 100644 index 000000000..e3887c0f6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nbformat.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('nbformat') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nbt.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nbt.py new file mode 100644 index 000000000..f8a285d9c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nbt.py @@ -0,0 +1,12 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +hiddenimports = ["nbt.nbt", "nbt.world", "nbt.region", "nbt.chunk"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ncclient.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ncclient.py new file mode 100644 index 000000000..42e727a0e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ncclient.py @@ -0,0 +1,23 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for ncclient. ncclient is a Python library that facilitates client-side +scripting and application development around the NETCONF protocol. +https://pypi.python.org/pypi/ncclient + +This hook was tested with ncclient 0.4.3. +""" +from PyInstaller.utils.hooks import collect_submodules + +# Modules 'ncclient.devices.*' are dynamically loaded and PyInstaller +# is not able to find them. +hiddenimports = collect_submodules('ncclient.devices') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-netCDF4.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-netCDF4.py new file mode 100644 index 000000000..8f19f7119 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-netCDF4.py @@ -0,0 +1,27 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies + +# netCDF4 (tested with v.1.1.9) has some hidden imports +hiddenimports = ['netCDF4.utils'] + +# Around netCDF4 1.4.0, netcdftime changed name to cftime +if is_module_satisfies("netCDF4 < 1.4.0"): + hiddenimports += ['netcdftime'] +else: + hiddenimports += ['cftime'] + +# Starting with netCDF 1.6.4, certifi is a hidden import made in +# netCDF4/_netCDF4.pyx. +if is_module_satisfies("netCDF4 >= 1.6.4"): + hiddenimports += ['certifi'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nltk.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nltk.py new file mode 100644 index 000000000..1f6c73a00 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nltk.py @@ -0,0 +1,27 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# hook for nltk +import nltk +import os +from PyInstaller.utils.hooks import collect_data_files + +# add datas for nltk +datas = collect_data_files('nltk', False) + +# loop through the data directories and add them +for p in nltk.data.path: + if os.path.exists(p): + datas.append((p, "nltk_data")) + +# nltk.chunk.named_entity should be included +hiddenimports = ["nltk.chunk.named_entity"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nnpy.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nnpy.py new file mode 100644 index 000000000..66df1c095 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-nnpy.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for https://pypi.org/project/nnpy/ +""" + +hiddenimports = ['_cffi_backend'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-notebook.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-notebook.py new file mode 100644 index 000000000..98cbd27f9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-notebook.py @@ -0,0 +1,27 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +import os +from PyInstaller.utils.hooks import collect_data_files, collect_submodules +from jupyter_core.paths import jupyter_config_path, jupyter_path + +# collect modules for handlers +hiddenimports = collect_submodules('notebook', filter=lambda name: name.endswith('.handles')) +hiddenimports.append('notebook.services.shutdown') + +datas = collect_data_files('notebook') + +# Collect share and etc folder for pre-installed extensions +datas += [(path, 'share/jupyter') + for path in jupyter_path() if os.path.exists(path)] +datas += [(path, 'etc/jupyter') + for path in jupyter_config_path() if os.path.exists(path)] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-numba.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-numba.py new file mode 100644 index 000000000..f713b7cba --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-numba.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# +# NumPy aware dynamic Python compiler using LLVM +# https://github.com/numba/numba +# +# Tested with: +# numba 0.26 (Anaconda 4.1.1, Windows), numba 0.28 (Linux) + +excludedimports = ["IPython", "scipy"] +hiddenimports = ["llvmlite"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-numcodecs.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-numcodecs.py new file mode 100644 index 000000000..a770c8ca1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-numcodecs.py @@ -0,0 +1,14 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# compat_ext is only imported from pyx files, so it is missed +hiddenimports = ['numcodecs.compat_ext'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-office365.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-office365.py new file mode 100644 index 000000000..ebda174ae --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-office365.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the Apache License 2.0 +# +# The full license is available in LICENSE.APL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: Apache-2.0 +# ------------------------------------------------------------------ +""" +Office365-REST-Python-Client contains xml templates that are needed by some methods +This hook ensures that all of the data used by the package is bundled +""" + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("office365") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-opencc.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-opencc.py new file mode 100644 index 000000000..fe2e4102d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-opencc.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('opencc') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-openpyxl.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-openpyxl.py new file mode 100644 index 000000000..0cff831ce --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-openpyxl.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for the openpyxl module: https://pypi.python.org/pypi/openpyxl +# Tested with openpyxl 2.3.4, Python 2.7, Windows + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('openpyxl') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-orjson.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-orjson.py new file mode 100644 index 000000000..9021a4c13 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-orjson.py @@ -0,0 +1,21 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Forced import of these modules happens on first orjson import +# and orjson is a compiled extension module. +hiddenimports = [ + 'uuid', + 'zoneinfo', + 'enum', + 'json', + 'dataclasses', +] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-osgeo.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-osgeo.py new file mode 100644 index 000000000..93ec328c7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-osgeo.py @@ -0,0 +1,81 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files +from PyInstaller.compat import is_win, is_darwin + +import os +import sys + +# The osgeo libraries require auxiliary data and may have hidden dependencies. +# There are several possible configurations on how these libraries can be +# deployed. +# This hook evaluates the cases when: +# - the `data` folder is present "in-source" (sharing the same namespace folder +# as the code libraries) +# - the `data` folder is present "out-source" (for instance, on Anaconda for +# Windows, in PYTHONHOME/Library/data) +# In this latter case, the hook also checks for the presence of `proj` library +# (e.g., on Windows in PYTHONHOME) for being added to the bundle. +# +# This hook has been tested with gdal (v.1.11.2 and 1.11.3) on: +# - Win 7 and 10 64bit +# - Ubuntu 15.04 64bit +# - Mac OS X Yosemite 10.10 +# +# TODO: Fix for gdal>=2.0.0, <2.0.3: 'NameError: global name 'help' is not defined' + +# flag used to identify an Anaconda environment +is_conda = False + +# Auxiliary data: +# +# - general case (data in 'osgeo/data/gdal'): +datas = collect_data_files('osgeo', subdir=os.path.join('data', 'gdal')) + +# check if the data has been effectively found in 'osgeo/data/gdal' +if len(datas) == 0: + + if hasattr(sys, 'real_prefix'): # check if in a virtual environment + root_path = sys.real_prefix + else: + root_path = sys.prefix + + # - conda-specific + if is_win: + tgt_gdal_data = os.path.join('Library', 'share', 'gdal') + src_gdal_data = os.path.join(root_path, 'Library', 'share', 'gdal') + if not os.path.exists(src_gdal_data): + tgt_gdal_data = os.path.join('Library', 'data') + src_gdal_data = os.path.join(root_path, 'Library', 'data') + + else: # both linux and darwin + tgt_gdal_data = os.path.join('share', 'gdal') + src_gdal_data = os.path.join(root_path, 'share', 'gdal') + + if os.path.exists(src_gdal_data): + is_conda = True + datas.append((src_gdal_data, tgt_gdal_data)) + # a real-time hook takes case to define the path for `GDAL_DATA` + +# Hidden dependencies +if is_conda: + # if `proj.4` is present, it provides additional functionalities + if is_win: + proj4_lib = os.path.join(root_path, 'proj.dll') + elif is_darwin: + proj4_lib = os.path.join(root_path, 'lib', 'libproj.dylib') + else: # assumed linux-like settings + proj4_lib = os.path.join(root_path, 'lib', 'libproj.so') + + if os.path.exists(proj4_lib): + binaries = [(proj4_lib, ".")] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pandas_flavor.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pandas_flavor.py new file mode 100644 index 000000000..177d3bdc0 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pandas_flavor.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# As of version 0.3.0, pandas_flavor uses lazy loader to import `register` and `xarray` sub-modules. In earlier +# versions, these used to be imported directly. +hiddenimports = ['pandas_flavor.register', 'pandas_flavor.xarray'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-panel.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-panel.py new file mode 100644 index 000000000..4643c57af --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-panel.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files, collect_submodules + +datas = collect_data_files("panel") + +# Some models are lazy-loaded on runtime, so we need to collect them +hiddenimports = collect_submodules("panel.models") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-parsedatetime.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-parsedatetime.py new file mode 100644 index 000000000..7351f00f9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-parsedatetime.py @@ -0,0 +1,28 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2020, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- +""" +Fixes https://github.com/pyinstaller/pyinstaller/issues/4995 + +Modules under parsedatetime.pdt_locales.* are lazily loaded using __import__. +But they are conviniently listed in parsedatetime.pdt_locales.locales. + +Tested on versions: + +- 1.1.1 +- 1.5 +- 2.0 +- 2.6 (latest) + +""" + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules("parsedatetime.pdt_locales") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-parso.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-parso.py new file mode 100644 index 000000000..a6be7344a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-parso.py @@ -0,0 +1,14 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2013-2018, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License with exception +# for distributing bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# ----------------------------------------------------------------------------- + +# Hook for Parso, a static analysis tool https://pypi.org/project/jedi/ (IPython dependency) + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('parso') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-passlib.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-passlib.py new file mode 100644 index 000000000..5b248dedc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-passlib.py @@ -0,0 +1,21 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Handlers are imported by a lazy-load proxy, based on a +# name-to-package mapping. Collect all handlers to ease packaging. +# If you want to reduce the size of your application, used +# `--exclude-module` to remove unused ones. +hiddenimports = [ + "passlib.handlers", + "passlib.handlers.digests", + "configparser", +] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-paste.exceptions.reporter.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-paste.exceptions.reporter.py new file mode 100644 index 000000000..deb4b4cd5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-paste.exceptions.reporter.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Some modules use the old-style import: explicitly include +the new module when the old one is referenced. +""" + +hiddenimports = ["email.mime.text", "email.mime.multipart"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-patsy.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-patsy.py new file mode 100644 index 000000000..9f40f4619 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-patsy.py @@ -0,0 +1,13 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = ['patsy.builtins'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pdfminer.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pdfminer.py new file mode 100644 index 000000000..c9cb79b50 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pdfminer.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('pdfminer') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pendulum.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pendulum.py new file mode 100644 index 000000000..a677db46f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pendulum.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files, collect_submodules + +# Pendulum checks for locale modules via os.path.exists before import. +# If the include_py_files option is turned off, this check fails, pendulum +# will raise a ValueError. +datas = collect_data_files("pendulum.locales", include_py_files=True) +hiddenimports = collect_submodules("pendulum.locales") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-phonenumbers.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-phonenumbers.py new file mode 100644 index 000000000..463b50c9f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-phonenumbers.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# +# Hook for the phonenumbers package: https://pypi.org/project/phonenumbers/ +# +# Tested with phonenumbers 8.9.7 and Python 3.6.1, on Ubuntu 16.04 64bit. + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules('phonenumbers') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pingouin.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pingouin.py new file mode 100644 index 000000000..924bc52b9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pingouin.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('pingouin') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pint.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pint.py new file mode 100644 index 000000000..f5a518c35 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pint.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files, copy_metadata + +datas = collect_data_files('pint') +datas += copy_metadata('pint') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pinyin.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pinyin.py new file mode 100644 index 000000000..853115c2a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pinyin.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for the pinyin package: https://pypi.python.org/pypi/pinyin +# Tested with pinyin 0.4.0 and Python 3.6.2, on Windows 10 x64. + +from PyInstaller.utils.hooks import collect_data_files + +# pinyin relies on 'Mandarin.dat' and 'cedict.txt.gz' +# for character and word translation. +datas = collect_data_files('pinyin') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-platformdirs.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-platformdirs.py new file mode 100644 index 000000000..bf72caa68 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-platformdirs.py @@ -0,0 +1,27 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.compat import is_darwin, is_win + +modules = ["platformdirs"] + +# platfromdirs contains dynamically loaded per-platform submodules. +if is_darwin: + modules.append("platformdirs.macos") +elif is_win: + modules.append("platformdirs.windows") +else: + # default to unix for all other platforms + # this includes unix, cygwin, and msys2 + modules.append("platformdirs.unix") + +hiddenimports = modules diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-plotly.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-plotly.py new file mode 100644 index 000000000..634ca70c2 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-plotly.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files +from PyInstaller.utils.hooks import collect_submodules + +datas = collect_data_files('plotly', includes=['package_data/**/*.*']) +hiddenimports = collect_submodules('plotly.validators') + ['pandas', 'cmath'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-prettytable.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-prettytable.py new file mode 100644 index 000000000..aa831d018 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-prettytable.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('prettytable') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-psutil.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-psutil.py new file mode 100644 index 000000000..789211d2e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-psutil.py @@ -0,0 +1,50 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +import os +import sys + +# see https://github.com/giampaolo/psutil/blob/release-5.9.5/psutil/_common.py#L82 +WINDOWS = os.name == "nt" +LINUX = sys.platform.startswith("linux") +MACOS = sys.platform.startswith("darwin") +FREEBSD = sys.platform.startswith(("freebsd", "midnightbsd")) +OPENBSD = sys.platform.startswith("openbsd") +NETBSD = sys.platform.startswith("netbsd") +BSD = FREEBSD or OPENBSD or NETBSD +SUNOS = sys.platform.startswith(("sunos", "solaris")) +AIX = sys.platform.startswith("aix") + +excludedimports = [ + "psutil._pslinux", + "psutil._pswindows", + "psutil._psosx", + "psutil._psbsd", + "psutil._pssunos", + "psutil._psaix", +] + +# see https://github.com/giampaolo/psutil/blob/release-5.9.5/psutil/__init__.py#L97 +if LINUX: + excludedimports.remove("psutil._pslinux") +elif WINDOWS: + excludedimports.remove("psutil._pswindows") + # see https://github.com/giampaolo/psutil/blob/release-5.9.5/psutil/_common.py#L856 + # This will exclude `curses` for windows + excludedimports.append("curses") +elif MACOS: + excludedimports.remove("psutil._psosx") +elif BSD: + excludedimports.remove("psutil._psbsd") +elif SUNOS: + excludedimports.remove("psutil._pssunos") +elif AIX: + excludedimports.remove("psutil._psaix") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-psychopy.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-psychopy.py new file mode 100644 index 000000000..d6a8cf6a7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-psychopy.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Tested on Windows 7 64bit with python 2.7.6 and PsychoPy 1.81.03 + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('psychopy') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-psycopg2.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-psycopg2.py new file mode 100644 index 000000000..4059ce575 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-psycopg2.py @@ -0,0 +1,13 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = ['mx.DateTime'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-publicsuffix2.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-publicsuffix2.py new file mode 100644 index 000000000..68f24665c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-publicsuffix2.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('publicsuffix2') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pubsub.core.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pubsub.core.py new file mode 100644 index 000000000..76eb6ca80 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pubsub.core.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('pubsub.core', include_py_files=True, excludes=['*.txt', '**/__pycache__']) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-puremagic.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-puremagic.py new file mode 100644 index 000000000..3eb8973da --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-puremagic.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("puremagic") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-py.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-py.py new file mode 100644 index 000000000..614da3b7d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-py.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules("py._path") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyarrow.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyarrow.py new file mode 100644 index 000000000..0ce8aa790 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyarrow.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for https://pypi.org/project/pyarrow/ + +from PyInstaller.utils.hooks import collect_submodules, collect_data_files, collect_dynamic_libs + +hiddenimports = collect_submodules('pyarrow', filter=lambda x: "tests" not in x) +datas = collect_data_files('pyarrow') +binaries = collect_dynamic_libs('pyarrow') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pycountry.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pycountry.py new file mode 100644 index 000000000..19be45205 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pycountry.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files, copy_metadata + +# pycountry requires the ISO databases for country data. +# Tested v1.15 on Linux/Ubuntu. +# https://pypi.python.org/pypi/pycountry +datas = copy_metadata('pycountry') + collect_data_files('pycountry') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pycparser.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pycparser.py new file mode 100644 index 000000000..e315ac2d9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pycparser.py @@ -0,0 +1,23 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# pycparser needs two modules -- lextab.py and yacctab.py -- which it +# generates at runtime if they cannot be imported. +# +# Those modules are written to the current working directory for which +# the running process may not have write permissions, leading to a runtime +# exception. +# +# This hook tells pyinstaller about those hidden imports, avoiding the +# possibility of such runtime failures. + +hiddenimports = ['pycparser.lextab', 'pycparser.yacctab'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pycrfsuite.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pycrfsuite.py new file mode 100644 index 000000000..40baa0885 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pycrfsuite.py @@ -0,0 +1,13 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = ['pycrfsuite._dumpparser', 'pycrfsuite._logparser', 'tempfile'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pydantic.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pydantic.py new file mode 100644 index 000000000..b3c148bd6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pydantic.py @@ -0,0 +1,48 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import get_module_attribute, collect_submodules +from PyInstaller.utils.hooks import is_module_satisfies + +# By default, PyPi wheels for pydantic < 2.0.0 come with all modules compiled as cython extensions, which prevents +# PyInstaller from automatically picking up the submodules. +if is_module_satisfies('pydantic >= 2.0.0'): + # The `pydantic.compiled` attribute was removed in v2. + is_compiled = False +else: + # NOTE: in PyInstaller 4.x and earlier, get_module_attribute() returns the string representation of the value + # ('True'), while in PyInstaller 5.x and later, the actual value is returned (True). + is_compiled = get_module_attribute('pydantic', 'compiled') in {'True', True} + +if is_compiled: + # Compiled version; we need to manually collect the submodules from + # pydantic... + hiddenimports = collect_submodules('pydantic') + # ... as well as the following modules from the standard library + hiddenimports += [ + 'colorsys', + 'dataclasses', + 'decimal', + 'json', + 'ipaddress', + 'pathlib', + 'uuid', + # Optional dependencies. + 'dotenv', + 'email_validator' + ] + # Older releases (prior 1.4) also import distutils.version + if not is_module_satisfies('pydantic >= 1.4'): + hiddenimports += ['distutils.version'] + # Version 1.8.0 introduced additional dependency on typing_extensions + if is_module_satisfies('pydantic >= 1.8'): + hiddenimports += ['typing_extensions'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pydivert.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pydivert.py new file mode 100644 index 000000000..39e261a63 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pydivert.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('pydivert.windivert_dll') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-io.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-io.py new file mode 100644 index 000000000..d8624134a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-io.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This hook was tested with pyexcel-io 0.5.18: +# https://github.com/pyexcel/pyexcel-io + +hiddenimports = ['pyexcel_io'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-ods.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-ods.py new file mode 100644 index 000000000..d2a78a0c2 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-ods.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This hook was tested with pyexcel-ods 0.5.6: +# https://github.com/pyexcel/pyexcel-ods + +hiddenimports = ['pyexcel_ods'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-ods3.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-ods3.py new file mode 100644 index 000000000..36fe552d5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-ods3.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This hook was tested with pyexcel-ods3 0.5.3: +# https://github.com/pyexcel/pyexcel-ods3 + +hiddenimports = ['pyexcel_ods3'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-odsr.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-odsr.py new file mode 100644 index 000000000..c8479dbdf --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-odsr.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This hook was tested with pyexcel-io 0.5.2: +# https://github.com/pyexcel/pyexcel-io + +hiddenimports = ['pyexcel_odsr'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-xls.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-xls.py new file mode 100644 index 000000000..3cf02d984 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-xls.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This hook was tested with pyexcel-xls 0.5.8: +# https://github.com/pyexcel/pyexcel-xls + +hiddenimports = ['pyexcel_xls'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-xlsx.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-xlsx.py new file mode 100644 index 000000000..1432e9ca2 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-xlsx.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This hook was tested with pyexcel-xlsx 0.4.2: +# https://github.com/pyexcel/pyexcel-xlsx + +hiddenimports = ['pyexcel_xlsx'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-xlsxw.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-xlsxw.py new file mode 100644 index 000000000..23a7af0d7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel-xlsxw.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This hook was tested with pyexcel-xlsxw 0.4.2: +# https://github.com/pyexcel/pyexcel-xlsxw + +hiddenimports = ['pyexcel_xlsxw'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel.py new file mode 100644 index 000000000..45fbda338 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel.py @@ -0,0 +1,29 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This hook was tested with pyexcel 0.5.13: +# https://github.com/pyexcel/pyexcel + +hiddenimports = [ + 'pyexcel.plugins.renderers.sqlalchemy', 'pyexcel.plugins.renderers.django', + 'pyexcel.plugins.renderers.excel', 'pyexcel.plugins.renderers._texttable', + 'pyexcel.plugins.parsers.excel', 'pyexcel.plugins.parsers.sqlalchemy', + 'pyexcel.plugins.sources.http', 'pyexcel.plugins.sources.file_input', + 'pyexcel.plugins.sources.memory_input', + 'pyexcel.plugins.sources.file_output', + 'pyexcel.plugins.sources.output_to_memory', + 'pyexcel.plugins.sources.pydata.bookdict', + 'pyexcel.plugins.sources.pydata.dictsource', + 'pyexcel.plugins.sources.pydata.arraysource', + 'pyexcel.plugins.sources.pydata.records', 'pyexcel.plugins.sources.django', + 'pyexcel.plugins.sources.sqlalchemy', 'pyexcel.plugins.sources.querysets' +] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_io.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_io.py new file mode 100644 index 000000000..c319f99ae --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_io.py @@ -0,0 +1,26 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This hook was tested with pyexcel-io 0.5.18: +# https://github.com/pyexcel/pyexcel-io + +hiddenimports = [ + 'pyexcel_io.readers.csvr', 'pyexcel_io.readers.csvz', + 'pyexcel_io.readers.tsv', 'pyexcel_io.readers.tsvz', + 'pyexcel_io.writers.csvw', 'pyexcel_io.writers.csvz', + 'pyexcel_io.writers.tsv', 'pyexcel_io.writers.tsvz', + 'pyexcel_io.readers.csvz', 'pyexcel_io.readers.tsv', + 'pyexcel_io.readers.tsvz', 'pyexcel_io.database.importers.django', + 'pyexcel_io.database.importers.sqlalchemy', + 'pyexcel_io.database.exporters.django', + 'pyexcel_io.database.exporters.sqlalchemy' +] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_ods.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_ods.py new file mode 100644 index 000000000..649f80ee0 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_ods.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This hook was tested with pyexcel-ods 0.5.6: +# https://github.com/pyexcel/pyexcel-ods + +hiddenimports = ['pyexcel_ods', 'pyexcel_ods.odsr', 'pyexcel_ods.odsw'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_ods3.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_ods3.py new file mode 100644 index 000000000..c2faaea8d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_ods3.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This hook was tested with pyexcel-ods3 0.5.3: +# https://github.com/pyexcel/pyexcel-ods3 + +hiddenimports = ['pyexcel_ods3', 'pyexcel_ods3.odsr', 'pyexcel_ods3.odsw'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_odsr.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_odsr.py new file mode 100644 index 000000000..3fe96ce2e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_odsr.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This hook was tested with pyexcel-io 0.5.2: +# https://github.com/pyexcel/pyexcel-io + +hiddenimports = ['pyexcel_odsr', 'pyexcel_odsr.odsr'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_xls.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_xls.py new file mode 100644 index 000000000..70d7b4a20 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_xls.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This hook was tested with pyexcel-xls 0.5.8: +# https://github.com/pyexcel/pyexcel-xls + +hiddenimports = ['pyexcel_xls', 'pyexcel_xls.xlsr', 'pyexcel_xls.xlsw'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_xlsx.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_xlsx.py new file mode 100644 index 000000000..fd0442918 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_xlsx.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This hook was tested with pyexcel-xlsx 0.4.2: +# https://github.com/pyexcel/pyexcel-xlsx + +hiddenimports = ['pyexcel_xlsx', 'pyexcel_xlsx.xlsxr', 'pyexcel_xlsx.xlsxw'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_xlsxw.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_xlsxw.py new file mode 100644 index 000000000..7802e6b80 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcel_xlsxw.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This hook was tested with pyexcel-xlsxw 0.4.2: +# https://github.com/pyexcel/pyexcel-xlsxw + +hiddenimports = ['pyexcel_xlsxw', 'pyexcel_xlsxw.xlsxw'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcelerate.Writer.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcelerate.Writer.py new file mode 100644 index 000000000..c565492db --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyexcelerate.Writer.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('pyexcelerate') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pygraphviz.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pygraphviz.py new file mode 100644 index 000000000..92e14eb56 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pygraphviz.py @@ -0,0 +1,66 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +import glob +import os +import shutil + +from PyInstaller.compat import is_win, is_darwin +from PyInstaller.depend.bindepend import findLibrary + +binaries = [] +datas = [] + +# List of binaries agraph.py may invoke. +progs = [ + "neato", + "dot", + "twopi", + "circo", + "fdp", + "nop", + "acyclic", + "gvpr", + "gvcolor", + "ccomps", + "sccmap", + "tred", + "sfdp", + "unflatten", +] + +if is_win: + for prog in progs: + for binary in glob.glob("c:/Program Files/Graphviz*/bin/" + prog + ".exe"): + binaries.append((binary, ".")) + for binary in glob.glob("c:/Program Files/Graphviz*/bin/*.dll"): + binaries.append((binary, ".")) + for data in glob.glob("c:/Program Files/Graphviz*/bin/config*"): + datas.append((data, ".")) +else: + # The dot binary in PATH is typically a symlink, handle that. + # graphviz_bindir is e.g. /usr/local/Cellar/graphviz/2.46.0/bin + graphviz_bindir = os.path.dirname(os.path.realpath(shutil.which("dot"))) + for binary in progs: + binaries.append((graphviz_bindir + "/" + binary, ".")) + if is_darwin: + suffix = "dylib" + # graphviz_libdir is e.g. /usr/local/Cellar/graphviz/2.46.0/lib/graphviz + graphviz_libdir = os.path.realpath(graphviz_bindir + "/../lib/graphviz") + else: + suffix = "so" + # graphviz_libdir is e.g. /usr/lib64/graphviz + graphviz_libdir = os.path.join(os.path.dirname(findLibrary('libcdt')), 'graphviz') + for binary in glob.glob(graphviz_libdir + "/*." + suffix): + binaries.append((binary, "graphviz")) + for data in glob.glob(graphviz_libdir + "/config*"): + datas.append((data, "graphviz")) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pylibmagic.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pylibmagic.py new file mode 100644 index 000000000..37aa1a808 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pylibmagic.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Pylibmagic contains data files (libmagic compiled and configurations) required to use the python-magic package. +""" + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("pylibmagic") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pylint.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pylint.py new file mode 100644 index 000000000..49e3f210b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pylint.py @@ -0,0 +1,75 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# +# ************************************************* +# hook-pylint.py - PyInstaller hook file for pylint +# ************************************************* +# The pylint package, in __pkginfo__.py, is version 1.4.3. Looking at its +# source: +# +# From checkers/__init__.py, starting at line 122:: +# +# def initialize(linter): +# """initialize linter with checkers in this package """ +# register_plugins(linter, __path__[0]) +# +# From reporters/__init__.py, starting at line 131:: +# +# def initialize(linter): +# """initialize linter with reporters in this package """ +# utils.register_plugins(linter, __path__[0]) +# +# From utils.py, starting at line 881:: +# +# def register_plugins(linter, directory): +# """load all module and package in the given directory, looking for a +# 'register' function in each one, used to register pylint checkers +# """ +# imported = {} +# for filename in os.listdir(directory): +# base, extension = splitext(filename) +# if base in imported or base == '__pycache__': +# continue +# if extension in PY_EXTS and base != '__init__' or ( +# not extension and isdir(join(directory, base))): +# try: +# module = load_module_from_file(join(directory, filename)) +# +# +# So, we need all the Python source in the ``checkers/`` and ``reporters/`` +# subdirectories, since these are run-time discovered and loaded. Therefore, +# these files are all data files. In addition, since this is a module, the +# pylint/__init__.py file must be included, since submodules must be children of +# a module. + +from PyInstaller.utils.hooks import ( + collect_data_files, collect_submodules, is_module_or_submodule, get_module_file_attribute +) + +datas = ( + [(get_module_file_attribute('pylint.__init__'), 'pylint')] + + collect_data_files('pylint.checkers', True) + + collect_data_files('pylint.reporters', True) +) + + +# Add imports from dynamically loaded modules, excluding pylint.test +# subpackage (pylint <= 2.3) and pylint.testutils submodule (pylint < 2.7) +# or subpackage (pylint >= 2.7) +def _filter_func(name): + return ( + not is_module_or_submodule(name, 'pylint.test') and + not is_module_or_submodule(name, 'pylint.testutils') + ) + + +hiddenimports = collect_submodules('pylint', _filter_func) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pylsl.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pylsl.py new file mode 100644 index 000000000..b235aa578 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pylsl.py @@ -0,0 +1,41 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +import os +from PyInstaller.utils.hooks import logger, isolated + + +def find_library(): + try: + # the import will fail it the library cannot be found + from pylsl import pylsl + + # the find_liblsl_libraries() is a generator function that yields multiple possibilities + for libfile in pylsl.find_liblsl_libraries(): + if libfile: + break + except (ImportError, ModuleNotFoundError, RuntimeError) as error: + print(error) + libfile = None + return libfile + + +# whenever a hook needs to load a 3rd party library, it needs to be done in an isolated subprocess +libfile = isolated.call(find_library) + +if libfile: + # add the liblsl library to the binaries + # it gets packaged in pylsl/lib, which is where pylsl will look first + binaries = [(libfile, os.path.join('pylsl', 'lib'))] +else: + logger.warning("liblsl shared library not found - pylsl will likely fail to work!") + binaries = [] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pymediainfo.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pymediainfo.py new file mode 100644 index 000000000..62d0354c7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pymediainfo.py @@ -0,0 +1,44 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.compat import is_win, is_darwin +from PyInstaller.utils.hooks import collect_dynamic_libs, logger + +# Collect bundled mediainfo shared library (available in Windows and macOS wheels on PyPI). +binaries = collect_dynamic_libs("pymediainfo") + +# On linux, no wheels are available, and pymediainfo uses system shared library. +if not binaries and not (is_win or is_darwin): + + def _find_system_mediainfo_library(): + import os + import ctypes.util + from PyInstaller.depend.utils import _resolveCtypesImports + + libname = ctypes.util.find_library("mediainfo") + if libname is not None: + resolved_binary = _resolveCtypesImports([os.path.basename(libname)]) + if resolved_binary: + return resolved_binary[0][1] + + try: + mediainfo_lib = _find_system_mediainfo_library() + except Exception as e: + logger.warning("Error while trying to find system-installed MediaInfo library: %s", e) + mediainfo_lib = None + + if mediainfo_lib: + # Put the library into pymediainfo sub-directory, to keep layout consistent with that of wheels. + binaries += [(mediainfo_lib, 'pymediainfo')] + +if not binaries: + logger.warning("MediaInfo shared library not found - pymediainfo will likely fail to work!") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pymorphy3.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pymorphy3.py new file mode 100644 index 000000000..c0a285482 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pymorphy3.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import can_import_module, copy_metadata, collect_data_files + +datas = copy_metadata('pymorphy3_dicts_ru') +datas += collect_data_files('pymorphy3_dicts_ru') + +hiddenimports = ['pymorphy3_dicts_ru'] + +# Check if the Ukrainian model is installed +if can_import_module('pymorphy3_dicts_uk'): + datas += copy_metadata('pymorphy3_dicts_uk') + datas += collect_data_files('pymorphy3_dicts_uk') + + hiddenimports += ['pymorphy3_dicts_uk'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pymssql.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pymssql.py new file mode 100644 index 000000000..d9c4edb6d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pymssql.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020-2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies + +hiddenimports = ["decimal"] +# In newer versions of pymssql, the _mssql was under pymssql +if is_module_satisfies("pymssql > 2.1.5"): + hiddenimports += ["pymssql._mssql", "uuid"] +else: + hiddenimports += ["_mssql"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pynput.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pynput.py new file mode 100644 index 000000000..b83ad50fd --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pynput.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules("pynput") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyodbc.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyodbc.py new file mode 100644 index 000000000..d4cf71b31 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyodbc.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import get_pyextension_imports + +# It's hard to detect imports of binary Python module without importing it. +# Let's try importing that module in a subprocess. +# TODO function get_pyextension_imports() is experimental and we need +# to evaluate its usage here and its suitability for other hooks. +hiddenimports = get_pyextension_imports('pyodbc') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyopencl.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyopencl.py new file mode 100644 index 000000000..c0df314fb --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyopencl.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for the pyopencl module: https://github.com/pyopencl/pyopencl + +from PyInstaller.utils.hooks import copy_metadata, collect_data_files + +datas = copy_metadata('pyopencl') +datas += collect_data_files('pyopencl') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pypemicro.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pypemicro.py new file mode 100755 index 000000000..a2b6e693c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pypemicro.py @@ -0,0 +1,43 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for the pypemicro module: https://github.com/nxpmicro/pypemicro + +import os +from PyInstaller.utils.hooks import get_package_paths, is_module_satisfies +from PyInstaller.log import logger +from PyInstaller.compat import is_darwin + +binaries = list() +if is_module_satisfies('pyinstaller >= 5.0'): + from PyInstaller import isolated + + @isolated.decorate + def get_safe_libs(): + from pypemicro import PyPemicro + libs = PyPemicro.get_pemicro_lib_list() + return libs + + pkg_base, pkg_dir = get_package_paths("pypemicro") + for lib in get_safe_libs(): + source_path = lib['path'] + source_name = lib['name'] + dest = os.path.relpath(source_path, pkg_base) + binaries.append((os.path.join(source_path, source_name), dest)) + if is_darwin: + libusb = os.path.join(source_path, 'libusb.dylib') + if os.path.exists(libusb): + binaries.append((libusb, dest)) + else: + logger.warning("libusb.dylib was not found for Mac OS, ignored") +else: + logger.warning("hook-pypemicro requires pyinstaller >= 5.0") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyphen.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyphen.py new file mode 100644 index 000000000..07c9668b8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyphen.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('pyphen') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyppeteer.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyppeteer.py new file mode 100644 index 000000000..18f38e6fc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyppeteer.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +# pyppeteer uses importlib.metadata to query its own version. +datas = copy_metadata("pyppeteer") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyproj.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyproj.py new file mode 100644 index 000000000..6f18b29be --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyproj.py @@ -0,0 +1,61 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +import os +import sys +from PyInstaller.utils.hooks import collect_data_files, is_module_satisfies, copy_metadata +from PyInstaller.compat import is_win, is_conda + +hiddenimports = [ + "pyproj.datadir" +] + +# Versions prior to 2.3.0 also require pyproj._datadir +if not is_module_satisfies("pyproj >= 2.3.0"): + hiddenimports += ["pyproj._datadir"] + +# Starting with version 3.0.0, pyproj._compat is needed +if is_module_satisfies("pyproj >= 3.0.0"): + hiddenimports += ["pyproj._compat"] + # Linux and macOS also require distutils. + if not is_win: + hiddenimports += ["distutils.util"] + +# Data collection +datas = collect_data_files('pyproj') + +if hasattr(sys, 'real_prefix'): # check if in a virtual environment + root_path = sys.real_prefix +else: + root_path = sys.prefix + +# - conda-specific +if is_win: + tgt_proj_data = os.path.join('Library', 'share', 'proj') + src_proj_data = os.path.join(root_path, 'Library', 'share', 'proj') + +else: # both linux and darwin + tgt_proj_data = os.path.join('share', 'proj') + src_proj_data = os.path.join(root_path, 'share', 'proj') + +if is_conda: + if os.path.exists(src_proj_data): + datas.append((src_proj_data, tgt_proj_data)) + else: + from PyInstaller.utils.hooks import logger + logger.warning("Datas for pyproj not found at:\n{}".format(src_proj_data)) + # A runtime hook defines the path for `PROJ_LIB` + +# With pyproj 3.4.0, we need to collect package's metadata due to `importlib.metadata.version(__package__)` call in +# `__init__.py`. This change was reverted in subsequent releases of pyproj, so we collect metadata only for 3.4.0. +if is_module_satisfies("pyproj == 3.4.0"): + datas += copy_metadata("pyproj") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pypsexec.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pypsexec.py new file mode 100644 index 000000000..068048999 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pypsexec.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# The bundled paexec.exe file needs to be collected (as data file; on any platform) +# because it is deployed to the remote side during execution. + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('pypsexec') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pypylon.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pypylon.py new file mode 100644 index 000000000..ab7c573fb --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pypylon.py @@ -0,0 +1,39 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# PyPylon is a tricky library to bundle. It encapsulates the pylon C++ SDK inside +# it with modified library references to make the module relocatable. +# PyInstaller is able to find those libraries and preserve the linkage for almost +# all of them. However - there is an additional linking step happening at runtime, +# when the library is creating the transport layer for the camera. This linking +# will fail with the library files modified by pyinstaller. +# As the module is already relocatable, we circumvent this issue by bundling +# pypylon as-is - for pyinstaller we treat the shared library files as just data. + +import os + +from PyInstaller.utils.hooks import collect_data_files +from PyInstaller.utils.hooks import collect_dynamic_libs + +# Collect dynamic libs as data (to prevent pyinstaller from modifying them) +datas = collect_dynamic_libs('pypylon') + +# Collect data files, looking for pypylon/pylonCXP/bin/ProducerCXP.cti, but other files may also be needed +datas += collect_data_files('pypylon') + +# Exclude the C++-extensions from automatic search, add them manually as data files +# their dependencies were already handled with collect_dynamic_libs +excludedimports = ['pypylon._pylon', 'pypylon._genicam'] +for filename, module in collect_data_files('pypylon', include_py_files=True): + if (os.path.basename(filename).startswith('_pylon.') + or os.path.basename(filename).startswith('_genicam.')): + datas += [(filename, module)] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyqtgraph.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyqtgraph.py new file mode 100644 index 000000000..46a3c6eb7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyqtgraph.py @@ -0,0 +1,43 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files, collect_submodules + +# Collect all data files, excluding the examples' data +datas = collect_data_files('pyqtgraph', excludes=['**/examples/*']) + +# pyqtgraph uses Qt-version-specific templates for the UI elements. +# There are templates for different versions of PySide and PyQt, e.g. +# +# - pyqtgraph.graphicsItems.ViewBox.axisCtrlTemplate_pyqt5 +# - pyqtgraph.graphicsItems.ViewBox.axisCtrlTemplate_pyqt6 +# - pyqtgraph.graphicsItems.ViewBox.axisCtrlTemplate_pyside2 +# - pyqtgraph.graphicsItems.ViewBox.axisCtrlTemplate_pyside6 +# - pyqtgraph.graphicsItems.PlotItem.plotConfigTemplate_pyqt5 +# - pyqtgraph.graphicsItems.PlotItem.plotConfigTemplate_pyqt6 +# - pyqtgraph.graphicsItems.PlotItem.plotConfigTemplate_pyside2 +# - pyqtgraph.graphicsItems.PlotItem.plotConfigTemplate_pyside6 +# +# To be future-proof, we collect all modules by +# using collect-submodules, and filtering the modules +# which appear to be templates. +# We need to avoid recursing into `pyqtgraph.examples`, because that +# triggers instantiation of `QApplication` (which requires X/Wayland +# session on linux). +# Tested with pyqtgraph master branch (commit c1900aa). +all_imports = collect_submodules("pyqtgraph", filter=lambda name: name != "pyqtgraph.examples") +hiddenimports = [name for name in all_imports if "Template" in name] + +# Collect the pyqtgraph/multiprocess/bootstrap.py as a module; this is required by our pyqtgraph.multiprocess runtime +# hook to handle the pyqtgraph's multiprocessing implementation. The pyqtgraph.multiprocess seems to be imported +# automatically on the import of pyqtgraph itself, so there is no point in creating a separate hook for this. +hiddenimports += ['pyqtgraph.multiprocess.bootstrap'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyshark.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyshark.py new file mode 100644 index 000000000..0c052e2bd --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyshark.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Python wrapper for pyshark(https://pypi.org/project/pyshark/) +# Tested with version 0.4.5 + +from PyInstaller.utils.hooks import collect_data_files, is_module_satisfies + +hiddenimports = ['pyshark.config'] + +if is_module_satisfies("pyshark < 0.6"): + hiddenimports += ['py._path.local', 'py._vendored_packages.iniconfig'] + if is_module_satisfies("pyshark >= 0.5"): + hiddenimports += ["py._io.terminalwriter", "py._builtin"] + +datas = collect_data_files('pyshark') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pysnmp.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pysnmp.py new file mode 100644 index 000000000..bb093611d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pysnmp.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_submodules, collect_data_files + +hiddenimports = collect_submodules('pysnmp.smi.mibs') +datas = collect_data_files('pysnmp.smi.mibs', include_py_files=True) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pystray.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pystray.py new file mode 100644 index 000000000..d7e20e62d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pystray.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_submodules +# https://github.com/moses-palmer/pystray/tree/feature-explicit-backends +# if this get merged then we don't need this hook +hiddenimports = collect_submodules("pystray") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pytest.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pytest.py new file mode 100644 index 000000000..dcb56bf0d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pytest.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for http://pypi.python.org/pypi/pytest/ +""" + +import pytest + +hiddenimports = pytest.freeze_includes() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pythainlp.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pythainlp.py new file mode 100644 index 000000000..dc6ba15d8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pythainlp.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('pythainlp') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pythoncom.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pythoncom.py new file mode 100644 index 000000000..1e4febf83 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pythoncom.py @@ -0,0 +1,31 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# pywin32 supports frozen mode; in that mode, it is looking at sys.path for pythoncomXY.dll. However, as of +# PyInstaller 5.4, we may collect that DLL into its original pywin32_system32 sub-directory as part of the +# binary dependency analysis (and add it to sys.path by means of a runtime hook). + +import pathlib + +from PyInstaller.utils.hooks import is_module_satisfies, get_pywin32_module_file_attribute + +dll_filename = get_pywin32_module_file_attribute('pythoncom') +dst_dir = '.' # Top-level application directory + +if is_module_satisfies('PyInstaller >= 5.4'): + # Try preserving the original pywin32_system directory, if applicable (it is not applicable in Anaconda, + # where the DLL is located in Library/bin). + dll_path = pathlib.Path(dll_filename) + if dll_path.parent.name == 'pywin32_system32': + dst_dir = 'pywin32_system32' + +binaries = [(dll_filename, dst_dir)] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyttsx.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyttsx.py new file mode 100644 index 000000000..4aadafa7b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyttsx.py @@ -0,0 +1,23 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +pyttsx imports drivers module based on specific platform. +Found at http://mrmekon.tumblr.com/post/5272210442/pyinstaller-and-pyttsx +""" + +hiddenimports = [ + 'drivers', + 'drivers.dummy', + 'drivers.espeak', + 'drivers.nsss', + 'drivers.sapi5', +] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyttsx3.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyttsx3.py new file mode 100644 index 000000000..992b51bcc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyttsx3.py @@ -0,0 +1,30 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# pyttsx3 conditionally imports drivers module based on specific platform. +# https://github.com/nateshmbhat/pyttsx3/blob/5a19376a94fdef6bfaef8795539e755b1f363fbf/pyttsx3/driver.py#L40-L50 + +import sys + +hiddenimports = ["pyttsx3.drivers", "pyttsx3.drivers.dummy"] + +# Take directly from the link above. +if sys.platform == 'darwin': + driverName = 'nsss' +elif sys.platform == 'win32': + driverName = 'sapi5' +else: + driverName = 'espeak' +# import driver module +name = 'pyttsx3.drivers.%s' % driverName + +hiddenimports.append(name) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyviz_comms.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyviz_comms.py new file mode 100644 index 000000000..3d5ed4714 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyviz_comms.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("pyviz_comms") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyvjoy.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyvjoy.py new file mode 100644 index 000000000..6afc37308 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pyvjoy.py @@ -0,0 +1,14 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +from PyInstaller.utils.hooks import collect_dynamic_libs + +binaries = collect_dynamic_libs("pyvjoy") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pywintypes.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pywintypes.py new file mode 100644 index 000000000..707f550db --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pywintypes.py @@ -0,0 +1,31 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# pywin32 supports frozen mode; in that mode, it is looking at sys.path for pywintypesXY.dll. However, as of +# PyInstaller 5.4, we may collect that DLL into its original pywin32_system32 sub-directory as part of the +# binary dependency analysis (and add it to sys.path by means of a runtime hook). + +import pathlib + +from PyInstaller.utils.hooks import is_module_satisfies, get_pywin32_module_file_attribute + +dll_filename = get_pywin32_module_file_attribute('pywintypes') +dst_dir = '.' # Top-level application directory + +if is_module_satisfies('PyInstaller >= 5.4'): + # Try preserving the original pywin32_system directory, if applicable (it is not applicable in Anaconda, + # where the DLL is located in Library/bin). + dll_path = pathlib.Path(dll_filename) + if dll_path.parent.name == 'pywin32_system32': + dst_dir = 'pywin32_system32' + +binaries = [(dll_filename, dst_dir)] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pywt.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pywt.py new file mode 100644 index 000000000..7f61c58a7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-pywt.py @@ -0,0 +1,21 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for https://github.com/PyWavelets/pywt + +hiddenimports = ['pywt._extensions._cwt'] + +# NOTE: There is another project `https://github.com/Knapstad/pywt installing +# a packagre `pywt`, too. This name clash is not much of a problem, even if +# this hook is picked up for the other package, since PyInstaller will simply +# skip any module added by this hook but acutally missing. If the other project +# requires a hook, too, simply add it to this file. diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-qtmodern.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-qtmodern.py new file mode 100644 index 000000000..316b16d30 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-qtmodern.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("qtmodern", includes=["**/*.qss"]) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-radicale.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-radicale.py new file mode 100644 index 000000000..f526ea27c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-radicale.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata, collect_data_files + +datas = copy_metadata('radicale') +datas += collect_data_files('radicale') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-raven.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-raven.py new file mode 100644 index 000000000..084be6639 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-raven.py @@ -0,0 +1,13 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = ['raven.events', 'raven.processors'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-rawpy.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-rawpy.py new file mode 100644 index 000000000..a4baf1b46 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-rawpy.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Python wrapper for LibRaw (https://pypi.python.org/pypi/rawpy) +# Tested with version 0.3.5 + +hiddenimports = ['numpy', 'enum'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-rdflib.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-rdflib.py new file mode 100644 index 000000000..cde99f68d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-rdflib.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules('rdflib.plugins') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-redmine.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-redmine.py new file mode 100644 index 000000000..8a393fe53 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-redmine.py @@ -0,0 +1,13 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = ['redmine.resources'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-regex.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-regex.py new file mode 100644 index 000000000..f0d8f2098 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-regex.py @@ -0,0 +1,13 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = ['warnings'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-reportlab.lib.utils.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-reportlab.lib.utils.py new file mode 100644 index 000000000..facf4a68f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-reportlab.lib.utils.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Needed for ReportLab 3 +hiddenimports = [ + 'reportlab.rl_settings', +] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-reportlab.pdfbase._fontdata.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-reportlab.pdfbase._fontdata.py new file mode 100644 index 000000000..9ea4bbf1e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-reportlab.pdfbase._fontdata.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_submodules + +# Tested on Windows 7 x64 with Python 2.7.6 x32 using ReportLab 3.0 +# This has been observed to *not* work on ReportLab 2.7 +hiddenimports = collect_submodules('reportlab.pdfbase', + lambda name: name.startswith('reportlab.pdfbase._fontdata_')) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-resampy.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-resampy.py new file mode 100644 index 000000000..67ebfd4a9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-resampy.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for resampy +from PyInstaller.utils.hooks import collect_data_files + +# resampy has two data files that need to be included. +datas = collect_data_files('resampy', False) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-rlp.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-rlp.py new file mode 100644 index 000000000..e5ce31d14 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-rlp.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies, copy_metadata + +# Starting with v4.0.0, `rlp` queries its version from metadata. +if is_module_satisfies("rlp >= 4.0.0"): + datas = copy_metadata('rlp') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-rpy2.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-rpy2.py new file mode 100644 index 000000000..1de574b53 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-rpy2.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = [ + "rpy2", + "rpy2.robjects", + "rpy2.robjects.packages", + "rpy2.situation", +] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-rtree.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-rtree.py new file mode 100644 index 000000000..6a045055f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-rtree.py @@ -0,0 +1,40 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +import pathlib + +from PyInstaller import compat +from PyInstaller.utils.hooks import collect_dynamic_libs, get_installer, get_package_paths + + +# Query the installer of the `rtree` package; in PyInstaller prior to 6.0, this might raise an exception, whereas in +# later versions, None is returned. +try: + package_installer = get_installer('rtree') +except Exception: + package_installer = None + +if package_installer == 'conda': + from PyInstaller.utils.hooks import conda + + # In Anaconda-packaged `rtree`, `libspatialindex` and `libspatialindex_c` shared libs are packaged in a separate + # `libspatialindex` package. Collect the libraries into `rtree/lib` sub-directory to simulate PyPI wheel layout. + binaries = conda.collect_dynamic_libs('libspatialindex', dest='rtree/lib', dependencies=False) +else: + # pip-installed package. The shared libs are usually placed in `rtree/lib` directory. + binaries = collect_dynamic_libs('rtree') + + # With rtree >= 1.1.0, Linux PyPI wheels place the shared library in a `Rtree.libs` top-level directory. + if compat.is_linux: + _, rtree_dir = get_package_paths('rtree') + rtree_libs_dir = pathlib.Path(rtree_dir).parent / 'Rtree.libs' + binaries += [(str(lib_file), 'Rtree.libs') for lib_file in rtree_libs_dir.glob("libspatialindex*.so*")] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sacremoses.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sacremoses.py new file mode 100644 index 000000000..ba9c49b17 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sacremoses.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('sacremoses') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-selenium.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-selenium.py new file mode 100644 index 000000000..714eb9374 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-selenium.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('selenium') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sentry_sdk.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sentry_sdk.py new file mode 100644 index 000000000..d906f5fe0 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sentry_sdk.py @@ -0,0 +1,40 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +import json +from PyInstaller.utils.hooks import exec_statement + +hiddenimports = ["sentry_sdk.integrations.stdlib", + "sentry_sdk.integrations.excepthook", + "sentry_sdk.integrations.dedupe", + "sentry_sdk.integrations.atexit", + "sentry_sdk.integrations.modules", + "sentry_sdk.integrations.argv", + "sentry_sdk.integrations.logging", + "sentry_sdk.integrations.threading"] + +statement = """ +import json +import sentry_sdk.integrations as si + +integrations = [] +if hasattr(si, '_AUTO_ENABLING_INTEGRATIONS'): + # _AUTO_ENABLING_INTEGRATIONS is a list of strings with default enabled integrations + # https://github.com/getsentry/sentry-python/blob/c6b6f2086b58ffc674df5c25a600b8a615079fb5/sentry_sdk/integrations/__init__.py#L54-L66 + + def make_integration_name(integration_name: str): + return integration_name.rsplit(".", maxsplit=1)[0] + + integrations.extend(map(make_integration_name, si._AUTO_ENABLING_INTEGRATIONS)) +print(json.dumps(integrations)) +""" + +hiddenimports.extend(json.loads(exec_statement(statement))) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-shapely.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-shapely.py new file mode 100644 index 000000000..4b39d054d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-shapely.py @@ -0,0 +1,105 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +import os +from ctypes.util import find_library + +from PyInstaller.utils.hooks import get_package_paths +from PyInstaller.utils.hooks import is_module_satisfies +from PyInstaller import compat + +# Necessary when using the vectorized subpackage +hiddenimports = ['shapely.prepared'] + +if is_module_satisfies('shapely >= 2.0.0'): + # An import made in the `shapely.geometry_helpers` extension; both `shapely.geometry_helpers` and `shapely._geos` + # extensions were introduced in v2.0.0. + hiddenimports += ['shapely._geos'] + +pkg_base, pkg_dir = get_package_paths('shapely') + +binaries = [] +datas = [] +if compat.is_win: + geos_c_dll_found = False + + # Search conda directory if conda is active, then search standard + # directory. This is the same order of precidence used in shapely. + standard_path = os.path.join(pkg_dir, 'DLLs') + lib_paths = [standard_path, os.environ['PATH']] + if compat.is_conda: + conda_path = os.path.join(compat.base_prefix, 'Library', 'bin') + lib_paths.insert(0, conda_path) + original_path = os.environ['PATH'] + try: + os.environ['PATH'] = os.pathsep.join(lib_paths) + dll_path = find_library('geos_c') + finally: + os.environ['PATH'] = original_path + if dll_path is not None: + binaries += [(dll_path, '.')] + geos_c_dll_found = True + + # Starting with shapely 1.8.1, the DLLs shipped with PyPI wheels are stored in + # site-packages/Shapely.libs instead of sub-directory in site-packages/shapely. + if is_module_satisfies("shapely >= 1.8.1"): + lib_dir = os.path.join(pkg_base, "Shapely.libs") + if os.path.isdir(lib_dir): + # We collect DLLs as data files instead of binaries to suppress binary + # analysis, which would result in duplicates (because it collects a copy + # into the top-level directory instead of preserving the original layout). + # In addition to DLls, this also collects .load-order* file (required on + # python < 3.8), and ensures that Shapely.libs directory exists (required + # on python >= 3.8 due to os.add_dll_directory call). + datas += [ + (os.path.join(lib_dir, lib_file), 'Shapely.libs') + for lib_file in os.listdir(lib_dir) + ] + + geos_c_dll_found |= any([ + os.path.basename(lib_file).startswith("geos_c") + for lib_file, _ in datas + ]) + + if not geos_c_dll_found: + raise SystemExit( + "Error: geos_c.dll not found, required by hook-shapely.py.\n" + "Please check your installation or provide a pull request to " + "PyInstaller to update hook-shapely.py.") +elif compat.is_linux and is_module_satisfies('shapely < 1.7'): + # This duplicates the libgeos*.so* files in the build. PyInstaller will + # copy them into the root of the build by default, but shapely cannot load + # them from there in linux IF shapely was installed via a whl file. The + # whl bundles its own libgeos with a different name, something like + # libgeos_c-*.so.* but shapely tries to load libgeos_c.so if there isn't a + # ./libs directory under its package. + # + # The fix for this (https://github.com/Toblerity/Shapely/pull/485) has + # been available in shapely since version 1.7. + lib_dir = os.path.join(pkg_dir, '.libs') + dest_dir = os.path.join('shapely', '.libs') + + binaries += [(os.path.join(lib_dir, f), dest_dir) for f in os.listdir(lib_dir)] +elif compat.is_darwin and is_module_satisfies('shapely >= 1.8.1'): + # In shapely 1.8.1, the libgeos_c library bundled in macOS PyPI wheels is not + # called libgeos.1.dylib anymore, but rather has a fullly-versioned name + # (e.g., libgeos_c.1.16.0.dylib). + # Shapely fails to find such a library unless it is located in the .dylibs + # directory. So we need to ensure that the libraries are collected into + # .dylibs directory; however, this will result in duplication due to binary + # analysis of the python extensions that are linked against these libraries + # as well (as that will copy the libraries to top-level directory). + lib_dir = os.path.join(pkg_dir, '.dylibs') + dest_dir = os.path.join('shapely', '.dylibs') + + if os.path.isdir(lib_dir): + binaries += [(os.path.join(lib_dir, f), dest_dir) for f in os.listdir(lib_dir)] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-shotgun_api3.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-shotgun_api3.py new file mode 100644 index 000000000..c9540e563 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-shotgun_api3.py @@ -0,0 +1,23 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +# Shotgun is using "six" to import these and +# PyInstaller does not seem to catch them correctly. +hiddenimports = ["xmlrpc", "xmlrpc.client"] + +# Collect the following files: +# /shotgun_api3/lib/httplib2/python2/cacerts.txt +# /shotgun_api3/lib/httplib2/python3/cacerts.txt +# /shotgun_api3/lib/certifi/cacert.pem +datas = collect_data_files("shotgun_api3") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-simplemma.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-simplemma.py new file mode 100644 index 000000000..3e6543a7e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-simplemma.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('simplemma') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.color.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.color.py new file mode 100644 index 000000000..ccaa2ac5f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.color.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies, collect_data_files, collect_submodules + +# As of scikit-image 0.21.0, we need to collect the __init__.pyi file for `lazy_loader`, as well as collect submodules +# due to lazy loading. +if is_module_satisfies("scikit-image >= 0.21.0"): + datas = collect_data_files("skimage.color", includes=["*.pyi"]) + hiddenimports = collect_submodules('skimage.color', filter=lambda name: name != 'skimage.color.tests') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.data.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.data.py new file mode 100644 index 000000000..7afee380c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.data.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies, collect_data_files, collect_submodules + +# As of scikit-image 0.20.0, we need to collect the __init__.pyi file for `lazy_loader`, as well as collect submodules +# due to lazy loading. +if is_module_satisfies('scikit-image >= 0.20.0'): + datas = collect_data_files("skimage.data", includes=["*.pyi"]) + hiddenimports = collect_submodules('skimage.data', filter=lambda name: name != 'skimage.data.tests') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.draw.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.draw.py new file mode 100644 index 000000000..32486fbf0 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.draw.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies, collect_data_files, collect_submodules + +# As of scikit-image 0.21.0, we need to collect the __init__.pyi file for `lazy_loader`, as well as collect submodules +# due to lazy loading. +if is_module_satisfies("scikit-image >= 0.21.0"): + datas = collect_data_files("skimage.draw", includes=["*.pyi"]) + hiddenimports = collect_submodules('skimage.draw', filter=lambda name: name != 'skimage.draw.tests') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.exposure.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.exposure.py new file mode 100644 index 000000000..f16f159c5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.exposure.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies, collect_data_files, collect_submodules + +# As of scikit-image 0.21.0, we need to collect the __init__.pyi file for `lazy_loader`, as well as collect submodules +# due to lazy loading. +if is_module_satisfies("scikit-image >= 0.21.0"): + datas = collect_data_files("skimage.exposure", includes=["*.pyi"]) + hiddenimports = collect_submodules('skimage.exposure', filter=lambda name: name != 'skimage.exposure.tests') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.feature.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.feature.py new file mode 100644 index 000000000..eb7b8b620 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.feature.py @@ -0,0 +1,22 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies, collect_data_files, collect_submodules + +# The following missing module prevents import of skimage.feature with skimage 0.17.x. +hiddenimports = ['skimage.feature._orb_descriptor_positions', ] + +# As of scikit-image 0.22.0, we need to collect the __init__.pyi file for `lazy_loader`, as well as collect submodules +# due to lazy loading. +if is_module_satisfies("scikit-image >= 0.22.0"): + datas = collect_data_files("skimage.feature", includes=["*.pyi"]) + hiddenimports = collect_submodules('skimage.feature', filter=lambda name: name != 'skimage.feature.tests') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.filters.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.filters.py new file mode 100644 index 000000000..2e4013378 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.filters.py @@ -0,0 +1,24 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies, collect_data_files, collect_submodules + +if is_module_satisfies("scikit-image >= 0.19.0"): + # In scikit-image 0.19.x, `skimage.filters` switched to lazy module loading, so we need to collect all submodules. + hiddenimports = collect_submodules('skimage.filters', filter=lambda name: name != 'skimage.filters.tests') + + # In scikit-image 0.20.0, `lazy_loader` is used, so we need to collect `__init__.pyi` file. + if is_module_satisfies("scikit-image >= 0.20.0"): + datas = collect_data_files("skimage.filters", includes=["*.pyi"]) +elif is_module_satisfies("scikit-image >= 0.18.0"): + # The following missing module prevents import of skimage.feature with skimage 0.18.x. + hiddenimports = ['skimage.filters.rank.core_cy_3d', ] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.future.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.future.py new file mode 100644 index 000000000..67b9bd622 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.future.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies, collect_data_files, collect_submodules + +# As of scikit-image 0.21.0, we need to collect the __init__.pyi file for `lazy_loader`, as well as collect submodules +# due to lazy loading. +if is_module_satisfies("scikit-image >= 0.21.0"): + datas = collect_data_files("skimage.future", includes=["*.pyi"]) + hiddenimports = collect_submodules('skimage.future', filter=lambda name: name != 'skimage.future.tests') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.graph.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.graph.py new file mode 100644 index 000000000..44ca09e06 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.graph.py @@ -0,0 +1,22 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies, collect_data_files, collect_submodules + +# The following missing module prevents import of skimage.graph with skimage 0.17.x. +hiddenimports = ['skimage.graph.heap', ] + +# As of scikit-image 0.22.0, we need to collect the __init__.pyi file for `lazy_loader`, as well as collect submodules +# due to lazy loading. +if is_module_satisfies("scikit-image >= 0.22.0"): + datas = collect_data_files("skimage.graph", includes=["*.pyi"]) + hiddenimports = collect_submodules('skimage.graph', filter=lambda name: name != 'skimage.graph.tests') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.io.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.io.py new file mode 100644 index 000000000..fade65cab --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.io.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# This hook was tested with scikit-image (skimage) 0.14.1: +# https://scikit-image.org + +from PyInstaller.utils.hooks import collect_data_files, collect_submodules + +datas = collect_data_files("skimage.io._plugins") +hiddenimports = collect_submodules('skimage.io._plugins') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.measure.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.measure.py new file mode 100644 index 000000000..ff125a2cc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.measure.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies, collect_data_files, collect_submodules + +# As of scikit-image 0.22.0, we need to collect the __init__.pyi file for `lazy_loader`, as well as collect submodules +# due to lazy loading. +if is_module_satisfies("scikit-image >= 0.22.0"): + datas = collect_data_files("skimage.measure", includes=["*.pyi"]) + hiddenimports = collect_submodules('skimage.measure', filter=lambda name: name != 'skimage.measure.tests') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.morphology.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.morphology.py new file mode 100644 index 000000000..68b65fd4e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.morphology.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files, is_module_satisfies + +# As of scikit-image 0.20.0, we need to collect .npy data files for `skimage.morphology` +if is_module_satisfies('scikit-image >= 0.20'): + datas = collect_data_files("skimage.morphology", includes=["*.npy"]) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.py new file mode 100644 index 000000000..e2567d06b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files, is_module_satisfies + +# As of scikit-image 0.20.0, we need to collect the __init__.pyi file for `lazy_loader`. +if is_module_satisfies('scikit-image >= 0.20.0'): + datas = collect_data_files("skimage", includes=["*.pyi"]) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.registration.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.registration.py new file mode 100644 index 000000000..cac50f5a7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.registration.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies, collect_data_files, collect_submodules + +# As of scikit-image 0.22.0, we need to collect the __init__.pyi file for `lazy_loader`, as well as collect submodules +# due to lazy loading. +if is_module_satisfies("scikit-image >= 0.22.0"): + datas = collect_data_files("skimage.registration", includes=["*.pyi"]) + hiddenimports = collect_submodules('skimage.registration', filter=lambda name: name != 'skimage.registration.tests') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.restoration.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.restoration.py new file mode 100644 index 000000000..ab5dba8d7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.restoration.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies, collect_data_files, collect_submodules + +# As of scikit-image 0.22.0, we need to collect the __init__.pyi file for `lazy_loader`, as well as collect submodules +# due to lazy loading. +if is_module_satisfies("scikit-image >= 0.22.0"): + datas = collect_data_files("skimage.restoration", includes=["*.pyi"]) + hiddenimports = collect_submodules('skimage.restoration', filter=lambda name: name != 'skimage.restoration.tests') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.transform.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.transform.py new file mode 100644 index 000000000..20c3fd38d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skimage.transform.py @@ -0,0 +1,24 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +from PyInstaller.utils.hooks import is_module_satisfies, collect_data_files, collect_submodules + +# Hook tested with scikit-image (skimage) 0.9.3 on Mac OS 10.9 and Windows 7 64-bit +hiddenimports = ['skimage.draw.draw', + 'skimage._shared.geometry', + 'skimage._shared.transform', + 'skimage.filters.rank.core_cy'] + +# As of scikit-image 0.22.0, we need to collect the __init__.pyi file for `lazy_loader`, as well as collect submodules +# due to lazy loading. +if is_module_satisfies("scikit-image >= 0.22.0"): + datas = collect_data_files("skimage.transform", includes=["*.pyi"]) + hiddenimports += collect_submodules('skimage.transform', filter=lambda name: name != 'skimage.transform.tests') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.cluster.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.cluster.py new file mode 100644 index 000000000..f84b650a1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.cluster.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies + +# sklearn.cluster in scikit-learn 0.23.x has a hidden import of +# threadpoolctl +if is_module_satisfies("scikit_learn >= 0.23"): + hiddenimports = ['threadpoolctl', ] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.linear_model.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.linear_model.py new file mode 100644 index 000000000..c183a8b5f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.linear_model.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies + +# sklearn.linear_model in scikit-learn 0.24.x has a hidden import of +# sklearn.utils._weight_vector +if is_module_satisfies("scikit_learn >= 0.24"): + hiddenimports = ['sklearn.utils._weight_vector', ] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.metrics.cluster.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.metrics.cluster.py new file mode 100644 index 000000000..812e00e1f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.metrics.cluster.py @@ -0,0 +1,27 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Required by scikit-learn 0.21 +from PyInstaller.utils.hooks import is_module_satisfies + +if is_module_satisfies("scikit-learn < 0.22"): + hiddenimports = [ + 'sklearn.utils.lgamma', + 'sklearn.utils.weight_vector' + ] +else: + # lgamma was removed and weight_vector privatised in 0.22. + # https://github.com/scikit-learn/scikit-learn/commit/58be9a671b0b8fcb4b75f4ae99f4469ca33a2158#diff-dbca16040fd2b85a499ba59833b37f1785c58e52d2e89ce5cdfc7fff164bd5f3 + # https://github.com/scikit-learn/scikit-learn/commit/150e82b52bf28c88c5a8b1a10f9777d0452b3ef2 + hiddenimports = [ + 'sklearn.utils._weight_vector' + ] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.metrics.pairwise.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.metrics.pairwise.py new file mode 100644 index 000000000..a76628d89 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.metrics.pairwise.py @@ -0,0 +1,21 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Required by scikit-learn 1.1.0 +from PyInstaller.utils.hooks import is_module_satisfies + +if is_module_satisfies("scikit-learn >= 1.1.0"): + hiddenimports = [ + 'sklearn.utils._heap', + 'sklearn.utils._sorting', + 'sklearn.utils._vector_sentinel', + ] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.metrics.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.metrics.py new file mode 100644 index 000000000..c15d6bcf9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.metrics.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies, collect_submodules + +hiddenimports = [] + +# Required by scikit-learn 1.0.0 +if is_module_satisfies("scikit-learn >= 1.0.0"): + hiddenimports += [ + 'sklearn.utils._typedefs', + ] + +# Required by scikit-learn 1.2.0 +if is_module_satisfies("scikit-learn >= 1.2.0"): + hiddenimports += collect_submodules("sklearn.metrics._pairwise_distances_reduction") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.neighbors.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.neighbors.py new file mode 100644 index 000000000..85af0e7d9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.neighbors.py @@ -0,0 +1,36 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies + +hiddenimports = [] + +if is_module_satisfies("scikit_learn >= 0.22"): + # 0.22 and later + hiddenimports += [ + 'sklearn.neighbors._typedefs', + 'sklearn.neighbors._quad_tree', + ] +else: + # 0.21 + hiddenimports += [ + 'sklearn.neighbors.typedefs', + 'sklearn.neighbors.quad_tree', + ] + +# The following hidden import must be added here +# (as opposed to sklearn.tree) +hiddenimports += ['sklearn.tree._criterion'] + +# Additional hidden imports introduced in v1.0.0 +if is_module_satisfies("scikit_learn >= 1.0.0"): + hiddenimports += ["sklearn.neighbors._partition_nodes"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.py new file mode 100644 index 000000000..b2bc4cb4f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Tested on Windows 10 64bit with python 3.7.1 + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('sklearn') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.tree.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.tree.py new file mode 100644 index 000000000..f27403591 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.tree.py @@ -0,0 +1,13 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = ['sklearn.tree._utils', ] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.utils.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.utils.py new file mode 100644 index 000000000..d82e91599 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sklearn.utils.py @@ -0,0 +1,13 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = ['sklearn.utils._cython_blas', ] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skyfield.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skyfield.py new file mode 100644 index 000000000..baa4e09e2 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-skyfield.py @@ -0,0 +1,14 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files +datas = collect_data_files('skyfield') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sound_lib.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sound_lib.py new file mode 100644 index 000000000..b6708260a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sound_lib.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +sound_lib: http://hg.q-continuum.net/sound_lib +""" + +from PyInstaller.utils.hooks import collect_dynamic_libs + +binaries = collect_dynamic_libs('sound_lib') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sounddevice.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sounddevice.py new file mode 100644 index 000000000..c639b194a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sounddevice.py @@ -0,0 +1,62 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +sounddevice: +https://github.com/spatialaudio/python-sounddevice/ +""" + +import pathlib + +from PyInstaller.utils.hooks import get_module_file_attribute, logger + +binaries = [] +datas = [] + +# PyPI wheels for Windows and macOS ship the sndfile shared library in _sounddevice_data directory, +# located next to the sounddevice.py module file (i.e., in the site-packages directory). +module_dir = pathlib.Path(get_module_file_attribute('sounddevice')).parent +data_dir = module_dir / '_sounddevice_data' / 'portaudio-binaries' +if data_dir.is_dir(): + destdir = str(data_dir.relative_to(module_dir)) + + # Collect the shared library (known variants: libportaudio64bit.dll, libportaudio32bit.dll, libportaudio.dylib) + for lib_file in data_dir.glob("libportaudio*.*"): + binaries += [(str(lib_file), destdir)] + + # Collect the README.md file + readme_file = data_dir / "README.md" + if readme_file.is_file(): + datas += [(str(readme_file), destdir)] +else: + # On linux and in Anaconda in all OSes, the system-installed portaudio library needs to be collected. + def _find_system_portaudio_library(): + import os + import ctypes.util + from PyInstaller.depend.utils import _resolveCtypesImports + + libname = ctypes.util.find_library("portaudio") + if libname is not None: + resolved_binary = _resolveCtypesImports([os.path.basename(libname)]) + if resolved_binary: + return resolved_binary[0][1] + + try: + lib_file = _find_system_portaudio_library() + except Exception as e: + logger.warning("Error while trying to find system-installed portaudio library: %s", e) + lib_file = None + + if lib_file: + binaries += [(lib_file, '.')] + +if not binaries: + logger.warning("portaudio shared library not found - sounddevice will likely fail to work!") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-soundfile.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-soundfile.py new file mode 100644 index 000000000..c37fcd97d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-soundfile.py @@ -0,0 +1,62 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +pysoundfile: +https://github.com/bastibe/SoundFile +""" + +import pathlib + +from PyInstaller.utils.hooks import get_module_file_attribute, logger + +binaries = [] +datas = [] + +# PyPI wheels for Windows and macOS ship the sndfile shared library in _soundfile_data directory, +# located next to the soundfile.py module file (i.e., in the site-packages directory). +module_dir = pathlib.Path(get_module_file_attribute('soundfile')).parent +data_dir = module_dir / '_soundfile_data' +if data_dir.is_dir(): + destdir = str(data_dir.relative_to(module_dir)) + + # Collect the shared library (known variants: libsndfile64bit.dll, libsndfile32bit.dll, libsndfile.dylib) + for lib_file in data_dir.glob("libsndfile*.*"): + binaries += [(str(lib_file), destdir)] + + # Collect the COPYING file + copying_file = data_dir / "COPYING" + if copying_file.is_file(): + datas += [(str(copying_file), destdir)] +else: + # On linux and in Anaconda in all OSes, the system-installed sndfile library needs to be collected. + def _find_system_sndfile_library(): + import os + import ctypes.util + from PyInstaller.depend.utils import _resolveCtypesImports + + libname = ctypes.util.find_library("sndfile") + if libname is not None: + resolved_binary = _resolveCtypesImports([os.path.basename(libname)]) + if resolved_binary: + return resolved_binary[0][1] + + try: + lib_file = _find_system_sndfile_library() + except Exception as e: + logger.warning("Error while trying to find system-installed sndfile library: %s", e) + lib_file = None + + if lib_file: + binaries += [(lib_file, '.')] + +if not binaries: + logger.warning("sndfile shared library not found - soundfile will likely fail to work!") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-spacy.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-spacy.py new file mode 100644 index 000000000..891715bb9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-spacy.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the Apache License 2.0 +# +# The full license is available in LICENSE.APL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: Apache-2.0 +# ------------------------------------------------------------------ +""" +Spacy contains hidden imports and data files which are needed to import it +""" + +from PyInstaller.utils.hooks import collect_data_files, collect_submodules + +datas = collect_data_files("spacy") +hiddenimports = collect_submodules("spacy") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-speech_recognition.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-speech_recognition.py new file mode 100644 index 000000000..df022b36b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-speech_recognition.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for speech_recognition: https://pypi.python.org/pypi/SpeechRecognition/ +# Tested on Windows 8.1 x64 with SpeechRecognition 1.5 + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("speech_recognition") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-spiceypy.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-spiceypy.py new file mode 100644 index 000000000..92170811c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-spiceypy.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for spiceypy: https://pypi.org/project/spiceypy/ +# Tested on Ubuntu 20.04 with spiceypy 5.1.1 + +from PyInstaller.utils.hooks import collect_dynamic_libs + +binaries = collect_dynamic_libs("spiceypy") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-spnego.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-spnego.py new file mode 100644 index 000000000..ffb56ce88 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-spnego.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules('spnego') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-srsly.msgpack._packer.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-srsly.msgpack._packer.py new file mode 100644 index 000000000..39c291a00 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-srsly.msgpack._packer.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the Apache License 2.0 +# +# The full license is available in LICENSE.APL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: Apache-2.0 +# ------------------------------------------------------------------ +""" +srsly.msgpack._packer contains hidden imports which are needed to import it +This hook was created to make spacy work correctly. +""" + +hiddenimports = ['srsly.msgpack.util'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sspilib.raw.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sspilib.raw.py new file mode 100644 index 000000000..01ef01366 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sspilib.raw.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_submodules + +# This seems to be required in python <= 3.9; in later versions, the `dataclasses` module ends up included via a +# different import chain. But for the sake of consistency, keep the hiddenimport for all python versions. +hiddenimports = ['dataclasses'] + +# Collect submodules of `sspilib.raw` - most of which are cythonized extensions. +hiddenimports += collect_submodules('sspilib.raw') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-statsmodels.tsa.statespace.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-statsmodels.tsa.statespace.py new file mode 100644 index 000000000..977d2e923 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-statsmodels.tsa.statespace.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules('statsmodels.tsa.statespace._filters') \ + + collect_submodules('statsmodels.tsa.statespace._smoothers') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-stdnum.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-stdnum.py new file mode 100644 index 000000000..e16f95afa --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-stdnum.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2022 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Collect data files that are required by some of the stdnum's sub-modules +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("stdnum") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-storm.database.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-storm.database.py new file mode 100644 index 000000000..c23bd8bbb --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-storm.database.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for storm ORM. +""" + +hiddenimports = [ + 'storm.databases.sqlite', + 'storm.databases.postgres', + 'storm.databases.mysql' +] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sudachipy.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sudachipy.py new file mode 100644 index 000000000..4949bfe17 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sudachipy.py @@ -0,0 +1,30 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import can_import_module, collect_data_files, is_module_satisfies + +datas = collect_data_files('sudachipy') +hiddenimports = [] + +# In v0.6.8, `sudachipy.config` and `sudachipy.errors` modules were added, and are referenced from binary extension. +if is_module_satisfies('sudachipy >= 0.6.8'): + hiddenimports += [ + 'sudachipy.config', + 'sudachipy.errors', + ] + +# Check which types of dictionary are installed +for sudachi_dict in ['sudachidict_small', 'sudachidict_core', 'sudachidict_full']: + if can_import_module(sudachi_dict): + datas += collect_data_files(sudachi_dict) + + hiddenimports += [sudachi_dict] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sunpy.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sunpy.py new file mode 100644 index 000000000..bdf9e08c6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sunpy.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files, collect_submodules, copy_metadata + +hiddenimports = collect_submodules("sunpy", filter=lambda x: "tests" not in x.split(".")) +datas = collect_data_files("sunpy", excludes=['**/tests/', '**/test/']) +datas += collect_data_files("drms") +datas += copy_metadata("sunpy") + +# Note : sunpy > 3.1.0 comes with it's own hook for running tests. diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-swagger_spec_validator.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-swagger_spec_validator.py new file mode 100644 index 000000000..d59e8e920 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-swagger_spec_validator.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("swagger_spec_validator") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sympy.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sympy.py new file mode 100644 index 000000000..f934fd75d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-sympy.py @@ -0,0 +1,22 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import logger, is_module_satisfies + +# With sympy 1.12, PyInstaller's modulegraph analysis hits the recursion limit. +# So, unless the user has already done so, increase it automatically. +if is_module_satisfies('sympy >= 1.12'): + import sys + new_limit = 5000 + if sys.getrecursionlimit() < new_limit: + logger.info("hook-sympy: raising recursion limit to %d", new_limit) + sys.setrecursionlimit(new_limit) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-tableauhyperapi.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-tableauhyperapi.py new file mode 100644 index 000000000..eef8ddea3 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-tableauhyperapi.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_dynamic_libs + +binaries = collect_dynamic_libs("tableauhyperapi") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-tables.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-tables.py new file mode 100644 index 000000000..6cb42d5f5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-tables.py @@ -0,0 +1,14 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# PyTables is a package for managing hierarchical datasets +hiddenimports = ["tables._comp_lzo", "tables._comp_bzip2"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-tcod.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-tcod.py new file mode 100644 index 000000000..fdee06bc5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-tcod.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for https://github.com/libtcod/python-tcod +""" +from PyInstaller.utils.hooks import collect_dynamic_libs + +hiddenimports = ['_cffi_backend'] + +# Install shared libraries to the working directory. +binaries = collect_dynamic_libs('tcod', destdir='.') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-tensorflow.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-tensorflow.py new file mode 100644 index 000000000..faf220c0b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-tensorflow.py @@ -0,0 +1,83 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import is_module_satisfies, \ + collect_submodules, collect_data_files + +tf_pre_1_15_0 = is_module_satisfies("tensorflow < 1.15.0") +tf_post_1_15_0 = is_module_satisfies("tensorflow >= 1.15.0") +tf_pre_2_0_0 = is_module_satisfies("tensorflow < 2.0.0") +tf_pre_2_2_0 = is_module_satisfies("tensorflow < 2.2.0") + +# Exclude from data collection: +# - development headers in include subdirectory +# - XLA AOT runtime sources +# - libtensorflow_framework and libtensorflow_cc (since TF 2.12) shared libraries (to avoid duplication) +# - import library (.lib) files (Windows-only) +data_excludes = [ + "include", + "xla_aot_runtime_src", + "libtensorflow_framework.*", + "libtensorflow_cc.*", + "**/*.lib", +] + +# Under tensorflow 2.3.0 (the most recent version at the time of writing), +# _pywrap_tensorflow_internal extension module ends up duplicated; once +# as an extension, and once as a shared library. In addition to increasing +# program size, this also causes problems on macOS, so we try to prevent +# the extension module "variant" from being picked up. +# +# See pyinstaller/pyinstaller-hooks-contrib#49 for details. +excluded_submodules = ['tensorflow.python._pywrap_tensorflow_internal'] + + +def _submodules_filter(x): + return x not in excluded_submodules + + +if tf_pre_1_15_0: + # 1.14.x and earlier: collect everything from tensorflow + hiddenimports = collect_submodules('tensorflow', + filter=_submodules_filter) + datas = collect_data_files('tensorflow', excludes=data_excludes) +elif tf_post_1_15_0 and tf_pre_2_2_0: + # 1.15.x - 2.1.x: collect everything from tensorflow_core + hiddenimports = collect_submodules('tensorflow_core', + filter=_submodules_filter) + datas = collect_data_files('tensorflow_core', excludes=data_excludes) + + # Under 1.15.x, we seem to fail collecting a specific submodule, + # and need to add it manually... + if tf_post_1_15_0 and tf_pre_2_0_0: + hiddenimports += \ + ['tensorflow_core._api.v1.compat.v2.summary.experimental'] +else: + # 2.2.0 and newer: collect everything from tensorflow again + hiddenimports = collect_submodules('tensorflow', + filter=_submodules_filter) + datas = collect_data_files('tensorflow', excludes=data_excludes) + + # From 2.6.0 on, we also need to explicitly collect keras (due to + # lazy mapping of tensorflow.keras.xyz -> keras.xyz) + if is_module_satisfies("tensorflow >= 2.6.0"): + hiddenimports += collect_submodules('keras') + + # Starting with 2.14.0, we need `ml_dtypes` among hidden imports. + if is_module_satisfies("tensorflow >= 2.14.0"): + hiddenimports += ['ml_dtypes'] + +excludedimports = excluded_submodules + +# Suppress warnings for missing hidden imports generated by this hook. +# Requires PyInstaller > 5.1 (with pyinstaller/pyinstaller#6914 merged); no-op otherwise. +warn_on_missing_hiddenimports = False diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-text_unidecode.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-text_unidecode.py new file mode 100644 index 000000000..bea0edfcd --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-text_unidecode.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# ----------------------------------------------------------------------------- +""" +text-unidecode: +https://github.com/kmike/text-unidecode/ +""" + +import os +from PyInstaller.utils.hooks import get_package_paths + +package_path = get_package_paths("text_unidecode") +data_bin_path = os.path.join(package_path[1], "data.bin") + +if os.path.exists(data_bin_path): + datas = [(data_bin_path, 'text_unidecode')] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-textdistance.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-textdistance.py new file mode 100644 index 000000000..7e97c9d2f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-textdistance.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for textdistance: https://pypi.org/project/textdistance/4.1.3/ + +from PyInstaller.utils.hooks import collect_all + +datas, binaries, hiddenimports = collect_all('textdistance') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-thinc.backends.numpy_ops.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-thinc.backends.numpy_ops.py new file mode 100644 index 000000000..f63bb6e1e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-thinc.backends.numpy_ops.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the Apache License 2.0 +# +# The full license is available in LICENSE.APL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: Apache-2.0 +# ------------------------------------------------------------------ +""" +thinc.banckends.numpy_ops contains hidden imports which are needed to import it +This hook was created to make spacy work correctly. +""" + +hiddenimports = ['cymem.cymem', 'preshed.maps', 'blis.py'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-thinc.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-thinc.py new file mode 100644 index 000000000..45bd8edd6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-thinc.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the Apache License 2.0 +# +# The full license is available in LICENSE.APL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: Apache-2.0 +# ------------------------------------------------------------------ +""" +Thinc contains data files and hidden imports. This hook was created to make spacy work correctly. +""" +from PyInstaller.utils.hooks import collect_data_files, collect_submodules + +datas = collect_data_files("thinc") +hiddenimports = collect_submodules("thinc") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-timezonefinder.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-timezonefinder.py new file mode 100644 index 000000000..19bc34d99 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-timezonefinder.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('timezonefinder') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-tinycss2.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-tinycss2.py new file mode 100644 index 000000000..38573b4bd --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-tinycss2.py @@ -0,0 +1,21 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for tinycss2. tinycss2 is a low-level CSS parser and generator. +https://github.com/Kozea/tinycss2 +""" +from PyInstaller.utils.hooks import collect_data_files + + +# Hook no longer required for tinycss2 >= 1.0.0 +def hook(hook_api): + hook_api.add_datas(collect_data_files(hook_api.__name__)) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-torch.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-torch.py new file mode 100644 index 000000000..b7ddadc74 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-torch.py @@ -0,0 +1,51 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import ( + logger, + collect_data_files, + is_module_satisfies, + collect_dynamic_libs, + collect_submodules, + get_package_paths, +) + +if is_module_satisfies("PyInstaller >= 6.0"): + module_collection_mode = "pyz+py" + warn_on_missing_hiddenimports = False + + datas = collect_data_files( + "torch", + excludes=[ + "**/*.h", + "**/*.hpp", + "**/*.cuh", + "**/*.lib", + "**/*.cpp", + "**/*.pyi", + "**/*.cmake", + ], + ) + binaries = collect_dynamic_libs("torch") + hiddenimports = collect_submodules("torch") +else: + datas = [(get_package_paths("torch")[1], "torch")] + +# With torch 2.0.0, PyInstaller's modulegraph analysis hits the recursion limit. +# So, unless the user has already done so, increase it automatically. +if is_module_satisfies("torch >= 2.0.0"): + import sys + + new_limit = 5000 + if sys.getrecursionlimit() < new_limit: + logger.info("hook-torch: raising recursion limit to %d", new_limit) + sys.setrecursionlimit(new_limit) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-torchvision.ops.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-torchvision.ops.py new file mode 100644 index 000000000..31ce0ab34 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-torchvision.ops.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Functions from torchvision.ops.* modules require torchvision._C +# extension module, which PyInstaller fails to pick up automatically... +hiddenimports = ['torchvision._C'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-trimesh.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-trimesh.py new file mode 100644 index 000000000..961591ef9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-trimesh.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +# Collect the *.json resource file. +# This issue is reported in here: https://github.com/mikedh/trimesh/issues/412 +datas = collect_data_files('trimesh') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ttkthemes.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ttkthemes.py new file mode 100644 index 000000000..cc2f7bb26 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ttkthemes.py @@ -0,0 +1,56 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for use with the ttkthemes package + +ttkthemes depends on a large set of image and Tcl-code files contained +within its package directory. These are not imported, and thus this hook +is required so they are copied. + +The file structure of the ttkthemes package folder is: +ttkthemes +├───advanced +| └───*.tcl +├───themes +| ├───theme1 +| | ├───theme1 +| | | └───*.gif +| | └───theme1.tcl +| ├───theme2 +| ├───... +| └───pkgIndex.tcl +├───png +└───gif + +The ``themes`` directory contains themes which only have a universal +image version (either base64 encoded in the theme files or GIF), while +``png`` and ``gif`` contain the PNG and GIF versions of the themes which +support both respectively. + +All of this must be copied, as the package expects all the data to be +present and only checks what themes to load at runtime. + +Tested hook on Linux (Ubuntu 18.04, Python 3.6 minimal venv) and on +Windows 7 (Python 3.7, minimal system-wide installation). + +>>> from tkinter import ttk +>>> from ttkthemes import ThemedTk +>>> +>>> +>>> if __name__ == '__main__': +>>> window = ThemedTk(theme="plastik") +>>> ttk.Button(window, text="Quit", command=window.destroy).pack() +>>> window.mainloop() +""" +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("ttkthemes") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ttkwidgets.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ttkwidgets.py new file mode 100644 index 000000000..a08680102 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-ttkwidgets.py @@ -0,0 +1,38 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for use with the ttkwidgets package + +ttkwidgets provides a set of cross-platform widgets for Tkinter/ttk, +some of which depend on image files in order to function properly. + +These images files are all provided in the `ttkwidgets/assets` folder, +which has to be copied by PyInstaller. + +This hook has been tested on Ubuntu 18.04 (Python 3.6.8 venv) and +Windows 7 (Python 3.5.4 system-wide). + +>>> import tkinter as tk +>>> from ttkwidgets import CheckboxTreeview +>>> +>>> window = tk.Tk() +>>> tree = CheckboxTreeview(window) +>>> tree.insert("", tk.END, "test", text="Hello World!") +>>> tree.insert("test", tk.END, "test2", text="Hello World again!") +>>> tree.insert("test", tk.END, "test3", text="Hello World again again!") +>>> tree.pack() +>>> window.mainloop() +""" + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files("ttkwidgets") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-tzdata.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-tzdata.py new file mode 100644 index 000000000..9a79021f9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-tzdata.py @@ -0,0 +1,22 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files, collect_submodules + +# Collect timezone data files +datas = collect_data_files("tzdata") + +# Collect submodules; each data subdirectory is in fact a package +# (e.g., zoneinfo.Europe), so we need its __init__.py for data files +# (e.g., zoneinfo/Europe/Ljubljana) to be discoverable via +# importlib.resources +hiddenimports = collect_submodules("tzdata") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-u1db.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-u1db.py new file mode 100644 index 000000000..ec8c17ce7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-u1db.py @@ -0,0 +1,31 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Pyinstaller hook for u1db module + +This hook was tested with: +- u1db 0.1.4 : https://launchpad.net/u1db +- Python 2.7.10 +- Linux Debian GNU/Linux unstable (sid) + +Test script used for testing: + + import u1db + db = u1db.open("mydb1.u1db", create=True) + doc = db.create_doc({"key": "value"}, doc_id="testdoc") + print doc.content + print doc.doc_id +""" + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('u1db') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-umap.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-umap.py new file mode 100644 index 000000000..7b81814c3 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-umap.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('umap-learn') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-unidecode.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-unidecode.py new file mode 100644 index 000000000..ad532c040 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-unidecode.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for the unidecode package: https://pypi.python.org/pypi/unidecode +# Tested with Unidecode 0.4.21 and Python 3.6.2, on Windows 10 x64. + +from PyInstaller.utils.hooks import collect_submodules + +# Unidecode dynamically imports modules with relevant character mappings. +# Non-ASCII characters are ignored if the mapping files are not found. +hiddenimports = collect_submodules('unidecode') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-uniseg.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-uniseg.py new file mode 100644 index 000000000..dbf6ecaf7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-uniseg.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for the uniseg module: https://pypi.python.org/pypi/uniseg + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('uniseg') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-usb.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-usb.py new file mode 100644 index 000000000..1bd9d25ca --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-usb.py @@ -0,0 +1,87 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +import ctypes.util +import os + +from PyInstaller.depend.utils import _resolveCtypesImports +from PyInstaller.compat import is_cygwin, getenv +from PyInstaller.utils.hooks import logger + +# Include glob for library lookup in run-time hook. +hiddenimports = ['glob'] + +# https://github.com/walac/pyusb/blob/master/docs/faq.rst +# https://github.com/walac/pyusb/blob/master/docs/tutorial.rst + +binaries = [] + +# Running usb.core.find() in this script crashes Ubuntu 14.04LTS, +# let users circumvent pyusb discovery with an environment variable. +skip_pyusb_discovery = \ + bool(getenv('PYINSTALLER_USB_HOOK_SKIP_PYUSB_DISCOVERY')) + +# Try to use pyusb's library locator. +if not skip_pyusb_discovery: + import usb.core + import usb.backend + try: + # get the backend symbols before find + backend_contents_before_discovery = set(dir(usb.backend)) + # perform find, which will load a usb library if found + usb.core.find() + # get the backend symbols which have been added (loaded) + backends = set(dir(usb.backend)) - backend_contents_before_discovery + # gather the libraries from the loaded backends + backend_lib_basenames = [] + for usblib in [getattr(usb.backend, be)._lib for be in backends]: + if usblib is not None: + # OSX returns the full path, Linux only the filename. + # save the basename and reconstruct the path after gathering. + backend_lib_basenames.append(os.path.basename(usblib._name)) + # try to resolve the library names to absolute paths. + binaries = _resolveCtypesImports(backend_lib_basenames) + except (ValueError, usb.core.USBError) as exc: + logger.warning("%s", exc) + +# If pyusb didn't find a backend, manually search for usb libraries. +if not binaries: + # NOTE: Update these lists when adding further libs. + if is_cygwin: + libusb_candidates = ['cygusb-1.0-0.dll', 'cygusb0.dll'] + else: + libusb_candidates = [ + # libusb10 + 'usb-1.0', + 'usb', + 'libusb-1.0', + # libusb01 + 'usb-0.1', + 'libusb0', + # openusb + 'openusb', + ] + + backend_library_basenames = [] + for candidate in libusb_candidates: + libname = ctypes.util.find_library(candidate) + if libname is not None: + backend_library_basenames.append(os.path.basename(libname)) + if backend_library_basenames: + binaries = _resolveCtypesImports(backend_library_basenames) + +# Validate and normalize the first found usb library. +if binaries: + # `_resolveCtypesImports` returns a 3-tuple, but `binaries` are only + # 2-tuples, so remove the last element: + assert len(binaries[0]) == 3 + binaries = [(binaries[0][1], '.')] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-uvicorn.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-uvicorn.py new file mode 100644 index 000000000..2d1df7bc9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-uvicorn.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules('uvicorn') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-uvloop.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-uvloop.py new file mode 100644 index 000000000..af32410c2 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-uvloop.py @@ -0,0 +1,19 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# +# Hook for the uvloop package: https://pypi.python.org/pypi/uvloop +# +# Tested with uvloop 0.8.1 and Python 3.6.2, on Ubuntu 16.04.1 64bit. + +from PyInstaller.utils.hooks import collect_submodules + +hiddenimports = collect_submodules('uvloop') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-vtkpython.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-vtkpython.py new file mode 100644 index 000000000..c39103f3f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-vtkpython.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +import os +if os.name == 'posix': + hiddenimports = [ + 'libvtkCommonPython', 'libvtkFilteringPython', 'libvtkIOPython', + 'libvtkImagingPython', 'libvtkGraphicsPython', 'libvtkRenderingPython', + 'libvtkHybridPython', 'libvtkParallelPython', 'libvtkPatentedPython' + ] +else: + hiddenimports = [ + 'vtkCommonPython', 'vtkFilteringPython', 'vtkIOPython', + 'vtkImagingPython', 'vtkGraphicsPython', 'vtkRenderingPython', + 'vtkHybridPython', 'vtkParallelPython', 'vtkPatentedPython' + ] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-wavefile.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-wavefile.py new file mode 100644 index 000000000..0a526f208 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-wavefile.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +python-wavefile: https://github.com/vokimon/python-wavefile +""" + +from PyInstaller.utils.hooks import collect_dynamic_libs + +binaries = collect_dynamic_libs('wavefile') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-weasyprint.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-weasyprint.py new file mode 100644 index 000000000..8122fa1bc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-weasyprint.py @@ -0,0 +1,85 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for weasyprint: https://pypi.python.org/pypi/WeasyPrint +# Tested on version weasyprint 54.0 using Windows 10 and python 3.8 +# Note that weasyprint < 54.0 does not work on python 3.8 due to https://github.com/Kozea/WeasyPrint/issues/1435 +# For weasyprint < 53.0 the required libs are +# libs = [ +# 'gobject-2.0', 'libgobject-2.0-0', 'libgobject-2.0.so.0', 'libgobject-2.0.dylib', +# 'pango-1.0', 'libpango-1.0-0', 'libpango-1.0.so.0', 'libpango-1.0.dylib', +# 'pangocairo-1.0', 'libpangocairo-1.0-0', 'libpangocairo-1.0.so.0', 'libpangocairo-1.0.dylib', +# 'fontconfig', 'libfontconfig', 'libfontconfig-1.dll', 'libfontconfig.so.1', 'libfontconfig-1.dylib', +# 'pangoft2-1.0', 'libpangoft2-1.0-0', 'libpangoft2-1.0.so.0', 'libpangoft2-1.0.dylib' +# ] + +import ctypes.util +import os +from pathlib import Path + +from PyInstaller.compat import is_win +from PyInstaller.depend.utils import _resolveCtypesImports +from PyInstaller.utils.hooks import collect_data_files, logger + +datas = collect_data_files('weasyprint') +binaries = [] +fontconfig_config_dir_found = False + +# On Windows, a GTK3-installation provides fontconfig and the corresponding fontconfig conf files. We have to add these +# for weasyprint to correctly use fonts. +# NOTE: Update these lists if weasyprint requires more libraries +fontconfig_libs = [ + 'fontconfig-1', 'fontconfig', 'libfontconfig', 'libfontconfig-1.dll', 'libfontconfig.so.1', 'libfontconfig-1.dylib' +] +libs = [ + 'gobject-2.0-0', 'gobject-2.0', 'libgobject-2.0-0', 'libgobject-2.0.so.0', 'libgobject-2.0.dylib', + 'pango-1.0-0', 'pango-1.0', 'libpango-1.0-0', 'libpango-1.0.so.0', 'libpango-1.0.dylib', + 'harfbuzz', 'harfbuzz-0.0', 'libharfbuzz-0', 'libharfbuzz.so.0', 'libharfbuzz.so.0', 'libharfbuzz.0.dylib', + 'pangoft2-1.0-0', 'pangoft2-1.0', 'libpangoft2-1.0-0', 'libpangoft2-1.0.so.0', 'libpangoft2-1.0.dylib' +] + +try: + lib_basenames = [] + for lib in libs: + libname = ctypes.util.find_library(lib) + if libname is not None: + lib_basenames += [os.path.basename(libname)] + for lib in fontconfig_libs: + libname = ctypes.util.find_library(lib) + if libname is not None: + lib_basenames += [os.path.basename(libname)] + # Try to load fontconfig config files on Windows from a GTK-installation + if is_win: + fontconfig_config_dir = Path(libname).parent.parent / 'etc/fonts' + if fontconfig_config_dir.exists() and fontconfig_config_dir.is_dir(): + datas += [(str(fontconfig_config_dir), 'etc/fonts')] + fontconfig_config_dir_found = True + if lib_basenames: + resolved_libs = _resolveCtypesImports(lib_basenames) + for resolved_lib in resolved_libs: + binaries.append((resolved_lib[1], '.')) + # Try to load fontconfig config files on other OS + fontconfig_config_dir = Path('/etc/fonts') + if fontconfig_config_dir.exists() and fontconfig_config_dir.is_dir(): + datas += [(str(fontconfig_config_dir), 'etc/fonts')] + fontconfig_config_dir_found = True + +except Exception as e: + logger.warning('Error while trying to find system-installed depending libraries: %s', e) + +if not binaries: + logger.warning('Depending libraries not found - weasyprint will likely fail to work!') + +if not fontconfig_config_dir_found: + logger.warning( + 'Fontconfig configuration files not found - weasyprint will likely throw warnings and use default fonts!' + ) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-web3.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-web3.py new file mode 100644 index 000000000..392d972a6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-web3.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata("web3") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-webassets.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-webassets.py new file mode 100644 index 000000000..abc4ad24e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-webassets.py @@ -0,0 +1,14 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('webassets', include_py_files=True) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-webrtcvad.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-webrtcvad.py new file mode 100644 index 000000000..8010feb14 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-webrtcvad.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('webrtcvad') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-websockets.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-websockets.py new file mode 100644 index 000000000..a6962b3ed --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-websockets.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_submodules + +# Websockets lazily loads its submodules. +hiddenimports = collect_submodules("websockets") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-webview.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-webview.py new file mode 100644 index 000000000..b8effbbc3 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-webview.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# hook for https://github.com/r0x0r/pywebview + +from PyInstaller.utils.hooks import collect_data_files, collect_dynamic_libs +from PyInstaller.compat import is_win + +if is_win: + datas = collect_data_files('webview', subdir='lib') + binaries = collect_dynamic_libs('webview') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-win32com.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-win32com.py new file mode 100644 index 000000000..a54b0fcdf --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-win32com.py @@ -0,0 +1,20 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = [ + # win32com client and server util + # modules could be hidden imports + # of some modules using win32com. + # Included for completeness. + 'win32com.client.util', + 'win32com.server.util', +] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-wordcloud.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-wordcloud.py new file mode 100644 index 000000000..a4e733940 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-wordcloud.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('wordcloud') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-workflow.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-workflow.py new file mode 100644 index 000000000..6895aa174 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-workflow.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('workflow') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-wx.lib.activex.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-wx.lib.activex.py new file mode 100644 index 000000000..86e409668 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-wx.lib.activex.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import exec_statement + +# This needed because comtypes wx.lib.activex generates some stuff. +exec_statement("import wx.lib.activex") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-wx.lib.pubsub.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-wx.lib.pubsub.py new file mode 100644 index 000000000..637ec9d4e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-wx.lib.pubsub.py @@ -0,0 +1,27 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('wx.lib.pubsub', include_py_files=True, excludes=['*.txt', '**/__pycache__']) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-wx.xrc.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-wx.xrc.py new file mode 100644 index 000000000..1d8b7a293 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-wx.xrc.py @@ -0,0 +1,13 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +hiddenimports = ['wx._xml', 'wx'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-xml.dom.html.HTMLDocument.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-xml.dom.html.HTMLDocument.py new file mode 100644 index 000000000..70400a92c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-xml.dom.html.HTMLDocument.py @@ -0,0 +1,67 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# xml.dom.html.HTMLDocument +hiddenimports = ['xml.dom.html.HTMLAnchorElement', + 'xml.dom.html.HTMLAppletElement', + 'xml.dom.html.HTMLAreaElement', + 'xml.dom.html.HTMLBaseElement', + 'xml.dom.html.HTMLBaseFontElement', + 'xml.dom.html.HTMLBodyElement', + 'xml.dom.html.HTMLBRElement', + 'xml.dom.html.HTMLButtonElement', + 'xml.dom.html.HTMLDirectoryElement', + 'xml.dom.html.HTMLDivElement', + 'xml.dom.html.HTMLDListElement', + 'xml.dom.html.HTMLElement', + 'xml.dom.html.HTMLFieldSetElement', + 'xml.dom.html.HTMLFontElement', + 'xml.dom.html.HTMLFormElement', + 'xml.dom.html.HTMLFrameElement', + 'xml.dom.html.HTMLFrameSetElement', + 'xml.dom.html.HTMLHeadElement', + 'xml.dom.html.HTMLHeadingElement', + 'xml.dom.html.HTMLHRElement', + 'xml.dom.html.HTMLHtmlElement', + 'xml.dom.html.HTMLIFrameElement', + 'xml.dom.html.HTMLImageElement', + 'xml.dom.html.HTMLInputElement', + 'xml.dom.html.HTMLIsIndexElement', + 'xml.dom.html.HTMLLabelElement', + 'xml.dom.html.HTMLLegendElement', + 'xml.dom.html.HTMLLIElement', + 'xml.dom.html.HTMLLinkElement', + 'xml.dom.html.HTMLMapElement', + 'xml.dom.html.HTMLMenuElement', + 'xml.dom.html.HTMLMetaElement', + 'xml.dom.html.HTMLModElement', + 'xml.dom.html.HTMLObjectElement', + 'xml.dom.html.HTMLOListElement', + 'xml.dom.html.HTMLOptGroupElement', + 'xml.dom.html.HTMLOptionElement', + 'xml.dom.html.HTMLParagraphElement', + 'xml.dom.html.HTMLParamElement', + 'xml.dom.html.HTMLPreElement', + 'xml.dom.html.HTMLQuoteElement', + 'xml.dom.html.HTMLScriptElement', + 'xml.dom.html.HTMLSelectElement', + 'xml.dom.html.HTMLStyleElement', + 'xml.dom.html.HTMLTableCaptionElement', + 'xml.dom.html.HTMLTableCellElement', + 'xml.dom.html.HTMLTableColElement', + 'xml.dom.html.HTMLTableElement', + 'xml.dom.html.HTMLTableRowElement', + 'xml.dom.html.HTMLTableSectionElement', + 'xml.dom.html.HTMLTextAreaElement', + 'xml.dom.html.HTMLTitleElement', + 'xml.dom.html.HTMLUListElement', + ] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-xml.sax.saxexts.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-xml.sax.saxexts.py new file mode 100644 index 000000000..80b9bb0fb --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-xml.sax.saxexts.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# xml.sax.saxexts +hiddenimports = ["xml.sax.drivers2.drv_pyexpat", + "xml.sax.drivers.drv_xmltok", + 'xml.sax.drivers2.drv_xmlproc', + "xml.sax.drivers.drv_xmltoolkit", + "xml.sax.drivers.drv_xmllib", + "xml.sax.drivers.drv_xmldc", + 'xml.sax.drivers.drv_pyexpat', + 'xml.sax.drivers.drv_xmlproc_val', + 'xml.sax.drivers.drv_htmllib', + 'xml.sax.drivers.drv_sgmlop', + "xml.sax.drivers.drv_sgmllib", + ] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-xmldiff.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-xmldiff.py new file mode 100644 index 000000000..d85ea88d2 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-xmldiff.py @@ -0,0 +1,16 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# Hook for https://github.com/Shoobx/xmldiff + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('xmldiff') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-xsge_gui.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-xsge_gui.py new file mode 100644 index 000000000..306d3d066 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-xsge_gui.py @@ -0,0 +1,17 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for the xsge_gui module: https://pypi.python.org/pypi/xsge_gui + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('xsge_gui') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-xyzservices.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-xyzservices.py new file mode 100644 index 000000000..bf79bc721 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-xyzservices.py @@ -0,0 +1,15 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +datas = collect_data_files('xyzservices') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-z3c.rml.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-z3c.rml.py new file mode 100644 index 000000000..3eac8c884 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-z3c.rml.py @@ -0,0 +1,25 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2023 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.utils.hooks import collect_data_files + +# `z3c.rml` uses Bitstream Vera TTF fonts from the `reportlab` package. As that package can be used without the bundled +# fonts and as some of the bundled fonts have restrictive license (e.g., DarkGarden), we collect the required subset +# of fonts here, instead of collecting them all in a hook for `reportlab`. +datas = collect_data_files( + "reportlab", + includes=[ + "fonts/00readme.txt", + "fonts/bitstream-vera-license.txt", + "fonts/Vera*.ttf", + ], +) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-zeep.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-zeep.py new file mode 100644 index 000000000..ac2e486ca --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-zeep.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +# Hook for the zeep module: https://pypi.python.org/pypi/zeep +# Tested with zeep 0.13.0, Python 2.7, Windows + +from PyInstaller.utils.hooks import copy_metadata + +datas = copy_metadata('zeep') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-zmq.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-zmq.py new file mode 100644 index 000000000..90b4110be --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-zmq.py @@ -0,0 +1,63 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +""" +Hook for PyZMQ. Cython based Python bindings for messaging library ZeroMQ. +http://www.zeromq.org/ +""" +import os +import glob +from PyInstaller.utils.hooks import collect_submodules +from PyInstaller.utils.hooks import is_module_satisfies, get_module_file_attribute +from PyInstaller.compat import is_win + +binaries = [] +datas = [] +hiddenimports = ['zmq.utils.garbage'] + +# PyZMQ comes with two backends, cython and cffi. Calling collect_submodules() +# on zmq.backend seems to trigger attempt at compilation of C extension +# module for cffi backend, which will fail if ZeroMQ development files +# are not installed on the system. On non-English locales, the resulting +# localized error messages may cause UnicodeDecodeError. Collecting each +# backend individually, however, does not seem to cause any problems. +hiddenimports += ['zmq.backend'] + +# cython backend +hiddenimports += collect_submodules('zmq.backend.cython') + +# cffi backend: contains extra data that needs to be collected +# (e.g., _cdefs.h) +# +# NOTE: the cffi backend requires compilation of C extension at runtime, +# which appears to be broken in frozen program. So avoid collecting +# it altogether... +if False: + from PyInstaller.utils.hooks import collect_data_files + + hiddenimports += collect_submodules('zmq.backend.cffi') + datas += collect_data_files('zmq.backend.cffi', excludes=['**/__pycache__', ]) + +# Starting with pyzmq 22.0.0, the DLLs in Windows wheel are located in +# site-packages/pyzmq.libs directory along with a .load_order file. This +# file is required on python 3.7 and earlier. On later versions of python, +# the pyzmq.libs is required to exist. +if is_win and is_module_satisfies('pyzmq >= 22.0.0'): + zmq_root = os.path.dirname(get_module_file_attribute('zmq')) + libs_dir = os.path.join(zmq_root, os.path.pardir, 'pyzmq.libs') + # .load_order file (22.0.3 replaced underscore with dash and added + # version suffix on this file, hence the glob) + load_order_file = glob.glob(os.path.join(libs_dir, '.load*')) + datas += [(filename, 'pyzmq.libs') for filename in load_order_file] + # We need to collect DLLs into _MEIPASS, to avoid duplication due to + # subsequent binary analysis + dll_files = glob.glob(os.path.join(libs_dir, "*.dll")) + binaries += [(dll_file, '.') for dll_file in dll_files] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-zoneinfo.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-zoneinfo.py new file mode 100644 index 000000000..93730f471 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/hooks/stdhooks/hook-zoneinfo.py @@ -0,0 +1,18 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2021 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +from PyInstaller.compat import is_win + +# On Windows, timezone data is provided by the tzdata package that is +# not directly loaded. +if is_win: + hiddenimports = ['tzdata'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/__init__.py new file mode 100644 index 000000000..8a0a93bcc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/__init__.py @@ -0,0 +1,28 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +import os + +DIR = os.path.dirname(__file__) +""" +This directory and every sub directory contains tests +""" + + +def get_test_dirs(): + + dirs = [] + # For every directory and sub directory (including cwd) + for path, _, _ in os.walk(DIR): + # Add the norm'd path to dirs + dirs.append(os.path.normpath(path)) + + return dirs diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/conftest.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/conftest.py new file mode 100644 index 000000000..350545cc5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/conftest.py @@ -0,0 +1,13 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ +# Import all fixtures from PyInstaller into the tests. +from PyInstaller.utils.conftest import * # noqa: F401,F403 diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/data/test_hydra/config.yaml b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/data/test_hydra/config.yaml new file mode 100644 index 000000000..f9f740384 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/data/test_hydra/config.yaml @@ -0,0 +1,3 @@ +test_group: + secret_string: secret + secret_number: 123 diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/scripts/pyi_lib_boto.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/scripts/pyi_lib_boto.py new file mode 100644 index 000000000..559fb4542 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/scripts/pyi_lib_boto.py @@ -0,0 +1,45 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2015-2020, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +# ----------------------------------------------------------------------------- + +from inspect import getmembers, isfunction +from functools import partial +import boto +import boto.exception + +credentials = dict( + aws_access_key_id='ASIAIH3F2FU3T63KIXKA', + aws_secret_access_key='lnN4qk1a0SuQAFVsGA+Y+ujo2/5rLq2j+a1O4Vuy') +# connect_cloudsearchdomain is broken in boto; the rest require custom params +skip = { + 'connect_cloudsearchdomain', + 'connect_ec2_endpoint', + 'connect_gs', + 'connect_euca', + 'connect_ia', + 'connect_walrus', +} +connect_funcs = [ + func for name, func in getmembers(boto) + if isfunction(func) and name.startswith('connect_') and name not in skip +] +connect_funcs += [ + partial(boto.connect_ec2_endpoint, 'https://ec2.amazonaws.com', + **credentials), + partial(boto.connect_gs, gs_access_key_id='', gs_secret_access_key=''), + partial(boto.connect_euca, host=None, **credentials), + partial(boto.connect_ia, ia_access_key_id='', ia_secret_access_key=''), + partial(boto.connect_walrus, host='s3.amazonaws.com', **credentials), +] +for connect_func in connect_funcs: + if isfunction(connect_func): + connect_func(**credentials) + else: + connect_func() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/scripts/pyi_lib_enchant.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/scripts/pyi_lib_enchant.py new file mode 100644 index 000000000..f594fdbc8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/scripts/pyi_lib_enchant.py @@ -0,0 +1,43 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2005-2020, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +# ----------------------------------------------------------------------------- + +# Enchant hook test. Tested with PyEnchant 1.6.6. + +import sys +import enchant + +print(80 * '-') +print('PYTHONPATH: %s' % sys.path) + +# At least one backend should be available +backends = [x.name for x in enchant.Broker().describe()] +if len(backends) < 1: + raise SystemExit('Error: No dictionary backend available') +print(80 * '-') +print('Backends: ' + ', '.join(backends)) + +# Usually en_US dictionary should be bundled. +languages = enchant.list_languages() +dicts = [x[0] for x in enchant.list_dicts()] +if len(dicts) < 1: + raise SystemExit('No dictionary available') +print(80 * '-') +print('Languages: %s' % ', '.join(languages)) +print('Dictionaries: %s' % dicts) +print(80 * '-') + +# Try spell checking if English is availale +language = 'en_US' +if language in languages: + d = enchant.Dict(language) + print('d.check("hallo") %s' % d.check('hallo')) + print('d.check("halllo") %s' % d.check('halllo')) + print('d.suggest("halllo") %s' % d.suggest('halllo')) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/scripts/pyi_lib_pycparser.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/scripts/pyi_lib_pycparser.py new file mode 100644 index 000000000..588ffcefc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/scripts/pyi_lib_pycparser.py @@ -0,0 +1,54 @@ +# ----------------------------------------------------------------------------- +# Copyright (c) 2014-2020, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +# ----------------------------------------------------------------------------- + +import os + +fnames_to_track = [ + 'lextab.py', + 'yacctab.py', +] + + +def fnames_found(): + return [fname for fname in fnames_to_track if os.path.isfile(fname)] + + +if __name__ == '__main__': + + # Confirm no files exist before we start. + if fnames_found(): + raise SystemExit('FAIL: Files present before test.') + + # Minimal invocation that generates the files. + from pycparser import c_parser + parser = c_parser.CParser() + + # Were the files generated? + fnames_generated = fnames_found() + + # Try to remove them, if so. + for fname in fnames_generated: + try: + os.unlink(fname) + except OSError: + pass + + # Did we fail at deleting any file? + fnames_left = fnames_found() + + # Fail if any file was generated. + if fnames_generated: + if fnames_left: + raise SystemExit('FAIL: Files generated and not removed.') + else: + raise SystemExit('FAIL: Files generated but removed.') + + # Success. diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/scripts/pyi_lib_tensorflow_layer.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/scripts/pyi_lib_tensorflow_layer.py new file mode 100644 index 000000000..0b7e68296 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/scripts/pyi_lib_tensorflow_layer.py @@ -0,0 +1,36 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +import os + +# Force CPU +os.environ['CUDA_VISIBLE_DEVICES'] = '-1' + +# Display only warnings and errors +os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' + +# Begin test - import tensorflow after environment variables are set +import tensorflow as tf # noqa: E402 + +# Input data: batch of four 28x28x3 images +input_shape = (4, 28, 28, 3) +x = tf.random.normal(input_shape) + +# Convolution with 3x3 kernel, two output filters +y = tf.keras.layers.Conv2D( + 2, + (3, 3), + activation='relu', + input_shape=input_shape[1:] +)(x) + +assert y.shape == (4, 26, 26, 2), "Unexpected output shape!" diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/scripts/pyi_lib_tensorflow_mnist.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/scripts/pyi_lib_tensorflow_mnist.py new file mode 100644 index 000000000..ea85c0218 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/scripts/pyi_lib_tensorflow_mnist.py @@ -0,0 +1,50 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +import os + +# Force CPU +os.environ['CUDA_VISIBLE_DEVICES'] = '-1' + +# Display only warnings and errors +os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' + +# Begin test - import tensorflow after environment variables are set +import tensorflow as tf # noqa: E402 + +# Load and normalize the dataset +mnist = tf.keras.datasets.mnist + +(x_train, y_train), (x_test, y_test) = mnist.load_data() +x_train, x_test = x_train / 255.0, x_test / 255.0 + +# Define model... +model = tf.keras.models.Sequential([ + tf.keras.layers.Flatten(input_shape=(28, 28)), + tf.keras.layers.Dense(128, activation='relu'), + tf.keras.layers.Dropout(0.2), + tf.keras.layers.Dense(10) +]) + +# ... and loss function +loss_fn = tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True) + +# Train +model.compile(optimizer='adam', loss=loss_fn, metrics=['accuracy']) +model.fit(x_train, y_train, epochs=1, verbose=1) + +# Evaluate +results = model.evaluate(x_test, y_test, verbose=1) + +# Expected accuracy after a single epoch is around 95%, so use 90% +# as a passing bar +assert results[1] >= 0.90, "Resulting accuracy on validation set too low!" diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/test_libraries.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/test_libraries.py new file mode 100644 index 000000000..daee18a44 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/test_libraries.py @@ -0,0 +1,1974 @@ +# ------------------------------------------------------------------ +# Copyright (c) 2020 PyInstaller Development Team. +# +# This file is distributed under the terms of the GNU General Public +# License (version 2.0 or later). +# +# The full license is available in LICENSE.GPL.txt, distributed with +# this software. +# +# SPDX-License-Identifier: GPL-2.0-or-later +# ------------------------------------------------------------------ + +import os +from pathlib import Path + +import pytest + +from PyInstaller.compat import is_darwin, is_linux, is_py39, is_win +from PyInstaller.utils.hooks import is_module_satisfies, can_import_module, get_module_attribute +from PyInstaller.utils.tests import importorskip, requires, xfail + + +@importorskip('fiona') +def test_fiona(pyi_builder): + pyi_builder.test_source( + ''' + import fiona + ''' + ) + + +@importorskip('fiona') +def test_fiona_transform(pyi_builder): + # Test that fiona in frozen application has access to its projections database. If projection data is unavailable, + # the transform becomes an identity transform. + pyi_builder.test_source( + """ + from fiona.transform import transform_geom + from fiona.crs import from_epsg + + eiffel_tower = { + 'type': 'Point', + 'coordinates': (2.294694, 48.858093), + } + + crs_source = from_epsg(4326) # WGS84 + crs_target = from_epsg(25831) # ETRS89 / UTM zone 31N + + transformed = transform_geom(crs_source, crs_target, eiffel_tower) + print(f"Transformed point: {transformed}") + + # Expected coordinates: obtained by manually running this program unfrozen + EXPECTED_COORDINATES = (448265.9146792292, 5411920.651338793) + EPS = 1e-6 + + delta = [abs(value - expected) for value, expected in zip(transformed["coordinates"], EXPECTED_COORDINATES)] + print(f"Delta: {delta}") + assert all([value < EPS for value in delta]), f"Delta {delta} exceeds threshold!" + """ + ) + + +@importorskip('jinxed') +def test_jinxed(pyi_builder): + pyi_builder.test_source( + ''' + import jinxed + jinxed.setupterm('xterm') + assert jinxed._terminal.TERM.terminfo is jinxed.terminfo.xterm + ''' + ) + + +@importorskip("geopandas") +def test_geopandas(pyi_builder): + pyi_builder.test_source( + ''' + import geopandas + ''' + ) + + +def tensorflow_onedir_only(test): + def wrapped(pyi_builder): + if pyi_builder._mode != 'onedir': + pytest.skip('Tensorflow tests support only onedir mode ' + 'due to potential distribution size.') + test(pyi_builder) + + return wrapped + + +@importorskip('tensorflow') +@tensorflow_onedir_only +def test_tensorflow(pyi_builder): + pyi_builder.test_source( + """ + from tensorflow import * + """ + ) + + +# Test if tensorflow.keras imports properly result in tensorflow being collected. +# See https://github.com/pyinstaller/pyinstaller/discussions/6890 +@importorskip('tensorflow') +@tensorflow_onedir_only +def test_tensorflow_keras_import(pyi_builder): + pyi_builder.test_source( + """ + from tensorflow.keras.models import Sequential + from tensorflow.keras.layers import Dense, LSTM, Dropout + from tensorflow.keras.optimizers import Adam + """ + ) + + +@importorskip('tensorflow') +@tensorflow_onedir_only +def test_tensorflow_layer(pyi_builder): + pyi_builder.test_script('pyi_lib_tensorflow_layer.py') + + +@importorskip('tensorflow') +@tensorflow_onedir_only +def test_tensorflow_mnist(pyi_builder): + pyi_builder.test_script('pyi_lib_tensorflow_mnist.py') + + +@importorskip('trimesh') +def test_trimesh(pyi_builder): + pyi_builder.test_source( + """ + import trimesh + """ + ) + + +@importorskip('apscheduler') +def test_apscheduler(pyi_builder): + pyi_builder.test_source( + """ + import apscheduler + import pytz + import asyncio + import random + import datetime as dt + from apscheduler.schedulers.asyncio import AsyncIOScheduler + from apscheduler.triggers.interval import IntervalTrigger + loop = asyncio.get_event_loop() + async def test_function(data=0): + print(dt.datetime.now(), random.randint(0, 100)) + test_scheduler = AsyncIOScheduler() + test_scheduler.add_job( + test_function, + id="TestJob", + trigger=IntervalTrigger( + seconds=1, + start_date=dt.datetime.now(tz=pytz.UTC) + ) + ) + test_scheduler.start() + loop.run_until_complete(asyncio.sleep(5)) + """ + ) + + +@importorskip('boto') +@xfail(reason='boto does not fully support Python 3') +def test_boto(pyi_builder): + pyi_builder.test_script('pyi_lib_boto.py') + + +@xfail(reason='Issue #1844.') +@importorskip('boto3') +def test_boto3(pyi_builder): + pyi_builder.test_source( + """ + import boto3 + session = boto3.Session(region_name='us-west-2') + + # verify all clients + for service in session.get_available_services(): + session.client(service) + + # verify all resources + for resource in session.get_available_resources(): + session.resource(resource) + """) + + +@xfail(reason='Issue #1844.') +@importorskip('botocore') +def test_botocore(pyi_builder): + pyi_builder.test_source( + """ + import botocore + from botocore.session import Session + session = Session() + # verify all services + for service in session.get_available_services(): + session.create_client(service, region_name='us-west-2') + """) + + +@xfail(is_darwin, reason='Issue #1895.') +@importorskip('enchant') +def test_enchant(pyi_builder): + pyi_builder.test_script('pyi_lib_enchant.py') + + +@importorskip('zmq') +def test_zmq(pyi_builder): + pyi_builder.test_source( + """ + import zmq + print(zmq.__version__) + print(zmq.zmq_version()) + # This is a problematic module and might cause some issues. + import zmq.utils.strtypes + """) + + +@importorskip('pylint') +def test_pylint(pyi_builder): + pyi_builder.test_source( + """ + # The following more obvious test doesn't work:: + # + # import pylint + # pylint.run_pylint() + # + # because pylint will exit with 32, since a valid command + # line wasn't given. Instead, provide a valid command line below. + + from pylint.lint import Run + Run(['-h']) + """) + + +@importorskip('markdown') +def test_markdown(pyi_builder): + # Markdown uses __import__ed extensions. Make sure these work by + # trying to use the 'toc' extension, using both short and long format. + pyi_builder.test_source( + """ + import markdown + print(markdown.markdown('testing', + extensions=['toc'])) + print(markdown.markdown('testing', + extensions=['markdown.extensions.toc'])) + """) + + +@importorskip('pylsl') +def test_pylsl(pyi_builder): + pyi_builder.test_source( + """ + import pylsl + print(pylsl.version.__version__) + """) + + +@importorskip('lxml') +def test_lxml_isoschematron(pyi_builder): + pyi_builder.test_source( + """ + # The import of this module triggers the loading of some + # required XML files. + from lxml import isoschematron + """) + + +@importorskip('openpyxl') +def test_openpyxl(pyi_builder): + pyi_builder.test_source( + """ + # Test the hook to openpyxl + from openpyxl import __version__ + """) + + +@importorskip('pyodbc') +def test_pyodbc(pyi_builder): + pyi_builder.test_source( + """ + # pyodbc is a binary Python module. On Windows when installed with easy_install + # it is installed as zipped Python egg. This binary module is extracted + # to PYTHON_EGG_CACHE directory. PyInstaller should find the binary there and + # include it with frozen executable. + import pyodbc + """) + + +@importorskip('pyttsx') +def test_pyttsx(pyi_builder): + pyi_builder.test_source( + """ + # Basic code example from pyttsx tutorial. + # http://packages.python.org/pyttsx/engine.html#examples + import pyttsx + engine = pyttsx.init() + engine.say('Sally sells seashells by the seashore.') + engine.say('The quick brown fox jumped over the lazy dog.') + engine.runAndWait() + """) + + +@importorskip('pyttsx3') +def test_pyttsx3(pyi_builder): + pyi_builder.test_source(""" + import pyttsx3 + engine = pyttsx3.init() + """) + + +@importorskip('pycparser') +def test_pycparser(pyi_builder): + pyi_builder.test_script('pyi_lib_pycparser.py') + + +@importorskip('Crypto') +def test_pycrypto(pyi_builder): + pyi_builder.test_source( + """ + import binascii + from Crypto.Cipher import AES + BLOCK_SIZE = 16 + print('AES null encryption, block size', BLOCK_SIZE) + # Just for testing functionality after all + print('HEX', binascii.hexlify( + AES.new(b"\\0" * BLOCK_SIZE, AES.MODE_ECB).encrypt(b"\\0" * BLOCK_SIZE))) + from Crypto.PublicKey import ECC + """) + + +@importorskip('Cryptodome') +def test_cryptodome(pyi_builder): + pyi_builder.test_source( + """ + from Cryptodome import Cipher + from Cryptodome.PublicKey import ECC + print('Cryptodome Cipher Module:', Cipher) + """) + + +@importorskip('h5py') +def test_h5py(pyi_builder): + pyi_builder.test_source(""" + import h5py + """) + + +@importorskip('unidecode') +def test_unidecode(pyi_builder): + pyi_builder.test_source(""" + from unidecode import unidecode + + # Unidecode should not skip non-ASCII chars if mappings for them exist. + assert unidecode(u"kožušček") == "kozuscek" + """) + + +@importorskip('pinyin') +def test_pinyin(pyi_builder): + pyi_builder.test_source(""" + import pinyin + """) + + +@importorskip('uvloop') +@pytest.mark.darwin +@pytest.mark.linux +def test_uvloop(pyi_builder): + pyi_builder.test_source("import uvloop") + + +@importorskip('web3') +def test_web3(pyi_builder): + pyi_builder.test_source("import web3") + + +@importorskip('phonenumbers') +def test_phonenumbers(pyi_builder): + pyi_builder.test_source(""" + import phonenumbers + + number = '+17034820623' + parsed_number = phonenumbers.parse(number) + + assert(parsed_number.country_code == 1) + assert(parsed_number.national_number == 7034820623) + """) + + +@importorskip('pendulum') +def test_pendulum(pyi_builder): + pyi_builder.test_source(""" + import pendulum + + print(pendulum.now().isoformat()) + """) + + +@importorskip('humanize') +def test_humanize(pyi_builder): + pyi_builder.test_source(""" + import humanize + from datetime import timedelta + + print(humanize.naturaldelta(timedelta(seconds=125))) + """) + + +@importorskip('argon2') +def test_argon2(pyi_builder): + pyi_builder.test_source(""" + from argon2 import PasswordHasher + + ph = PasswordHasher() + hash = ph.hash("s3kr3tp4ssw0rd") + ph.verify(hash, "s3kr3tp4ssw0rd") + """) + + +@importorskip('pytest') +def test_pytest_runner(pyi_builder): + """ + Check if pytest runner builds correctly. + """ + pyi_builder.test_source( + """ + import pytest + import sys + sys.exit(pytest.main(['--help'])) + """) + + +@importorskip('eel') +def test_eel(pyi_builder): + pyi_builder.test_source("import eel") + + +@importorskip('sentry_sdk') +def test_sentry(pyi_builder): + pyi_builder.test_source( + """ + import sentry_sdk + sentry_sdk.init() + """) + + +@importorskip('iminuit') +def test_iminuit(pyi_builder): + pyi_builder.test_source(""" + from iminuit import Minuit + """) + + +@importorskip('av') +def test_av(pyi_builder): + pyi_builder.test_source(""" + import av + """) + + +@importorskip('passlib') +@xfail(is_linux and is_py39 and not is_module_satisfies('passlib > 1.7.4'), + reason='Passlib does not account for crypt() behavior change that ' + 'was introduced in 3.9.x (python #39289).') +def test_passlib(pyi_builder): + pyi_builder.test_source(""" + import passlib.apache + """) + + +@importorskip('publicsuffix2') +def test_publicsuffix2(pyi_builder): + pyi_builder.test_source(""" + import publicsuffix2 + publicsuffix2.PublicSuffixList() + """) + + +@importorskip('pydivert') +def test_pydivert(pyi_builder): + pyi_builder.test_source(""" + import pydivert + pydivert.WinDivert.check_filter("inbound") + """) + + +@pytest.mark.slow +@importorskip('skimage') +@pytest.mark.skipif(not is_module_satisfies('scikit_image >= 0.16'), + reason='The test supports only scikit-image >= 0.16.') +@pytest.mark.parametrize('submodule', [ + 'color', 'data', 'draw', 'exposure', 'feature', 'filters', 'future', + 'graph', 'io', 'measure', 'metrics', 'morphology', 'registration', + 'restoration', 'segmentation', 'transform', 'util' +]) +def test_skimage(pyi_builder, submodule): + pyi_builder.test_source(""" + import skimage.{0} + """.format(submodule)) + + +@pytest.mark.slow +@importorskip('sklearn') +@pytest.mark.skipif(not is_module_satisfies('scikit_learn >= 0.21'), + reason='The test supports only scikit-learn >= 0.21.') +@pytest.mark.parametrize('submodule', [ + 'calibration', 'cluster', 'covariance', 'cross_decomposition', + 'datasets', 'decomposition', 'dummy', 'ensemble', 'exceptions', + 'experimental', 'externals', 'feature_extraction', + 'feature_selection', 'gaussian_process', 'inspection', + 'isotonic', 'kernel_approximation', 'kernel_ridge', + 'linear_model', 'manifold', 'metrics', 'mixture', + 'model_selection', 'multiclass', 'multioutput', + 'naive_bayes', 'neighbors', 'neural_network', 'pipeline', + 'preprocessing', 'random_projection', 'semi_supervised', + 'svm', 'tree', 'discriminant_analysis', 'impute', 'compose' +]) +def test_sklearn(pyi_builder, submodule): + pyi_builder.test_source(""" + import sklearn.{0} + """.format(submodule)) + + +@importorskip('statsmodels') +@pytest.mark.skipif(not is_module_satisfies('statsmodels >= 0.12'), + reason='This has only been tested with statsmodels >= 0.12.') +def test_statsmodels(pyi_builder): + pyi_builder.test_source(""" + import statsmodels.api as sm + """) + + +@importorskip('win32ctypes') +@pytest.mark.skipif(not is_win, reason='pywin32-ctypes is supported only on Windows') +@pytest.mark.parametrize('submodule', ['win32api', 'win32cred', 'pywintypes']) +def test_pywin32ctypes(pyi_builder, submodule): + pyi_builder.test_source(""" + from win32ctypes.pywin32 import {0} + """.format(submodule)) + + +@importorskip('pyproj') +@pytest.mark.skipif(not is_module_satisfies('pyproj >= 2.1.3'), + reason='The test supports only pyproj >= 2.1.3.') +def test_pyproj(pyi_builder): + pyi_builder.test_source(""" + import pyproj + tf = pyproj.Transformer.from_crs( + 7789, + 8401 + ) + result = tf.transform( + xx=3496737.2679, + yy=743254.4507, + zz=5264462.9620, + tt=2019.0 + ) + print(result) + """) + + +@importorskip('pydantic') +def test_pydantic(pyi_builder): + pyi_builder.test_source(""" + import datetime + import pprint + + import pydantic + + + class User(pydantic.BaseModel): + id: int + name: str = 'John Doe' + signup_ts: datetime.datetime + + + external_data = {'id': 'not an int', } + try: + User(**external_data) + except pydantic.ValidationError as e: + pprint.pprint(e.errors()) + """) + + +def torch_onedir_only(test): + + def wrapped(pyi_builder): + if pyi_builder._mode != 'onedir': + pytest.skip('PyTorch tests support only onedir mode ' + 'due to potential distribution size.') + test(pyi_builder) + + return wrapped + + +@importorskip('torch') +@torch_onedir_only +def test_torch(pyi_builder): + pyi_builder.test_source(""" + import torch + + torch.rand((10, 10)) * torch.rand((10, 10)) + """) + + +@importorskip('torchvision') +@torch_onedir_only +def test_torchvision_nms(pyi_builder): + pyi_builder.test_source(""" + import torch + import torchvision + # boxes: Nx4 tensor (x1, y1, x2, y2) + boxes = torch.tensor([ + [0.0, 0.0, 1.0, 1.0], + [0.45, 0.0, 1.0, 1.0], + ]) + # scores: Nx1 tensor + scores = torch.tensor([ + 1.0, + 1.1 + ]) + keep = torchvision.ops.nms(boxes, scores, 0.5) + # The boxes have IoU of 0.55, and the second one has a slightly + # higher score, so we expect it to be kept while the first one + # is discarded. + assert keep == 1 + """) + + +@requires('google-api-python-client >= 2.0.0') +def test_googleapiclient(pyi_builder): + pyi_builder.test_source(""" + from googleapiclient import discovery, discovery_cache + + API_NAME = "youtube" + API_VERSION = "v3" + + for file in os.listdir(discovery_cache.DISCOVERY_DOC_DIR): # Always up to date + if file.startswith("youtube.v") and file.endswith(".json"): + API_NAME, API_VERSION = file.split(".")[:2] + break + + # developerKey can be any non-empty string + yt = discovery.build(API_NAME, API_VERSION, developerKey=":)", static_discovery=True) + """) + + +@importorskip('eth_typing') +def test_eth_typing(pyi_builder): + pyi_builder.test_source(""" + import eth_typing + """) + + +@importorskip("eth_utils") +def test_eth_utils_network(pyi_builder): + pyi_builder.test_source(""" + import eth_utils.network + eth_utils.network.name_from_chain_id(1) + """) + + +@importorskip('plotly') +@importorskip('pandas') +def test_plotly(pyi_builder): + pyi_builder.test_source(""" + import pandas as pd + import plotly.express as px + + data = [(1, 1), (2, 1), (3, 5), (4, -3)] + df = pd.DataFrame.from_records(data, columns=['col_1', 'col_2']) + fig = px.scatter(df, x='col_1', y='col_2') + """) + + +@pytest.mark.timeout(600) +@importorskip('dash') +def test_dash(pyi_builder): + pyi_builder.test_source(""" + import dash + import dash_core_components as dcc + import dash_html_components as html + from dash.dependencies import Input, Output + + app = dash.Dash(__name__) + app.layout = html.Div( + [ + dcc.Input(id='input_text', type='text', placeholder='input type text'), + html.Div(id='out-all-types'), + ] + ) + + @app.callback( + Output('out-all-types', 'children'), + [Input('input_text', 'value')], + ) + def cb_render(val): + return val + """) + + +@importorskip('dash_table') +def test_dash_table(pyi_builder): + pyi_builder.test_source(""" + import dash + import dash_table + + app = dash.Dash(__name__) + app.layout = dash_table.DataTable( + id='table', + columns=[{'name': 'a', 'id': 'a'}, {'name': 'b', 'id': 'b'}], + data=[{'a': 1, 'b': 2}, {'a': 3, 'b': 4}], + ) + """) + + +@importorskip('dash_bootstrap_components') +def test_dash_bootstrap_components(pyi_builder): + pyi_builder.test_source(""" + import dash + import dash_bootstrap_components as dbc + import dash_html_components as html + + app = dash.Dash(external_stylesheets=[dbc.themes.BOOTSTRAP]) + alert = dbc.Alert([html.H4('Well done!', className='alert-heading')]) + """) + + +@importorskip('blspy') +def test_blspy(pyi_builder): + pyi_builder.test_source(""" + import blspy + """) + + +@importorskip('flirpy') +def test_flirpy(pyi_builder): + pyi_builder.test_source(""" + from flirpy.camera.lepton import Lepton + + print(Lepton.find_video_device()) + """) + + +@importorskip('office365') +def test_office365(pyi_builder): + pyi_builder.test_source(""" + from office365.runtime.auth.providers.saml_token_provider import SamlTokenProvider + + SamlTokenProvider._prepare_request_from_template('FederatedSAML.xml', {}) + SamlTokenProvider._prepare_request_from_template('RST2.xml', {}) + SamlTokenProvider._prepare_request_from_template('SAML.xml', {}) + """) + + +@importorskip('thinc') +def test_thinc(pyi_builder): + pyi_builder.test_source(""" + from thinc.backends import numpy_ops + """) + + +@importorskip('srsly') +def test_srsly(pyi_builder): + pyi_builder.test_source(""" + import srsly + """) + + +@importorskip('spacy') +def test_spacy(pyi_builder): + pyi_builder.test_source(""" + import spacy + """) + + +@importorskip('shotgun_api3') +def test_shotgun_api3(pyi_builder): + pyi_builder.test_source(""" + import shotgun_api3 + """) + + +@importorskip('msoffcrypto') +def test_msoffcrypto(pyi_builder): + pyi_builder.test_source(""" + import msoffcrypto + """) + + +@importorskip('mariadb') +def test_mariadb(pyi_builder): + pyi_builder.test_source(""" + import mariadb + """) + + +@importorskip('dash_uploader') +def test_dash_uploader(pyi_builder): + pyi_builder.test_source(""" + import dash_uploader + """) + + +@importorskip('cloudscraper') +def test_cloudscraper(pyi_builder): + pyi_builder.test_source(""" + import cloudscraper + scraper = cloudscraper.create_scraper() + """) + + +@importorskip('mnemonic') +def test_mnemonic(pyi_builder): + pyi_builder.test_source(""" + import mnemonic + mnemonic.Mnemonic("english") + """) + + +@importorskip('pynput') +def test_pynput(pyi_builder): + pyi_builder.test_source(""" + import pynput + """) + + +@importorskip('pystray') +def test_pystray(pyi_builder): + pyi_builder.test_source(""" + import pystray + """) + + +@importorskip('rtree') +def test_rtree(pyi_builder): + pyi_builder.test_source(""" + import rtree + """) + + +@importorskip('pingouin') +def test_pingouin(pyi_builder): + pyi_builder.test_source(""" + import pingouin + """) + + +@importorskip('timezonefinder') +def test_timezonefinder(pyi_builder): + pyi_builder.test_source(""" + from timezonefinder import TimezoneFinder + TimezoneFinder() + """) + + +@importorskip('uvicorn') +def test_uvicorn(pyi_builder): + pyi_builder.test_source(""" + from uvicorn import lifespan, loops + """) + + +@importorskip("langdetect") +def test_langdetect(pyi_builder): + pyi_builder.test_source(""" + import langdetect + print(langdetect.detect("this is a test")) + """) + + +@importorskip("swagger_spec_validator") +def test_swagger_spec_validator(pyi_builder): + pyi_builder.test_source(""" + from swagger_spec_validator.common import read_resource_file + read_resource_file("schemas/v1.2/resourceListing.json") + read_resource_file("schemas/v2.0/schema.json") + """) + + +@requires('pythonnet < 3.dev') +@pytest.mark.skipif(not is_win, reason='pythonnet 2 does not support .Net Core, so its only supported by Windows') +def test_pythonnet2(pyi_builder): + pyi_builder.test_source(""" + import clr + """) + + +@requires('pythonnet >= 3.dev') +def test_pythonnet3(pyi_builder): + pyi_builder.test_source(""" + from clr_loader import get_coreclr + from pythonnet import set_runtime + set_runtime(get_coreclr()) # Pick up and use any installed .NET runtime. + + import clr + """) + + +if is_win: + # This is a hack to prevent monkeypatch from interfering with PyQt5's additional PATH entries. See: + # https://github.com/pyinstaller/pyinstaller/commit/b66c9021129e9e875ddd138a298ce542483dd6c9 + try: + import PyQt5 # noqa: F401 + except ImportError: + pass + + +@importorskip("qtmodern") +@importorskip("PyQt5") +def test_qtmodern(pyi_builder): + pyi_builder.test_source(""" + import sys + from PyQt5 import QtWidgets + import qtmodern.styles + import qtmodern.windows + + app = QtWidgets.QApplication(sys.argv) + window = QtWidgets.QWidget() + qtmodern.styles.dark(app) + modern_window = qtmodern.windows.ModernWindow(window) + modern_window.show() + """) + + +@importorskip("platformdirs") +def test_platformdirs(pyi_builder): + pyi_builder.test_source(""" + import platformdirs + platformdirs.user_data_dir("FooApp", "Mr Foo") + """) + + +@importorskip("websockets") +def test_websockets(pyi_builder): + pyi_builder.test_source("import websockets") + + +@importorskip("tableauhyperapi") +def test_tableauhyperapi(pyi_builder): + pyi_builder.test_source(""" + import tableauhyperapi + """) + + +@importorskip("pymssql") +def test_pymssql(pyi_builder): + pyi_builder.test_source(""" + import pymssql + """) + + +@importorskip("branca") +def test_branca(pyi_builder): + pyi_builder.test_source(""" + import branca + """) + + +@importorskip("folium") +def test_folium(pyi_builder): + pyi_builder.test_source(""" + import folium + m = folium.Map(location=[0, 0], zoom_start=5) + """) + + +@importorskip("metpy") +def test_metpy(pyi_builder): + # Import metpy.plots, which triggers search for colortables data. + pyi_builder.test_source(""" + import metpy.plots + """) + + +@importorskip("pyvjoy") +def test_pyvjoy(pyi_builder): + pyi_builder.test_source(""" + import pyvjoy + """) + + +@importorskip("adbutils") +def test_adbutils(pyi_builder): + # adbutils 0.15.0 renamed adbutils._utils.get_adb_exe() to adb_path() + if is_module_satisfies("adbutils >= 0.15.0"): + pyi_builder.test_source(""" + from adbutils._utils import adb_path; adb_path() + """) + else: + pyi_builder.test_source(""" + from adbutils._utils import get_adb_exe; get_adb_exe() + """) + + +@importorskip("pymediainfo") +def test_pymediainfo(pyi_builder): + pyi_builder.test_source(""" + from pymediainfo import MediaInfo + MediaInfo._get_library() # Trigger search for shared library. + """) + + +@importorskip("sacremoses") +def test_sacremoses(pyi_builder): + pyi_builder.test_source(""" + import sacremoses + """) + + +@importorskip("pypeteer") +def test_pypeteer(pyi_builder): + pyi_builder.test_source(""" + import pypeteer + print(pypeteer.version) + """) + + +@importorskip("tzdata") +@pytest.mark.skipif(not is_py39 and not can_import_module('importlib_resources'), + reason='importlib_resources is required on python < 3.9.') +def test_tzdata(pyi_builder): + pyi_builder.test_source(""" + import tzdata.zoneinfo # hiddenimport + + try: + import importlib.resources as importlib_resources + except ImportError: + import importlib_resources + + # This emulates time-zone data retrieval from tzdata, as peformed by + # zoneinfo / backports.zoneinfo + zone_name = "Europe/Ljubljana" + + components = zone_name.split("/") + package_name = ".".join(["tzdata.zoneinfo"] + components[:-1]) + resource_name = components[-1] + + with importlib_resources.open_binary(package_name, resource_name) as fp: + data = fp.read() + + print(data) + """) + + +@importorskip("backports.zoneinfo") +@pytest.mark.skipif(is_win and not can_import_module('tzdata'), + reason='On Windows, backports.zoneinfo requires tzdata.') +def test_backports_zoneinfo(pyi_builder): + pyi_builder.test_source(""" + from backports import zoneinfo + tz = zoneinfo.ZoneInfo("Europe/Ljubljana") + print(tz) + """) + + +@importorskip("zoneinfo") +@pytest.mark.skipif(is_win and not can_import_module('tzdata'), + reason='On Windows, zoneinfo requires tzdata.') +def test_zoneinfo(pyi_builder): + pyi_builder.test_source(""" + import zoneinfo + tz = zoneinfo.ZoneInfo("Europe/Ljubljana") + print(tz) + """) + + +@importorskip("panel") +def test_panel(pyi_builder): + pyi_builder.test_source(""" + import panel + + # Load the Ace extension to trigger lazy-loading of model + panel.extension("ace") + """) + + +@importorskip("pyviz_comms") +def test_pyviz_comms(pyi_builder): + pyi_builder.test_source(""" + import pyviz_comms + """) + + +@importorskip("pyphen") +def test_pyphen(pyi_builder): + pyi_builder.test_source(""" + import pyphen + """) + + +@importorskip("pandas") +@importorskip("plotly") +@importorskip("kaleido") +def test_kaleido(pyi_builder): + pyi_builder.test_source(""" + import plotly.express as px + fig = px.scatter(px.data.iris(), x="sepal_length", y="sepal_width", color="species") + fig.write_image("figure.png", engine="kaleido") + """) + + +@pytest.mark.skipif(is_win, + reason='On Windows, Cairo dependencies cannot be installed using Chocolatey.') +@importorskip("cairocffi") +def test_cairocffi(pyi_builder): + pyi_builder.test_source(""" + import cairocffi + """) + + +@pytest.mark.skipif(is_win, + reason='On Windows, Cairo dependencies cannot be installed using Chocolatey.') +@importorskip("cairosvg") +def test_cairosvg(pyi_builder): + pyi_builder.test_source(""" + import cairosvg + """) + + +@importorskip("ffpyplayer") +def test_ffpyplayer(pyi_builder): + pyi_builder.test_source(""" + import ffpyplayer.player + """) + + +@importorskip("cv2") +def test_cv2(pyi_builder): + pyi_builder.test_source(""" + import cv2 + """) + + +# Requires OpenCV with enabled HighGUI +@importorskip("cv2") +def test_cv2_highgui(pyi_builder): + from PyInstaller import isolated + + @isolated.decorate + def _get_cv2_highgui_backend(): + import re + import cv2 + + # Find `GUI: ` line in OpenCV build information dump. This is available only in recent OpenCV versions; + # in earlier versions, we would need to parse all subsequent backend entries, which is out of our scope here. + pattern = re.compile(r'$\s*GUI\s*:\s*(?P\S+)\s*^', re.MULTILINE) + info = cv2.getBuildInformation() + m = pattern.search(info) + if not m: + return None + + return m.group('gui') + + has_gui = True + backend = _get_cv2_highgui_backend() + if backend is None: + # We could not determine the backend from OpenCV information; fall back to the dist name + if is_module_satisfies('opencv-python-headless'): + has_gui = False + elif backend == "NONE": + has_gui = False + + if not has_gui: + pytest.skip("OpenCV has no GUI support.") + + pyi_builder.test_source(""" + import cv2 + import numpy as np + + img = np.zeros((64, 64), dtype='uint8') + cv2.imshow("Test", img) + cv2.waitKey(1000) # Wait a second + """) + + +@importorskip("twisted") +def test_twisted_default_reactor(pyi_builder): + pyi_builder.test_source(""" + from twisted.internet import reactor + assert callable(reactor.listenTCP) + """) + + +@importorskip("twisted") +def test_twisted_custom_reactor(pyi_builder): + pyi_builder.test_source(""" + import sys + if sys.platform.startswith("win") and sys.version_info >= (3,7): + import asyncio + asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy()) + from twisted.internet import asyncioreactor + asyncioreactor.install() + from twisted.internet import reactor + assert callable(reactor.listenTCP) + """) + + +@importorskip("pygraphviz") +def test_pygraphviz_bundled_programs(pyi_builder): + # Test that the frozen application is using collected graphviz executables instead of system-installed ones. + pyi_builder.test_source(""" + import sys + import os + import pygraphviz + + bundle_dir = os.path.normpath(sys._MEIPASS) + dot_path = os.path.normpath(pygraphviz.AGraph()._get_prog('dot')) + + assert os.path.commonprefix([dot_path, bundle_dir]) == bundle_dir, \ + f"Invalid program path: {dot_path}!" + """) + + +@importorskip("pypsexec") +def test_pypsexec(pyi_builder): + pyi_builder.test_source(""" + from pypsexec.paexec import paexec_out_stream + next(paexec_out_stream()) + """) + + +@importorskip("mimesis") +def test_mimesis(pyi_builder): + pyi_builder.test_source(""" + from mimesis import Address + Address().address() + """) + + +@importorskip('orjson') +def test_orjson(pyi_builder): + pyi_builder.test_source(""" + import orjson + """) + + +@importorskip('altair') +def test_altair(pyi_builder): + pyi_builder.test_source(""" + import altair + """) + + +@importorskip('fabric') +def test_fabric(pyi_builder): + pyi_builder.test_source(""" + import fabric + """) + + +@importorskip('cassandra') +def test_cassandra(pyi_builder): + pyi_builder.test_source(""" + import cassandra + """) + + +@importorskip('gitlab') +def test_gitlab(pyi_builder): + pyi_builder.test_source(""" + import gitlab + """) + + +@importorskip('graphql_query') +def test_graphql_query(pyi_builder): + pyi_builder.test_source(""" + from graphql_query import Operation, Query + hero = Query(name="hero", fields=["name"]) + operation = Operation(type="query", queries=[hero]) + print(operation.render()) + """) + + +@importorskip('shapely') +def test_shapely(pyi_builder): + pyi_builder.test_source(""" + from shapely.geometry import Point + patch = Point(0.0, 0.0).buffer(10.0) + print(patch.area) + """) + + +@importorskip('lark') +def test_lark(pyi_builder): + pyi_builder.test_source(""" + import lark + parser = lark.Lark(''' + value: "true" + %import common.SIGNED_NUMBER''', + start='value') + """) + + +@importorskip('stdnum') +def test_stdnum_iban(pyi_builder): + pyi_builder.test_source(""" + import stdnum.iban + """) + + +@importorskip('numcodecs') +def test_numcodecs(pyi_builder): + pyi_builder.test_source(""" + # numcodecs uses multiprocessing + import multiprocessing + multiprocessing.freeze_support() + from numcodecs import Blosc + """) + + +@importorskip('pypemicro') +def test_pypemicro(pyi_builder): + pyi_builder.test_source(""" + from pypemicro import PyPemicro + assert PyPemicro.get_pemicro_lib() + """) + + +@importorskip('sounddevice') +def test_sounddevice(pyi_builder): + pyi_builder.test_source(""" + import sounddevice + """) + + +@importorskip('soundfile') +def test_soundfile(pyi_builder): + pyi_builder.test_source(""" + import soundfile + """) + + +@importorskip('limits') +def test_limits(pyi_builder): + pyi_builder.test_source(""" + import limits + """) + + +@pytest.mark.skipif(is_win, + reason='On Windows, Weasyprint dependencies cannot be installed using Chocolatey.') +@importorskip("weasyprint") +def test_weasyprint(pyi_builder): + pyi_builder.test_source(""" + import weasyprint + """) + + +@importorskip("great_expectations") +def test_great_expectations(pyi_builder): + # Reproduce the error from pyinstaller/pyinstaller-hooks-contrib#445 + pyi_builder.test_source(""" + from great_expectations.render.view import view + v = view.DefaultJinjaView() + """) + + +@importorskip('pyshark') +def test_pyshark(pyi_builder): + pyi_builder.test_source( + """ + import pyshark + #capture = pyshark.FileCapture('/tmp/networkpackages.cap') + #data = [print x for x in capture] + #print(data) + """ + ) + + +@importorskip('pyqtgraph') +@importorskip('PyQt5') +def test_pyqtgraph(pyi_builder): + pyi_builder.test_source( + """ + import pyqtgraph.graphicsItems.PlotItem + import pyqtgraph.graphicsItems.ViewBox.ViewBoxMenu + import pyqtgraph.imageview.ImageView + """, + pyi_args=['--exclude', 'PySide2', '--exclude', 'PySide6', '--exclude', 'PyQt6'] + ) + + +@importorskip('pyqtgraph') +def test_pyqtgraph_colormap(pyi_builder): + pyi_builder.test_source( + """ + import pyqtgraph.colormap + assert pyqtgraph.colormap.listMaps() + """ + ) + + +@importorskip('pyqtgraph') +@importorskip('PyQt5') +def test_pyqtgraph_remote_graphics_view(pyi_builder): + pyi_builder.test_source( + """ + import sys + import os + import signal + + from PyQt5 import QtCore, QtWidgets + import pyqtgraph + + # Multiprocessing is used internally by pyqtgraph.multiprocess + import multiprocessing + multiprocessing.freeze_support() + + # pyqtgraph.multiprocess also uses a subprocess.Popen() to spawn its + # sub-process, so we need to restore _MEIPASS2 to prevent the executable + # to unpacking itself again in the subprocess. + os.environ['_MEIPASS2'] = sys._MEIPASS + + # Create a window with remote graphics view + app = QtWidgets.QApplication(sys.argv) + signal.signal(signal.SIGINT, signal.SIG_DFL) + + window = QtWidgets.QWidget() + layout = QtWidgets.QVBoxLayout(window) + remote_view = pyqtgraph.widgets.RemoteGraphicsView.RemoteGraphicsView() + layout.addWidget(remote_view) + + window.show() + + # Quit after a second + QtCore.QTimer.singleShot(1000, app.exit) + + sys.exit(app.exec_()) + """, + pyi_args=['--exclude', 'PySide2', '--exclude', 'PySide6', '--exclude', 'PyQt6'] + ) + + +# Remove xfail once facebookresearch/hydra#2531 is merged. +@importorskip('hydra') +@xfail( + is_module_satisfies('PyInstaller >= 5.8'), + reason="uses deprecated PEP-302 functionality that was removed from PyInstaller's FrozenImporter.") +def test_hydra(pyi_builder, tmpdir): + config_file = str((Path(__file__) / '../data/test_hydra/config.yaml').resolve(strict=True).as_posix()) + + pyi_builder.test_source( + """ + import os + + import hydra + from omegaconf import DictConfig, OmegaConf + + config_path = os.path.join(os.path.dirname(__file__), 'conf') + + @hydra.main(config_path=config_path, config_name="config") + def my_app(cfg): + assert cfg.test_group.secret_string == 'secret' + assert cfg.test_group.secret_number == 123 + + if __name__ == "__main__": + my_app() + """, + pyi_args=['--add-data', os.pathsep.join((config_file, 'conf'))] + ) + + +@importorskip('pywintypes') +def test_pywintypes(pyi_builder): + pyi_builder.test_source(""" + import pywintypes + """) + + +@importorskip('pythoncom') +def test_pythoncom(pyi_builder): + pyi_builder.test_source(""" + import pythoncom + """) + + +@importorskip('spiceypy') +def test_spiceypy(pyi_builder): + pyi_builder.test_source(""" + import spiceypy + """) + + +@importorskip('discid') +def test_discid(pyi_builder): + pyi_builder.test_source( + """ + # Basic import check + import discid + + # Check that shared library is in fact collected into application bundle. + # We expect the hook to collect it to top-level directory (sys._MEIPASS). + import discid.libdiscid + lib_name = discid.libdiscid._LIB_NAME + + lib_file = os.path.join(sys._MEIPASS, lib_name) + assert os.path.isfile(lib_file), f"Shared library {lib_name} not collected to _MEIPASS!" + """ + ) + + +@importorskip('exchangelib') +def test_exchangelib(pyi_builder): + pyi_builder.test_source(""" + import exchangelib + """) + + +@importorskip('cftime') +def test_cftime(pyi_builder): + pyi_builder.test_source(""" + import cftime + """) + + +@importorskip('netCDF4') +def test_netcdf4(pyi_builder): + pyi_builder.test_source(""" + import netCDF4 + """) + + +@importorskip('charset_normalizer') +def test_charset_normalizer(pyi_builder): + pyi_builder.test_source(""" + import base64 + import charset_normalizer + message = base64.b64decode(b"yUCEmYWBlIWEQIFAhJmFgZRAloZAgUCUlpmFQKKFlaKJgpOFQJeBg5KBh4U=") + print(charset_normalizer.from_bytes(message).best()) + """) + + +@importorskip('cf_units') +def test_cf_units(pyi_builder): + pyi_builder.test_source(""" + import cf_units + """) + + +@importorskip('compliance_checker') +def test_compliance_checker(pyi_builder): + # The test file - taken from the package's own test data/examples. Use an .nc file instead of .cdl one, because + # loading the latter requires ncgen utility to be available on the system. + pkg_path = get_module_attribute('compliance_checker', '__path__')[0] + input_file = Path(pkg_path) / 'tests/data/bad-trajectory.nc' + assert input_file.is_file(), f"Selected test file, {input_file!s} does not exist! Fix the test!" + + pyi_builder.test_source(""" + import os + import json + + import compliance_checker + import compliance_checker.runner + + input_file = sys.argv[1] + + # Load all available checker classes + check_suite = compliance_checker.runner.CheckSuite() + check_suite.load_all_available_checkers() + + # Run cf and adcc checks + return_value, errors = compliance_checker.runner.ComplianceChecker.run_checker( + input_file, + checker_names=['cf', 'acdd'], + verbose=False, + criteria='normal', + output_filename='-', + output_format='json') + + # We do not really care about validation results, just that validation finished without raising any exceptions. + print("Return value:", return_value) + print("Errors occurred:", errors) + """, app_args=[str(input_file)]) + + +@importorskip('nbt') +def test_nbt(pyi_builder): + pyi_builder.test_source(""" + import nbt + """) + + +@importorskip('minecraft_launcher_lib') +def test_minecraft_launcher_lib(pyi_builder): + pyi_builder.test_source( + ''' + import minecraft_launcher_lib + assert isinstance(minecraft_launcher_lib.utils.get_library_version(), str) + ''' + ) + + +@importorskip('moviepy') +def test_moviepy_editor(pyi_builder): + # `moviepy.editor` tries to access the `moviepy.video.fx` and `moviepy.audio.fx` plugins/modules via the + # `moviepy.video.fx.all` and `moviepy.video.fx.all` modules, which in turn programmatically import and + # forward all corresponding submodules. + pyi_builder.test_source(""" + import moviepy.editor + """) + + +@importorskip('customtkinter') +def test_customtkinter(pyi_builder): + pyi_builder.test_source(""" + import customtkinter + """) + + +@importorskip('pylibmagic') +def test_pylibmagic(pyi_builder): + pyi_builder.test_source(""" + import pylibmagic + import os + import sys + + bundle_dir = os.path.normpath(sys._MEIPASS) + pylibmagic_data_path = f"{bundle_dir}/pylibmagic" + + files_to_assert = ["magic.mgc"] + if sys.platform == 'darwin': + files_to_assert.append("libmagic.1.dylib") + elif sys.platform.startswith('linux'): + files_to_assert.append("libmagic.so.1") + + for file in files_to_assert: + assert os.path.isfile(f"{pylibmagic_data_path}/{file}"), \ + f"The {file} was not collected to _MEIPASS!" + """) + + +@importorskip('fastparquet') +def test_fastparquet(pyi_builder): + pyi_builder.test_source(""" + import fastparquet + """) + + +@importorskip('librosa') +def test_librosa(pyi_builder): + pyi_builder.test_source(""" + import librosa + + # Requires intervals.msgpack data file + import librosa.core.intervals + + # Requires example files on import + import librosa.util.files + """) + + +@importorskip('librosa') +def test_librosa_util_function(pyi_builder): + # Test that functions from `librosa.util` that use `numba` vectorization can be run in frozen application. + pyi_builder.test_source(""" + import librosa.util + import numpy as np + + x = np.array([1, 0, 1, 2, -1, 0, -2, 1]) + result = librosa.util.localmin(x) + expected = np.array([False, True, False, False, True, False, True, False]) + assert (result == expected).all() + """) + + +@importorskip('sympy') +def test_sympy(pyi_builder): + pyi_builder.test_source(""" + import sympy + """) + + +@importorskip('bokeh') +def test_bokeh(pyi_builder): + pyi_builder.test_source(""" + import bokeh + """) + + +@importorskip('xyzservices') +def test_xyzservices(pyi_builder): + pyi_builder.test_source(""" + import xyzservices.providers + print(xyzservices.providers.CartoDB) + """) + + +@importorskip('mistune') +def test_mistune(pyi_builder): + pyi_builder.test_source(""" + import mistune + """) + + +@importorskip('jsonschema') +def test_jsonschema(pyi_builder): + pyi_builder.test_source(""" + import jsonschema + + # Sample schema + schema = { + "type" : "object", + "properties" : { + "price" : {"type" : "number"}, + "name" : {"type" : "string"}, + }, + } + + jsonschema.validate(instance={"name" : "Eggs", "price" : 3.38}, schema=schema) + + try: + jsonschema.validate(instance={"name" : "Eggs", "price" : "Invalid"}, schema=schema) + except jsonschema.ValidationError as e: + print(f"Validation error: {e}") + """) + + +@importorskip('psutil') +def test_psutil(pyi_builder): + pyi_builder.test_source(""" + import psutil + """) + + +@importorskip('litestar') +def test_litestar(pyi_builder): + pyi_builder.test_source(""" + from litestar import Litestar, get + from litestar.testing import TestClient + from typing import Dict, Any + + + @get("/sync", sync_to_thread=False) + def sync_hello_world() -> Dict[str, Any]: + return {"hello": "world"} + + + app = Litestar(route_handlers=[sync_hello_world]) + client = TestClient(app) + response = client.get("/sync") + assert response.status_code == 200 + assert response.json() == {"hello": "world"} + """) + + +@importorskip('lingua') +def test_lingua_language_detector(pyi_builder): + pyi_builder.test_source(""" + from lingua import Language, LanguageDetectorBuilder + + languages = [Language.ENGLISH, Language.FRENCH, Language.GERMAN, Language.SPANISH] + detector = LanguageDetectorBuilder.from_languages(*languages).build() + + assert detector.detect_language_of("languages are awesome") == Language.ENGLISH + """) + + +@importorskip('opencc') +def test_opencc(pyi_builder): + pyi_builder.test_source(""" + import opencc + + cc = opencc.OpenCC('s2t') + + assert cc.convert('开放中文转换') == '開放中文轉換' + """) + + +@importorskip('jieba') +def test_jieba(pyi_builder): + pyi_builder.test_source(""" + import jieba + + assert jieba.lcut('我来到北京清华大学') == ['我', '来到', '北京', '清华大学'] + """) + + +@importorskip('simplemma') +def test_simplemma(pyi_builder): + pyi_builder.test_source(""" + import simplemma + + assert simplemma.lemmatize('tests', lang='en') == 'test' + """) + + +@importorskip('wordcloud') +def test_wordcloud(pyi_builder): + pyi_builder.test_source(""" + import wordcloud + + wordcloud.WordCloud().generate('test') + """) + + +@importorskip('eng_to_ipa') +def test_eng_to_ipa(pyi_builder): + pyi_builder.test_source(""" + import eng_to_ipa + """) + + +@importorskip('mecab') +def test_mecab(pyi_builder): + pyi_builder.test_source(""" + import mecab + + mecab.MeCab() + """) + + +@importorskip('khmernltk') +def test_khmernltk(pyi_builder): + pyi_builder.test_source(""" + import khmernltk + """) + + +@importorskip('pycrfsuite') +def test_pycrfsuite(pyi_builder): + pyi_builder.test_source(""" + import pycrfsuite + """) + + +@importorskip('pymorphy3') +def test_pymorphy3(pyi_builder): + # Language availability depends on installed packages. + available_languages = [] + if can_import_module('pymorphy3_dicts_ru'): + available_languages.append('ru') + if can_import_module('pymorphy3_dicts_uk'): + available_languages.append('uk') + + pyi_builder.test_source(""" + import sys + import pymorphy3 + + languages = sys.argv[1:] + print(f"Languages to test: {languages}") + + for language in languages: + pymorphy3.MorphAnalyzer(lang=language) + """, app_args=available_languages) + + +@importorskip('sudachipy') +@importorskip('sudachidict_small') +@importorskip('sudachidict_core') +@importorskip('sudachidict_full') +def test_sudachipy(pyi_builder): + pyi_builder.test_source(""" + from sudachipy import Dictionary + + Dictionary(dict='small').create() + Dictionary(dict='core').create() + Dictionary(dict='full').create() + """) + + +@importorskip('laonlp') +def test_laonlp(pyi_builder): + pyi_builder.test_source(""" + import laonlp + """) + + +@importorskip('pythainlp') +def test_pythainlp(pyi_builder): + pyi_builder.test_source(""" + import pythainlp + """) + + +@importorskip('gmsh') +def test_gmsh(pyi_builder): + pyi_builder.test_source(""" + import gmsh + """) + + +@importorskip('sspilib') +def test_sspilib(pyi_builder): + pyi_builder.test_source(""" + import sspilib + + cred = sspilib.UserCredential( + "username@DOMAIN.COM", + "password", + ) + + ctx = sspilib.ClientSecurityContext( + "host/server.domain.com", + credential=cred, + ) + + print(ctx) + """) + + +@importorskip('rlp') +def test_rlp(pyi_builder): + pyi_builder.test_source(""" + import rlp + """) + + +@importorskip('eth_rlp') +def test_eth_rlp(pyi_builder): + pyi_builder.test_source(""" + import eth_rlp + """) + + +@importorskip('z3c.rml') +def test_z3c_rml_rml2pdf(pyi_builder): + pyi_builder.test_source(""" + from z3c.rml import rml2pdf + + rml = ''' + + + + + + Welcome to RML. + + + ''' + + pdf_bytes = rml2pdf.parseString(rml) + """) + + +@importorskip('freetype') +def test_pyi_freetype(pyi_builder): + pyi_builder.test_source(""" + import sys + import pathlib + + import freetype + + # Ensure that the freetype shared library is bundled with the frozen application; otherwise, freetype might be + # using system-wide library. + + # First, check that freetype.FT_Library_filename is an absolute path; otherwise, it is likely using + # basename-only ctypes fallback. + ft_library_file = pathlib.Path(freetype.FT_Library_filename) + print(f"FT library file (original): {ft_library_file}", file=sys.stderr) + assert ft_library_file.is_absolute(), "FT library file is not an absolute path!" + + # Check that fully-resolved freetype.FT_Library_filename is anchored in fully-resolved frozen application + # directory. + app_dir = pathlib.Path(__file__).resolve().parent + print(f"Application directory: {app_dir}", file=sys.stderr) + ft_library_path = pathlib.Path(ft_library_file).resolve() + print(f"FT library file (resolved): {ft_library_path}", file=sys.stderr) + assert app_dir in ft_library_path.parents, "FT library is not bundled with frozen application!" + """) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/test_wx_lib_pubsub.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/test_wx_lib_pubsub.py new file mode 100644 index 000000000..9306f7abd --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pyinstaller_hooks_contrib/tests/test_wx_lib_pubsub.py @@ -0,0 +1,64 @@ +#----------------------------------------------------------------------------- +# Copyright (c) 2005-2023, PyInstaller Development Team. +# +# Distributed under the terms of the GNU General Public License (version 2 +# or later) with exception for distributing the bootloader. +# +# The full license is in the file COPYING.txt, distributed with this software. +# +# SPDX-License-Identifier: (GPL-2.0-or-later WITH Bootloader-exception) +#----------------------------------------------------------------------------- + +from PyInstaller.utils.tests import importorskip + + +@importorskip('wx.lib.pubsub') +def test_wx_lib_pubsub_protocol_default(pyi_builder): + pyi_builder.test_source( + """ + from wx.lib.pubsub import pub + + def on_message(number): + print('Message received.') + if not number == 762: + raise SystemExit('Message data "762" expected but received "%s".' % str(number)) + + pub.subscribe(on_message, 'topic.subtopic') + pub.sendMessage('topic.subtopic', number=762) + """) + + +# Functional test exercising the non-default protocol `arg1` of version 3 of the PyPubSub API. +@importorskip('wx.lib.pubsub.core') +def test_wx_lib_pubsub_protocol_kwargs(pyi_builder): + pyi_builder.test_source( + """ + from wx.lib.pubsub import setuparg1 # noqa: F401 + from wx.lib.pubsub import pub + + def on_message(message): + print('Message received.') + if not message.data == 762: + raise SystemExit('Message data "762" expected but received "%s".' % str(message.data)) + + pub.subscribe(on_message, 'topic.subtopic') + pub.sendMessage('topic.subtopic', 762) + """) + + +# Functional test exercising the default protocol `kwargs` of version 3 of the PyPubSub API. +@importorskip('wx.lib.pubsub.core') +def test_wx_lib_pubsub_protocol_arg1(pyi_builder): + pyi_builder.test_source( + """ + from wx.lib.pubsub import setupkwargs # noqa: F401 + from wx.lib.pubsub import pub + + def on_message(number): + print('Message received.') + if not number == 762: + raise SystemExit('Message data "762" expected but received "%s".' % str(number)) + + pub.subscribe(on_message, 'topic.subtopic') + pub.sendMessage('topic.subtopic', number=762) + """) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/__init__.py new file mode 100644 index 000000000..8a406c5c7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/__init__.py @@ -0,0 +1,9 @@ +__all__ = ["__version__", "version_tuple"] + +try: + from ._version import version as __version__, version_tuple +except ImportError: # pragma: no cover + # broken installation, we don't even try + # unknown only works because we do poor mans version compare + __version__ = "unknown" + version_tuple = (0, 0, "unknown") # type:ignore[assignment] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_argcomplete.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_argcomplete.py new file mode 100644 index 000000000..6a8083770 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_argcomplete.py @@ -0,0 +1,116 @@ +"""Allow bash-completion for argparse with argcomplete if installed. + +Needs argcomplete>=0.5.6 for python 3.2/3.3 (older versions fail +to find the magic string, so _ARGCOMPLETE env. var is never set, and +this does not need special code). + +Function try_argcomplete(parser) should be called directly before +the call to ArgumentParser.parse_args(). + +The filescompleter is what you normally would use on the positional +arguments specification, in order to get "dirname/" after "dirn" +instead of the default "dirname ": + + optparser.add_argument(Config._file_or_dir, nargs='*').completer=filescompleter + +Other, application specific, completers should go in the file +doing the add_argument calls as they need to be specified as .completer +attributes as well. (If argcomplete is not installed, the function the +attribute points to will not be used). + +SPEEDUP +======= + +The generic argcomplete script for bash-completion +(/etc/bash_completion.d/python-argcomplete.sh) +uses a python program to determine startup script generated by pip. +You can speed up completion somewhat by changing this script to include + # PYTHON_ARGCOMPLETE_OK +so the python-argcomplete-check-easy-install-script does not +need to be called to find the entry point of the code and see if that is +marked with PYTHON_ARGCOMPLETE_OK. + +INSTALL/DEBUGGING +================= + +To include this support in another application that has setup.py generated +scripts: + +- Add the line: + # PYTHON_ARGCOMPLETE_OK + near the top of the main python entry point. + +- Include in the file calling parse_args(): + from _argcomplete import try_argcomplete, filescompleter + Call try_argcomplete just before parse_args(), and optionally add + filescompleter to the positional arguments' add_argument(). + +If things do not work right away: + +- Switch on argcomplete debugging with (also helpful when doing custom + completers): + export _ARC_DEBUG=1 + +- Run: + python-argcomplete-check-easy-install-script $(which appname) + echo $? + will echo 0 if the magic line has been found, 1 if not. + +- Sometimes it helps to find early on errors using: + _ARGCOMPLETE=1 _ARC_DEBUG=1 appname + which should throw a KeyError: 'COMPLINE' (which is properly set by the + global argcomplete script). +""" +import argparse +import os +import sys +from glob import glob +from typing import Any +from typing import List +from typing import Optional + + +class FastFilesCompleter: + """Fast file completer class.""" + + def __init__(self, directories: bool = True) -> None: + self.directories = directories + + def __call__(self, prefix: str, **kwargs: Any) -> List[str]: + # Only called on non option completions. + if os.sep in prefix[1:]: + prefix_dir = len(os.path.dirname(prefix) + os.sep) + else: + prefix_dir = 0 + completion = [] + globbed = [] + if "*" not in prefix and "?" not in prefix: + # We are on unix, otherwise no bash. + if not prefix or prefix[-1] == os.sep: + globbed.extend(glob(prefix + ".*")) + prefix += "*" + globbed.extend(glob(prefix)) + for x in sorted(globbed): + if os.path.isdir(x): + x += "/" + # Append stripping the prefix (like bash, not like compgen). + completion.append(x[prefix_dir:]) + return completion + + +if os.environ.get("_ARGCOMPLETE"): + try: + import argcomplete.completers + except ImportError: + sys.exit(-1) + filescompleter: Optional[FastFilesCompleter] = FastFilesCompleter() + + def try_argcomplete(parser: argparse.ArgumentParser) -> None: + argcomplete.autocomplete(parser, always_complete_options=False) + +else: + + def try_argcomplete(parser: argparse.ArgumentParser) -> None: + pass + + filescompleter = None diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_code/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_code/__init__.py new file mode 100644 index 000000000..511d0dde6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_code/__init__.py @@ -0,0 +1,22 @@ +"""Python inspection/code generation API.""" +from .code import Code +from .code import ExceptionInfo +from .code import filter_traceback +from .code import Frame +from .code import getfslineno +from .code import Traceback +from .code import TracebackEntry +from .source import getrawcode +from .source import Source + +__all__ = [ + "Code", + "ExceptionInfo", + "filter_traceback", + "Frame", + "getfslineno", + "getrawcode", + "Traceback", + "TracebackEntry", + "Source", +] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_code/code.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_code/code.py new file mode 100644 index 000000000..9b051332b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_code/code.py @@ -0,0 +1,1337 @@ +import ast +import dataclasses +import inspect +import os +import re +import sys +import traceback +from inspect import CO_VARARGS +from inspect import CO_VARKEYWORDS +from io import StringIO +from pathlib import Path +from traceback import format_exception_only +from types import CodeType +from types import FrameType +from types import TracebackType +from typing import Any +from typing import Callable +from typing import ClassVar +from typing import Dict +from typing import Generic +from typing import Iterable +from typing import List +from typing import Mapping +from typing import Optional +from typing import overload +from typing import Pattern +from typing import Sequence +from typing import Set +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import TypeVar +from typing import Union + +import pluggy + +import _pytest +from _pytest._code.source import findsource +from _pytest._code.source import getrawcode +from _pytest._code.source import getstatementrange_ast +from _pytest._code.source import Source +from _pytest._io import TerminalWriter +from _pytest._io.saferepr import safeformat +from _pytest._io.saferepr import saferepr +from _pytest.compat import final +from _pytest.compat import get_real_func +from _pytest.deprecated import check_ispytest +from _pytest.pathlib import absolutepath +from _pytest.pathlib import bestrelpath + +if TYPE_CHECKING: + from typing_extensions import Final + from typing_extensions import Literal + from typing_extensions import SupportsIndex + + _TracebackStyle = Literal["long", "short", "line", "no", "native", "value", "auto"] + +if sys.version_info[:2] < (3, 11): + from exceptiongroup import BaseExceptionGroup + + +class Code: + """Wrapper around Python code objects.""" + + __slots__ = ("raw",) + + def __init__(self, obj: CodeType) -> None: + self.raw = obj + + @classmethod + def from_function(cls, obj: object) -> "Code": + return cls(getrawcode(obj)) + + def __eq__(self, other): + return self.raw == other.raw + + # Ignore type because of https://github.com/python/mypy/issues/4266. + __hash__ = None # type: ignore + + @property + def firstlineno(self) -> int: + return self.raw.co_firstlineno - 1 + + @property + def name(self) -> str: + return self.raw.co_name + + @property + def path(self) -> Union[Path, str]: + """Return a path object pointing to source code, or an ``str`` in + case of ``OSError`` / non-existing file.""" + if not self.raw.co_filename: + return "" + try: + p = absolutepath(self.raw.co_filename) + # maybe don't try this checking + if not p.exists(): + raise OSError("path check failed.") + return p + except OSError: + # XXX maybe try harder like the weird logic + # in the standard lib [linecache.updatecache] does? + return self.raw.co_filename + + @property + def fullsource(self) -> Optional["Source"]: + """Return a _pytest._code.Source object for the full source file of the code.""" + full, _ = findsource(self.raw) + return full + + def source(self) -> "Source": + """Return a _pytest._code.Source object for the code object's source only.""" + # return source only for that part of code + return Source(self.raw) + + def getargs(self, var: bool = False) -> Tuple[str, ...]: + """Return a tuple with the argument names for the code object. + + If 'var' is set True also return the names of the variable and + keyword arguments when present. + """ + # Handy shortcut for getting args. + raw = self.raw + argcount = raw.co_argcount + if var: + argcount += raw.co_flags & CO_VARARGS + argcount += raw.co_flags & CO_VARKEYWORDS + return raw.co_varnames[:argcount] + + +class Frame: + """Wrapper around a Python frame holding f_locals and f_globals + in which expressions can be evaluated.""" + + __slots__ = ("raw",) + + def __init__(self, frame: FrameType) -> None: + self.raw = frame + + @property + def lineno(self) -> int: + return self.raw.f_lineno - 1 + + @property + def f_globals(self) -> Dict[str, Any]: + return self.raw.f_globals + + @property + def f_locals(self) -> Dict[str, Any]: + return self.raw.f_locals + + @property + def code(self) -> Code: + return Code(self.raw.f_code) + + @property + def statement(self) -> "Source": + """Statement this frame is at.""" + if self.code.fullsource is None: + return Source("") + return self.code.fullsource.getstatement(self.lineno) + + def eval(self, code, **vars): + """Evaluate 'code' in the frame. + + 'vars' are optional additional local variables. + + Returns the result of the evaluation. + """ + f_locals = self.f_locals.copy() + f_locals.update(vars) + return eval(code, self.f_globals, f_locals) + + def repr(self, object: object) -> str: + """Return a 'safe' (non-recursive, one-line) string repr for 'object'.""" + return saferepr(object) + + def getargs(self, var: bool = False): + """Return a list of tuples (name, value) for all arguments. + + If 'var' is set True, also include the variable and keyword arguments + when present. + """ + retval = [] + for arg in self.code.getargs(var): + try: + retval.append((arg, self.f_locals[arg])) + except KeyError: + pass # this can occur when using Psyco + return retval + + +class TracebackEntry: + """A single entry in a Traceback.""" + + __slots__ = ("_rawentry", "_repr_style") + + def __init__( + self, + rawentry: TracebackType, + repr_style: Optional['Literal["short", "long"]'] = None, + ) -> None: + self._rawentry: "Final" = rawentry + self._repr_style: "Final" = repr_style + + def with_repr_style( + self, repr_style: Optional['Literal["short", "long"]'] + ) -> "TracebackEntry": + return TracebackEntry(self._rawentry, repr_style) + + @property + def lineno(self) -> int: + return self._rawentry.tb_lineno - 1 + + @property + def frame(self) -> Frame: + return Frame(self._rawentry.tb_frame) + + @property + def relline(self) -> int: + return self.lineno - self.frame.code.firstlineno + + def __repr__(self) -> str: + return "" % (self.frame.code.path, self.lineno + 1) + + @property + def statement(self) -> "Source": + """_pytest._code.Source object for the current statement.""" + source = self.frame.code.fullsource + assert source is not None + return source.getstatement(self.lineno) + + @property + def path(self) -> Union[Path, str]: + """Path to the source code.""" + return self.frame.code.path + + @property + def locals(self) -> Dict[str, Any]: + """Locals of underlying frame.""" + return self.frame.f_locals + + def getfirstlinesource(self) -> int: + return self.frame.code.firstlineno + + def getsource( + self, astcache: Optional[Dict[Union[str, Path], ast.AST]] = None + ) -> Optional["Source"]: + """Return failing source code.""" + # we use the passed in astcache to not reparse asttrees + # within exception info printing + source = self.frame.code.fullsource + if source is None: + return None + key = astnode = None + if astcache is not None: + key = self.frame.code.path + if key is not None: + astnode = astcache.get(key, None) + start = self.getfirstlinesource() + try: + astnode, _, end = getstatementrange_ast( + self.lineno, source, astnode=astnode + ) + except SyntaxError: + end = self.lineno + 1 + else: + if key is not None and astcache is not None: + astcache[key] = astnode + return source[start:end] + + source = property(getsource) + + def ishidden(self, excinfo: Optional["ExceptionInfo[BaseException]"]) -> bool: + """Return True if the current frame has a var __tracebackhide__ + resolving to True. + + If __tracebackhide__ is a callable, it gets called with the + ExceptionInfo instance and can decide whether to hide the traceback. + + Mostly for internal use. + """ + tbh: Union[ + bool, Callable[[Optional[ExceptionInfo[BaseException]]], bool] + ] = False + for maybe_ns_dct in (self.frame.f_locals, self.frame.f_globals): + # in normal cases, f_locals and f_globals are dictionaries + # however via `exec(...)` / `eval(...)` they can be other types + # (even incorrect types!). + # as such, we suppress all exceptions while accessing __tracebackhide__ + try: + tbh = maybe_ns_dct["__tracebackhide__"] + except Exception: + pass + else: + break + if tbh and callable(tbh): + return tbh(excinfo) + return tbh + + def __str__(self) -> str: + name = self.frame.code.name + try: + line = str(self.statement).lstrip() + except KeyboardInterrupt: + raise + except BaseException: + line = "???" + # This output does not quite match Python's repr for traceback entries, + # but changing it to do so would break certain plugins. See + # https://github.com/pytest-dev/pytest/pull/7535/ for details. + return " File %r:%d in %s\n %s\n" % ( + str(self.path), + self.lineno + 1, + name, + line, + ) + + @property + def name(self) -> str: + """co_name of underlying code.""" + return self.frame.code.raw.co_name + + +class Traceback(List[TracebackEntry]): + """Traceback objects encapsulate and offer higher level access to Traceback entries.""" + + def __init__( + self, + tb: Union[TracebackType, Iterable[TracebackEntry]], + ) -> None: + """Initialize from given python traceback object and ExceptionInfo.""" + if isinstance(tb, TracebackType): + + def f(cur: TracebackType) -> Iterable[TracebackEntry]: + cur_: Optional[TracebackType] = cur + while cur_ is not None: + yield TracebackEntry(cur_) + cur_ = cur_.tb_next + + super().__init__(f(tb)) + else: + super().__init__(tb) + + def cut( + self, + path: Optional[Union["os.PathLike[str]", str]] = None, + lineno: Optional[int] = None, + firstlineno: Optional[int] = None, + excludepath: Optional["os.PathLike[str]"] = None, + ) -> "Traceback": + """Return a Traceback instance wrapping part of this Traceback. + + By providing any combination of path, lineno and firstlineno, the + first frame to start the to-be-returned traceback is determined. + + This allows cutting the first part of a Traceback instance e.g. + for formatting reasons (removing some uninteresting bits that deal + with handling of the exception/traceback). + """ + path_ = None if path is None else os.fspath(path) + excludepath_ = None if excludepath is None else os.fspath(excludepath) + for x in self: + code = x.frame.code + codepath = code.path + if path is not None and str(codepath) != path_: + continue + if ( + excludepath is not None + and isinstance(codepath, Path) + and excludepath_ in (str(p) for p in codepath.parents) # type: ignore[operator] + ): + continue + if lineno is not None and x.lineno != lineno: + continue + if firstlineno is not None and x.frame.code.firstlineno != firstlineno: + continue + return Traceback(x._rawentry) + return self + + @overload + def __getitem__(self, key: "SupportsIndex") -> TracebackEntry: + ... + + @overload + def __getitem__(self, key: slice) -> "Traceback": + ... + + def __getitem__( + self, key: Union["SupportsIndex", slice] + ) -> Union[TracebackEntry, "Traceback"]: + if isinstance(key, slice): + return self.__class__(super().__getitem__(key)) + else: + return super().__getitem__(key) + + def filter( + self, + # TODO(py38): change to positional only. + _excinfo_or_fn: Union[ + "ExceptionInfo[BaseException]", + Callable[[TracebackEntry], bool], + ], + ) -> "Traceback": + """Return a Traceback instance with certain items removed. + + If the filter is an `ExceptionInfo`, removes all the ``TracebackEntry``s + which are hidden (see ishidden() above). + + Otherwise, the filter is a function that gets a single argument, a + ``TracebackEntry`` instance, and should return True when the item should + be added to the ``Traceback``, False when not. + """ + if isinstance(_excinfo_or_fn, ExceptionInfo): + fn = lambda x: not x.ishidden(_excinfo_or_fn) # noqa: E731 + else: + fn = _excinfo_or_fn + return Traceback(filter(fn, self)) + + def recursionindex(self) -> Optional[int]: + """Return the index of the frame/TracebackEntry where recursion originates if + appropriate, None if no recursion occurred.""" + cache: Dict[Tuple[Any, int, int], List[Dict[str, Any]]] = {} + for i, entry in enumerate(self): + # id for the code.raw is needed to work around + # the strange metaprogramming in the decorator lib from pypi + # which generates code objects that have hash/value equality + # XXX needs a test + key = entry.frame.code.path, id(entry.frame.code.raw), entry.lineno + # print "checking for recursion at", key + values = cache.setdefault(key, []) + if values: + f = entry.frame + loc = f.f_locals + for otherloc in values: + if otherloc == loc: + return i + values.append(entry.frame.f_locals) + return None + + +E = TypeVar("E", bound=BaseException, covariant=True) + + +@final +@dataclasses.dataclass +class ExceptionInfo(Generic[E]): + """Wraps sys.exc_info() objects and offers help for navigating the traceback.""" + + _assert_start_repr: ClassVar = "AssertionError('assert " + + _excinfo: Optional[Tuple[Type["E"], "E", TracebackType]] + _striptext: str + _traceback: Optional[Traceback] + + def __init__( + self, + excinfo: Optional[Tuple[Type["E"], "E", TracebackType]], + striptext: str = "", + traceback: Optional[Traceback] = None, + *, + _ispytest: bool = False, + ) -> None: + check_ispytest(_ispytest) + self._excinfo = excinfo + self._striptext = striptext + self._traceback = traceback + + @classmethod + def from_exception( + cls, + # Ignoring error: "Cannot use a covariant type variable as a parameter". + # This is OK to ignore because this class is (conceptually) readonly. + # See https://github.com/python/mypy/issues/7049. + exception: E, # type: ignore[misc] + exprinfo: Optional[str] = None, + ) -> "ExceptionInfo[E]": + """Return an ExceptionInfo for an existing exception. + + The exception must have a non-``None`` ``__traceback__`` attribute, + otherwise this function fails with an assertion error. This means that + the exception must have been raised, or added a traceback with the + :py:meth:`~BaseException.with_traceback()` method. + + :param exprinfo: + A text string helping to determine if we should strip + ``AssertionError`` from the output. Defaults to the exception + message/``__str__()``. + + .. versionadded:: 7.4 + """ + assert ( + exception.__traceback__ + ), "Exceptions passed to ExcInfo.from_exception(...) must have a non-None __traceback__." + exc_info = (type(exception), exception, exception.__traceback__) + return cls.from_exc_info(exc_info, exprinfo) + + @classmethod + def from_exc_info( + cls, + exc_info: Tuple[Type[E], E, TracebackType], + exprinfo: Optional[str] = None, + ) -> "ExceptionInfo[E]": + """Like :func:`from_exception`, but using old-style exc_info tuple.""" + _striptext = "" + if exprinfo is None and isinstance(exc_info[1], AssertionError): + exprinfo = getattr(exc_info[1], "msg", None) + if exprinfo is None: + exprinfo = saferepr(exc_info[1]) + if exprinfo and exprinfo.startswith(cls._assert_start_repr): + _striptext = "AssertionError: " + + return cls(exc_info, _striptext, _ispytest=True) + + @classmethod + def from_current( + cls, exprinfo: Optional[str] = None + ) -> "ExceptionInfo[BaseException]": + """Return an ExceptionInfo matching the current traceback. + + .. warning:: + + Experimental API + + :param exprinfo: + A text string helping to determine if we should strip + ``AssertionError`` from the output. Defaults to the exception + message/``__str__()``. + """ + tup = sys.exc_info() + assert tup[0] is not None, "no current exception" + assert tup[1] is not None, "no current exception" + assert tup[2] is not None, "no current exception" + exc_info = (tup[0], tup[1], tup[2]) + return ExceptionInfo.from_exc_info(exc_info, exprinfo) + + @classmethod + def for_later(cls) -> "ExceptionInfo[E]": + """Return an unfilled ExceptionInfo.""" + return cls(None, _ispytest=True) + + def fill_unfilled(self, exc_info: Tuple[Type[E], E, TracebackType]) -> None: + """Fill an unfilled ExceptionInfo created with ``for_later()``.""" + assert self._excinfo is None, "ExceptionInfo was already filled" + self._excinfo = exc_info + + @property + def type(self) -> Type[E]: + """The exception class.""" + assert ( + self._excinfo is not None + ), ".type can only be used after the context manager exits" + return self._excinfo[0] + + @property + def value(self) -> E: + """The exception value.""" + assert ( + self._excinfo is not None + ), ".value can only be used after the context manager exits" + return self._excinfo[1] + + @property + def tb(self) -> TracebackType: + """The exception raw traceback.""" + assert ( + self._excinfo is not None + ), ".tb can only be used after the context manager exits" + return self._excinfo[2] + + @property + def typename(self) -> str: + """The type name of the exception.""" + assert ( + self._excinfo is not None + ), ".typename can only be used after the context manager exits" + return self.type.__name__ + + @property + def traceback(self) -> Traceback: + """The traceback.""" + if self._traceback is None: + self._traceback = Traceback(self.tb) + return self._traceback + + @traceback.setter + def traceback(self, value: Traceback) -> None: + self._traceback = value + + def __repr__(self) -> str: + if self._excinfo is None: + return "" + return "<{} {} tblen={}>".format( + self.__class__.__name__, saferepr(self._excinfo[1]), len(self.traceback) + ) + + def exconly(self, tryshort: bool = False) -> str: + """Return the exception as a string. + + When 'tryshort' resolves to True, and the exception is an + AssertionError, only the actual exception part of the exception + representation is returned (so 'AssertionError: ' is removed from + the beginning). + """ + lines = format_exception_only(self.type, self.value) + text = "".join(lines) + text = text.rstrip() + if tryshort: + if text.startswith(self._striptext): + text = text[len(self._striptext) :] + return text + + def errisinstance( + self, exc: Union[Type[BaseException], Tuple[Type[BaseException], ...]] + ) -> bool: + """Return True if the exception is an instance of exc. + + Consider using ``isinstance(excinfo.value, exc)`` instead. + """ + return isinstance(self.value, exc) + + def _getreprcrash(self) -> Optional["ReprFileLocation"]: + # Find last non-hidden traceback entry that led to the exception of the + # traceback, or None if all hidden. + for i in range(-1, -len(self.traceback) - 1, -1): + entry = self.traceback[i] + if not entry.ishidden(self): + path, lineno = entry.frame.code.raw.co_filename, entry.lineno + exconly = self.exconly(tryshort=True) + return ReprFileLocation(path, lineno + 1, exconly) + return None + + def getrepr( + self, + showlocals: bool = False, + style: "_TracebackStyle" = "long", + abspath: bool = False, + tbfilter: Union[ + bool, Callable[["ExceptionInfo[BaseException]"], Traceback] + ] = True, + funcargs: bool = False, + truncate_locals: bool = True, + chain: bool = True, + ) -> Union["ReprExceptionInfo", "ExceptionChainRepr"]: + """Return str()able representation of this exception info. + + :param bool showlocals: + Show locals per traceback entry. + Ignored if ``style=="native"``. + + :param str style: + long|short|line|no|native|value traceback style. + + :param bool abspath: + If paths should be changed to absolute or left unchanged. + + :param tbfilter: + A filter for traceback entries. + + * If false, don't hide any entries. + * If true, hide internal entries and entries that contain a local + variable ``__tracebackhide__ = True``. + * If a callable, delegates the filtering to the callable. + + Ignored if ``style`` is ``"native"``. + + :param bool funcargs: + Show fixtures ("funcargs" for legacy purposes) per traceback entry. + + :param bool truncate_locals: + With ``showlocals==True``, make sure locals can be safely represented as strings. + + :param bool chain: + If chained exceptions in Python 3 should be shown. + + .. versionchanged:: 3.9 + + Added the ``chain`` parameter. + """ + if style == "native": + return ReprExceptionInfo( + reprtraceback=ReprTracebackNative( + traceback.format_exception( + self.type, + self.value, + self.traceback[0]._rawentry if self.traceback else None, + ) + ), + reprcrash=self._getreprcrash(), + ) + + fmt = FormattedExcinfo( + showlocals=showlocals, + style=style, + abspath=abspath, + tbfilter=tbfilter, + funcargs=funcargs, + truncate_locals=truncate_locals, + chain=chain, + ) + return fmt.repr_excinfo(self) + + def match(self, regexp: Union[str, Pattern[str]]) -> "Literal[True]": + """Check whether the regular expression `regexp` matches the string + representation of the exception using :func:`python:re.search`. + + If it matches `True` is returned, otherwise an `AssertionError` is raised. + """ + __tracebackhide__ = True + value = str(self.value) + msg = f"Regex pattern did not match.\n Regex: {regexp!r}\n Input: {value!r}" + if regexp == value: + msg += "\n Did you mean to `re.escape()` the regex?" + assert re.search(regexp, value), msg + # Return True to allow for "assert excinfo.match()". + return True + + +@dataclasses.dataclass +class FormattedExcinfo: + """Presenting information about failing Functions and Generators.""" + + # for traceback entries + flow_marker: ClassVar = ">" + fail_marker: ClassVar = "E" + + showlocals: bool = False + style: "_TracebackStyle" = "long" + abspath: bool = True + tbfilter: Union[bool, Callable[[ExceptionInfo[BaseException]], Traceback]] = True + funcargs: bool = False + truncate_locals: bool = True + chain: bool = True + astcache: Dict[Union[str, Path], ast.AST] = dataclasses.field( + default_factory=dict, init=False, repr=False + ) + + def _getindent(self, source: "Source") -> int: + # Figure out indent for the given source. + try: + s = str(source.getstatement(len(source) - 1)) + except KeyboardInterrupt: + raise + except BaseException: + try: + s = str(source[-1]) + except KeyboardInterrupt: + raise + except BaseException: + return 0 + return 4 + (len(s) - len(s.lstrip())) + + def _getentrysource(self, entry: TracebackEntry) -> Optional["Source"]: + source = entry.getsource(self.astcache) + if source is not None: + source = source.deindent() + return source + + def repr_args(self, entry: TracebackEntry) -> Optional["ReprFuncArgs"]: + if self.funcargs: + args = [] + for argname, argvalue in entry.frame.getargs(var=True): + args.append((argname, saferepr(argvalue))) + return ReprFuncArgs(args) + return None + + def get_source( + self, + source: Optional["Source"], + line_index: int = -1, + excinfo: Optional[ExceptionInfo[BaseException]] = None, + short: bool = False, + ) -> List[str]: + """Return formatted and marked up source lines.""" + lines = [] + if source is not None and line_index < 0: + line_index += len(source) + if source is None or line_index >= len(source.lines) or line_index < 0: + # `line_index` could still be outside `range(len(source.lines))` if + # we're processing AST with pathological position attributes. + source = Source("???") + line_index = 0 + space_prefix = " " + if short: + lines.append(space_prefix + source.lines[line_index].strip()) + else: + for line in source.lines[:line_index]: + lines.append(space_prefix + line) + lines.append(self.flow_marker + " " + source.lines[line_index]) + for line in source.lines[line_index + 1 :]: + lines.append(space_prefix + line) + if excinfo is not None: + indent = 4 if short else self._getindent(source) + lines.extend(self.get_exconly(excinfo, indent=indent, markall=True)) + return lines + + def get_exconly( + self, + excinfo: ExceptionInfo[BaseException], + indent: int = 4, + markall: bool = False, + ) -> List[str]: + lines = [] + indentstr = " " * indent + # Get the real exception information out. + exlines = excinfo.exconly(tryshort=True).split("\n") + failindent = self.fail_marker + indentstr[1:] + for line in exlines: + lines.append(failindent + line) + if not markall: + failindent = indentstr + return lines + + def repr_locals(self, locals: Mapping[str, object]) -> Optional["ReprLocals"]: + if self.showlocals: + lines = [] + keys = [loc for loc in locals if loc[0] != "@"] + keys.sort() + for name in keys: + value = locals[name] + if name == "__builtins__": + lines.append("__builtins__ = ") + else: + # This formatting could all be handled by the + # _repr() function, which is only reprlib.Repr in + # disguise, so is very configurable. + if self.truncate_locals: + str_repr = saferepr(value) + else: + str_repr = safeformat(value) + # if len(str_repr) < 70 or not isinstance(value, (list, tuple, dict)): + lines.append(f"{name:<10} = {str_repr}") + # else: + # self._line("%-10s =\\" % (name,)) + # # XXX + # pprint.pprint(value, stream=self.excinfowriter) + return ReprLocals(lines) + return None + + def repr_traceback_entry( + self, + entry: Optional[TracebackEntry], + excinfo: Optional[ExceptionInfo[BaseException]] = None, + ) -> "ReprEntry": + lines: List[str] = [] + style = ( + entry._repr_style + if entry is not None and entry._repr_style is not None + else self.style + ) + if style in ("short", "long") and entry is not None: + source = self._getentrysource(entry) + if source is None: + source = Source("???") + line_index = 0 + else: + line_index = entry.lineno - entry.getfirstlinesource() + short = style == "short" + reprargs = self.repr_args(entry) if not short else None + s = self.get_source(source, line_index, excinfo, short=short) + lines.extend(s) + if short: + message = "in %s" % (entry.name) + else: + message = excinfo and excinfo.typename or "" + entry_path = entry.path + path = self._makepath(entry_path) + reprfileloc = ReprFileLocation(path, entry.lineno + 1, message) + localsrepr = self.repr_locals(entry.locals) + return ReprEntry(lines, reprargs, localsrepr, reprfileloc, style) + elif style == "value": + if excinfo: + lines.extend(str(excinfo.value).split("\n")) + return ReprEntry(lines, None, None, None, style) + else: + if excinfo: + lines.extend(self.get_exconly(excinfo, indent=4)) + return ReprEntry(lines, None, None, None, style) + + def _makepath(self, path: Union[Path, str]) -> str: + if not self.abspath and isinstance(path, Path): + try: + np = bestrelpath(Path.cwd(), path) + except OSError: + return str(path) + if len(np) < len(str(path)): + return np + return str(path) + + def repr_traceback(self, excinfo: ExceptionInfo[BaseException]) -> "ReprTraceback": + traceback = excinfo.traceback + if callable(self.tbfilter): + traceback = self.tbfilter(excinfo) + elif self.tbfilter: + traceback = traceback.filter(excinfo) + + if isinstance(excinfo.value, RecursionError): + traceback, extraline = self._truncate_recursive_traceback(traceback) + else: + extraline = None + + if not traceback: + if extraline is None: + extraline = "All traceback entries are hidden. Pass `--full-trace` to see hidden and internal frames." + entries = [self.repr_traceback_entry(None, excinfo)] + return ReprTraceback(entries, extraline, style=self.style) + + last = traceback[-1] + if self.style == "value": + entries = [self.repr_traceback_entry(last, excinfo)] + return ReprTraceback(entries, None, style=self.style) + + entries = [ + self.repr_traceback_entry(entry, excinfo if last == entry else None) + for entry in traceback + ] + return ReprTraceback(entries, extraline, style=self.style) + + def _truncate_recursive_traceback( + self, traceback: Traceback + ) -> Tuple[Traceback, Optional[str]]: + """Truncate the given recursive traceback trying to find the starting + point of the recursion. + + The detection is done by going through each traceback entry and + finding the point in which the locals of the frame are equal to the + locals of a previous frame (see ``recursionindex()``). + + Handle the situation where the recursion process might raise an + exception (for example comparing numpy arrays using equality raises a + TypeError), in which case we do our best to warn the user of the + error and show a limited traceback. + """ + try: + recursionindex = traceback.recursionindex() + except Exception as e: + max_frames = 10 + extraline: Optional[str] = ( + "!!! Recursion error detected, but an error occurred locating the origin of recursion.\n" + " The following exception happened when comparing locals in the stack frame:\n" + " {exc_type}: {exc_msg}\n" + " Displaying first and last {max_frames} stack frames out of {total}." + ).format( + exc_type=type(e).__name__, + exc_msg=str(e), + max_frames=max_frames, + total=len(traceback), + ) + # Type ignored because adding two instances of a List subtype + # currently incorrectly has type List instead of the subtype. + traceback = traceback[:max_frames] + traceback[-max_frames:] # type: ignore + else: + if recursionindex is not None: + extraline = "!!! Recursion detected (same locals & position)" + traceback = traceback[: recursionindex + 1] + else: + extraline = None + + return traceback, extraline + + def repr_excinfo( + self, excinfo: ExceptionInfo[BaseException] + ) -> "ExceptionChainRepr": + repr_chain: List[ + Tuple[ReprTraceback, Optional[ReprFileLocation], Optional[str]] + ] = [] + e: Optional[BaseException] = excinfo.value + excinfo_: Optional[ExceptionInfo[BaseException]] = excinfo + descr = None + seen: Set[int] = set() + while e is not None and id(e) not in seen: + seen.add(id(e)) + + if excinfo_: + # Fall back to native traceback as a temporary workaround until + # full support for exception groups added to ExceptionInfo. + # See https://github.com/pytest-dev/pytest/issues/9159 + if isinstance(e, BaseExceptionGroup): + reprtraceback: Union[ + ReprTracebackNative, ReprTraceback + ] = ReprTracebackNative( + traceback.format_exception( + type(excinfo_.value), + excinfo_.value, + excinfo_.traceback[0]._rawentry, + ) + ) + else: + reprtraceback = self.repr_traceback(excinfo_) + reprcrash = excinfo_._getreprcrash() + else: + # Fallback to native repr if the exception doesn't have a traceback: + # ExceptionInfo objects require a full traceback to work. + reprtraceback = ReprTracebackNative( + traceback.format_exception(type(e), e, None) + ) + reprcrash = None + repr_chain += [(reprtraceback, reprcrash, descr)] + + if e.__cause__ is not None and self.chain: + e = e.__cause__ + excinfo_ = ExceptionInfo.from_exception(e) if e.__traceback__ else None + descr = "The above exception was the direct cause of the following exception:" + elif ( + e.__context__ is not None and not e.__suppress_context__ and self.chain + ): + e = e.__context__ + excinfo_ = ExceptionInfo.from_exception(e) if e.__traceback__ else None + descr = "During handling of the above exception, another exception occurred:" + else: + e = None + repr_chain.reverse() + return ExceptionChainRepr(repr_chain) + + +@dataclasses.dataclass(eq=False) +class TerminalRepr: + def __str__(self) -> str: + # FYI this is called from pytest-xdist's serialization of exception + # information. + io = StringIO() + tw = TerminalWriter(file=io) + self.toterminal(tw) + return io.getvalue().strip() + + def __repr__(self) -> str: + return f"<{self.__class__} instance at {id(self):0x}>" + + def toterminal(self, tw: TerminalWriter) -> None: + raise NotImplementedError() + + +# This class is abstract -- only subclasses are instantiated. +@dataclasses.dataclass(eq=False) +class ExceptionRepr(TerminalRepr): + # Provided by subclasses. + reprtraceback: "ReprTraceback" + reprcrash: Optional["ReprFileLocation"] + sections: List[Tuple[str, str, str]] = dataclasses.field( + init=False, default_factory=list + ) + + def addsection(self, name: str, content: str, sep: str = "-") -> None: + self.sections.append((name, content, sep)) + + def toterminal(self, tw: TerminalWriter) -> None: + for name, content, sep in self.sections: + tw.sep(sep, name) + tw.line(content) + + +@dataclasses.dataclass(eq=False) +class ExceptionChainRepr(ExceptionRepr): + chain: Sequence[Tuple["ReprTraceback", Optional["ReprFileLocation"], Optional[str]]] + + def __init__( + self, + chain: Sequence[ + Tuple["ReprTraceback", Optional["ReprFileLocation"], Optional[str]] + ], + ) -> None: + # reprcrash and reprtraceback of the outermost (the newest) exception + # in the chain. + super().__init__( + reprtraceback=chain[-1][0], + reprcrash=chain[-1][1], + ) + self.chain = chain + + def toterminal(self, tw: TerminalWriter) -> None: + for element in self.chain: + element[0].toterminal(tw) + if element[2] is not None: + tw.line("") + tw.line(element[2], yellow=True) + super().toterminal(tw) + + +@dataclasses.dataclass(eq=False) +class ReprExceptionInfo(ExceptionRepr): + reprtraceback: "ReprTraceback" + reprcrash: Optional["ReprFileLocation"] + + def toterminal(self, tw: TerminalWriter) -> None: + self.reprtraceback.toterminal(tw) + super().toterminal(tw) + + +@dataclasses.dataclass(eq=False) +class ReprTraceback(TerminalRepr): + reprentries: Sequence[Union["ReprEntry", "ReprEntryNative"]] + extraline: Optional[str] + style: "_TracebackStyle" + + entrysep: ClassVar = "_ " + + def toterminal(self, tw: TerminalWriter) -> None: + # The entries might have different styles. + for i, entry in enumerate(self.reprentries): + if entry.style == "long": + tw.line("") + entry.toterminal(tw) + if i < len(self.reprentries) - 1: + next_entry = self.reprentries[i + 1] + if ( + entry.style == "long" + or entry.style == "short" + and next_entry.style == "long" + ): + tw.sep(self.entrysep) + + if self.extraline: + tw.line(self.extraline) + + +class ReprTracebackNative(ReprTraceback): + def __init__(self, tblines: Sequence[str]) -> None: + self.reprentries = [ReprEntryNative(tblines)] + self.extraline = None + self.style = "native" + + +@dataclasses.dataclass(eq=False) +class ReprEntryNative(TerminalRepr): + lines: Sequence[str] + + style: ClassVar["_TracebackStyle"] = "native" + + def toterminal(self, tw: TerminalWriter) -> None: + tw.write("".join(self.lines)) + + +@dataclasses.dataclass(eq=False) +class ReprEntry(TerminalRepr): + lines: Sequence[str] + reprfuncargs: Optional["ReprFuncArgs"] + reprlocals: Optional["ReprLocals"] + reprfileloc: Optional["ReprFileLocation"] + style: "_TracebackStyle" + + def _write_entry_lines(self, tw: TerminalWriter) -> None: + """Write the source code portions of a list of traceback entries with syntax highlighting. + + Usually entries are lines like these: + + " x = 1" + "> assert x == 2" + "E assert 1 == 2" + + This function takes care of rendering the "source" portions of it (the lines without + the "E" prefix) using syntax highlighting, taking care to not highlighting the ">" + character, as doing so might break line continuations. + """ + + if not self.lines: + return + + # separate indents and source lines that are not failures: we want to + # highlight the code but not the indentation, which may contain markers + # such as "> assert 0" + fail_marker = f"{FormattedExcinfo.fail_marker} " + indent_size = len(fail_marker) + indents: List[str] = [] + source_lines: List[str] = [] + failure_lines: List[str] = [] + for index, line in enumerate(self.lines): + is_failure_line = line.startswith(fail_marker) + if is_failure_line: + # from this point on all lines are considered part of the failure + failure_lines.extend(self.lines[index:]) + break + else: + if self.style == "value": + source_lines.append(line) + else: + indents.append(line[:indent_size]) + source_lines.append(line[indent_size:]) + + tw._write_source(source_lines, indents) + + # failure lines are always completely red and bold + for line in failure_lines: + tw.line(line, bold=True, red=True) + + def toterminal(self, tw: TerminalWriter) -> None: + if self.style == "short": + if self.reprfileloc: + self.reprfileloc.toterminal(tw) + self._write_entry_lines(tw) + if self.reprlocals: + self.reprlocals.toterminal(tw, indent=" " * 8) + return + + if self.reprfuncargs: + self.reprfuncargs.toterminal(tw) + + self._write_entry_lines(tw) + + if self.reprlocals: + tw.line("") + self.reprlocals.toterminal(tw) + if self.reprfileloc: + if self.lines: + tw.line("") + self.reprfileloc.toterminal(tw) + + def __str__(self) -> str: + return "{}\n{}\n{}".format( + "\n".join(self.lines), self.reprlocals, self.reprfileloc + ) + + +@dataclasses.dataclass(eq=False) +class ReprFileLocation(TerminalRepr): + path: str + lineno: int + message: str + + def __post_init__(self) -> None: + self.path = str(self.path) + + def toterminal(self, tw: TerminalWriter) -> None: + # Filename and lineno output for each entry, using an output format + # that most editors understand. + msg = self.message + i = msg.find("\n") + if i != -1: + msg = msg[:i] + tw.write(self.path, bold=True, red=True) + tw.line(f":{self.lineno}: {msg}") + + +@dataclasses.dataclass(eq=False) +class ReprLocals(TerminalRepr): + lines: Sequence[str] + + def toterminal(self, tw: TerminalWriter, indent="") -> None: + for line in self.lines: + tw.line(indent + line) + + +@dataclasses.dataclass(eq=False) +class ReprFuncArgs(TerminalRepr): + args: Sequence[Tuple[str, object]] + + def toterminal(self, tw: TerminalWriter) -> None: + if self.args: + linesofar = "" + for name, value in self.args: + ns = f"{name} = {value}" + if len(ns) + len(linesofar) + 2 > tw.fullwidth: + if linesofar: + tw.line(linesofar) + linesofar = ns + else: + if linesofar: + linesofar += ", " + ns + else: + linesofar = ns + if linesofar: + tw.line(linesofar) + tw.line("") + + +def getfslineno(obj: object) -> Tuple[Union[str, Path], int]: + """Return source location (path, lineno) for the given object. + + If the source cannot be determined return ("", -1). + + The line number is 0-based. + """ + # xxx let decorators etc specify a sane ordering + # NOTE: this used to be done in _pytest.compat.getfslineno, initially added + # in 6ec13a2b9. It ("place_as") appears to be something very custom. + obj = get_real_func(obj) + if hasattr(obj, "place_as"): + obj = obj.place_as # type: ignore[attr-defined] + + try: + code = Code.from_function(obj) + except TypeError: + try: + fn = inspect.getsourcefile(obj) or inspect.getfile(obj) # type: ignore[arg-type] + except TypeError: + return "", -1 + + fspath = fn and absolutepath(fn) or "" + lineno = -1 + if fspath: + try: + _, lineno = findsource(obj) + except OSError: + pass + return fspath, lineno + + return code.path, code.firstlineno + + +# Relative paths that we use to filter traceback entries from appearing to the user; +# see filter_traceback. +# note: if we need to add more paths than what we have now we should probably use a list +# for better maintenance. + +_PLUGGY_DIR = Path(pluggy.__file__.rstrip("oc")) +# pluggy is either a package or a single module depending on the version +if _PLUGGY_DIR.name == "__init__.py": + _PLUGGY_DIR = _PLUGGY_DIR.parent +_PYTEST_DIR = Path(_pytest.__file__).parent + + +def filter_traceback(entry: TracebackEntry) -> bool: + """Return True if a TracebackEntry instance should be included in tracebacks. + + We hide traceback entries of: + + * dynamically generated code (no code to show up for it); + * internal traceback from pytest or its internal libraries, py and pluggy. + """ + # entry.path might sometimes return a str object when the entry + # points to dynamically generated code. + # See https://bitbucket.org/pytest-dev/py/issues/71. + raw_filename = entry.frame.code.raw.co_filename + is_generated = "<" in raw_filename and ">" in raw_filename + if is_generated: + return False + + # entry.path might point to a non-existing file, in which case it will + # also return a str object. See #1133. + p = Path(entry.path) + + parents = p.parents + if _PLUGGY_DIR in parents: + return False + if _PYTEST_DIR in parents: + return False + + return True diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_code/source.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_code/source.py new file mode 100644 index 000000000..208cfb800 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_code/source.py @@ -0,0 +1,217 @@ +import ast +import inspect +import textwrap +import tokenize +import types +import warnings +from bisect import bisect_right +from typing import Iterable +from typing import Iterator +from typing import List +from typing import Optional +from typing import overload +from typing import Tuple +from typing import Union + + +class Source: + """An immutable object holding a source code fragment. + + When using Source(...), the source lines are deindented. + """ + + def __init__(self, obj: object = None) -> None: + if not obj: + self.lines: List[str] = [] + elif isinstance(obj, Source): + self.lines = obj.lines + elif isinstance(obj, (tuple, list)): + self.lines = deindent(x.rstrip("\n") for x in obj) + elif isinstance(obj, str): + self.lines = deindent(obj.split("\n")) + else: + try: + rawcode = getrawcode(obj) + src = inspect.getsource(rawcode) + except TypeError: + src = inspect.getsource(obj) # type: ignore[arg-type] + self.lines = deindent(src.split("\n")) + + def __eq__(self, other: object) -> bool: + if not isinstance(other, Source): + return NotImplemented + return self.lines == other.lines + + # Ignore type because of https://github.com/python/mypy/issues/4266. + __hash__ = None # type: ignore + + @overload + def __getitem__(self, key: int) -> str: + ... + + @overload + def __getitem__(self, key: slice) -> "Source": + ... + + def __getitem__(self, key: Union[int, slice]) -> Union[str, "Source"]: + if isinstance(key, int): + return self.lines[key] + else: + if key.step not in (None, 1): + raise IndexError("cannot slice a Source with a step") + newsource = Source() + newsource.lines = self.lines[key.start : key.stop] + return newsource + + def __iter__(self) -> Iterator[str]: + return iter(self.lines) + + def __len__(self) -> int: + return len(self.lines) + + def strip(self) -> "Source": + """Return new Source object with trailing and leading blank lines removed.""" + start, end = 0, len(self) + while start < end and not self.lines[start].strip(): + start += 1 + while end > start and not self.lines[end - 1].strip(): + end -= 1 + source = Source() + source.lines[:] = self.lines[start:end] + return source + + def indent(self, indent: str = " " * 4) -> "Source": + """Return a copy of the source object with all lines indented by the + given indent-string.""" + newsource = Source() + newsource.lines = [(indent + line) for line in self.lines] + return newsource + + def getstatement(self, lineno: int) -> "Source": + """Return Source statement which contains the given linenumber + (counted from 0).""" + start, end = self.getstatementrange(lineno) + return self[start:end] + + def getstatementrange(self, lineno: int) -> Tuple[int, int]: + """Return (start, end) tuple which spans the minimal statement region + which containing the given lineno.""" + if not (0 <= lineno < len(self)): + raise IndexError("lineno out of range") + ast, start, end = getstatementrange_ast(lineno, self) + return start, end + + def deindent(self) -> "Source": + """Return a new Source object deindented.""" + newsource = Source() + newsource.lines[:] = deindent(self.lines) + return newsource + + def __str__(self) -> str: + return "\n".join(self.lines) + + +# +# helper functions +# + + +def findsource(obj) -> Tuple[Optional[Source], int]: + try: + sourcelines, lineno = inspect.findsource(obj) + except Exception: + return None, -1 + source = Source() + source.lines = [line.rstrip() for line in sourcelines] + return source, lineno + + +def getrawcode(obj: object, trycall: bool = True) -> types.CodeType: + """Return code object for given function.""" + try: + return obj.__code__ # type: ignore[attr-defined,no-any-return] + except AttributeError: + pass + if trycall: + call = getattr(obj, "__call__", None) + if call and not isinstance(obj, type): + return getrawcode(call, trycall=False) + raise TypeError(f"could not get code object for {obj!r}") + + +def deindent(lines: Iterable[str]) -> List[str]: + return textwrap.dedent("\n".join(lines)).splitlines() + + +def get_statement_startend2(lineno: int, node: ast.AST) -> Tuple[int, Optional[int]]: + # Flatten all statements and except handlers into one lineno-list. + # AST's line numbers start indexing at 1. + values: List[int] = [] + for x in ast.walk(node): + if isinstance(x, (ast.stmt, ast.ExceptHandler)): + # Before Python 3.8, the lineno of a decorated class or function pointed at the decorator. + # Since Python 3.8, the lineno points to the class/def, so need to include the decorators. + if isinstance(x, (ast.ClassDef, ast.FunctionDef, ast.AsyncFunctionDef)): + for d in x.decorator_list: + values.append(d.lineno - 1) + values.append(x.lineno - 1) + for name in ("finalbody", "orelse"): + val: Optional[List[ast.stmt]] = getattr(x, name, None) + if val: + # Treat the finally/orelse part as its own statement. + values.append(val[0].lineno - 1 - 1) + values.sort() + insert_index = bisect_right(values, lineno) + start = values[insert_index - 1] + if insert_index >= len(values): + end = None + else: + end = values[insert_index] + return start, end + + +def getstatementrange_ast( + lineno: int, + source: Source, + assertion: bool = False, + astnode: Optional[ast.AST] = None, +) -> Tuple[ast.AST, int, int]: + if astnode is None: + content = str(source) + # See #4260: + # Don't produce duplicate warnings when compiling source to find AST. + with warnings.catch_warnings(): + warnings.simplefilter("ignore") + astnode = ast.parse(content, "source", "exec") + + start, end = get_statement_startend2(lineno, astnode) + # We need to correct the end: + # - ast-parsing strips comments + # - there might be empty lines + # - we might have lesser indented code blocks at the end + if end is None: + end = len(source.lines) + + if end > start + 1: + # Make sure we don't span differently indented code blocks + # by using the BlockFinder helper used which inspect.getsource() uses itself. + block_finder = inspect.BlockFinder() + # If we start with an indented line, put blockfinder to "started" mode. + block_finder.started = source.lines[start][0].isspace() + it = ((x + "\n") for x in source.lines[start:end]) + try: + for tok in tokenize.generate_tokens(lambda: next(it)): + block_finder.tokeneater(*tok) + except (inspect.EndOfBlock, IndentationError): + end = block_finder.last + start + except Exception: + pass + + # The end might still point to a comment or empty line, correct it. + while end: + line = source.lines[end - 1].lstrip() + if line.startswith("#") or not line: + end -= 1 + else: + break + return astnode, start, end diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_io/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_io/__init__.py new file mode 100644 index 000000000..db001e918 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_io/__init__.py @@ -0,0 +1,8 @@ +from .terminalwriter import get_terminal_width +from .terminalwriter import TerminalWriter + + +__all__ = [ + "TerminalWriter", + "get_terminal_width", +] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_io/saferepr.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_io/saferepr.py new file mode 100644 index 000000000..c70187223 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_io/saferepr.py @@ -0,0 +1,180 @@ +import pprint +import reprlib +from typing import Any +from typing import Dict +from typing import IO +from typing import Optional + + +def _try_repr_or_str(obj: object) -> str: + try: + return repr(obj) + except (KeyboardInterrupt, SystemExit): + raise + except BaseException: + return f'{type(obj).__name__}("{obj}")' + + +def _format_repr_exception(exc: BaseException, obj: object) -> str: + try: + exc_info = _try_repr_or_str(exc) + except (KeyboardInterrupt, SystemExit): + raise + except BaseException as exc: + exc_info = f"unpresentable exception ({_try_repr_or_str(exc)})" + return "<[{} raised in repr()] {} object at 0x{:x}>".format( + exc_info, type(obj).__name__, id(obj) + ) + + +def _ellipsize(s: str, maxsize: int) -> str: + if len(s) > maxsize: + i = max(0, (maxsize - 3) // 2) + j = max(0, maxsize - 3 - i) + return s[:i] + "..." + s[len(s) - j :] + return s + + +class SafeRepr(reprlib.Repr): + """ + repr.Repr that limits the resulting size of repr() and includes + information on exceptions raised during the call. + """ + + def __init__(self, maxsize: Optional[int], use_ascii: bool = False) -> None: + """ + :param maxsize: + If not None, will truncate the resulting repr to that specific size, using ellipsis + somewhere in the middle to hide the extra text. + If None, will not impose any size limits on the returning repr. + """ + super().__init__() + # ``maxstring`` is used by the superclass, and needs to be an int; using a + # very large number in case maxsize is None, meaning we want to disable + # truncation. + self.maxstring = maxsize if maxsize is not None else 1_000_000_000 + self.maxsize = maxsize + self.use_ascii = use_ascii + + def repr(self, x: object) -> str: + try: + if self.use_ascii: + s = ascii(x) + else: + s = super().repr(x) + + except (KeyboardInterrupt, SystemExit): + raise + except BaseException as exc: + s = _format_repr_exception(exc, x) + if self.maxsize is not None: + s = _ellipsize(s, self.maxsize) + return s + + def repr_instance(self, x: object, level: int) -> str: + try: + s = repr(x) + except (KeyboardInterrupt, SystemExit): + raise + except BaseException as exc: + s = _format_repr_exception(exc, x) + if self.maxsize is not None: + s = _ellipsize(s, self.maxsize) + return s + + +def safeformat(obj: object) -> str: + """Return a pretty printed string for the given object. + + Failing __repr__ functions of user instances will be represented + with a short exception info. + """ + try: + return pprint.pformat(obj) + except Exception as exc: + return _format_repr_exception(exc, obj) + + +# Maximum size of overall repr of objects to display during assertion errors. +DEFAULT_REPR_MAX_SIZE = 240 + + +def saferepr( + obj: object, maxsize: Optional[int] = DEFAULT_REPR_MAX_SIZE, use_ascii: bool = False +) -> str: + """Return a size-limited safe repr-string for the given object. + + Failing __repr__ functions of user instances will be represented + with a short exception info and 'saferepr' generally takes + care to never raise exceptions itself. + + This function is a wrapper around the Repr/reprlib functionality of the + stdlib. + """ + + return SafeRepr(maxsize, use_ascii).repr(obj) + + +def saferepr_unlimited(obj: object, use_ascii: bool = True) -> str: + """Return an unlimited-size safe repr-string for the given object. + + As with saferepr, failing __repr__ functions of user instances + will be represented with a short exception info. + + This function is a wrapper around simple repr. + + Note: a cleaner solution would be to alter ``saferepr``this way + when maxsize=None, but that might affect some other code. + """ + try: + if use_ascii: + return ascii(obj) + return repr(obj) + except Exception as exc: + return _format_repr_exception(exc, obj) + + +class AlwaysDispatchingPrettyPrinter(pprint.PrettyPrinter): + """PrettyPrinter that always dispatches (regardless of width).""" + + def _format( + self, + object: object, + stream: IO[str], + indent: int, + allowance: int, + context: Dict[int, Any], + level: int, + ) -> None: + # Type ignored because _dispatch is private. + p = self._dispatch.get(type(object).__repr__, None) # type: ignore[attr-defined] + + objid = id(object) + if objid in context or p is None: + # Type ignored because _format is private. + super()._format( # type: ignore[misc] + object, + stream, + indent, + allowance, + context, + level, + ) + return + + context[objid] = 1 + p(self, object, stream, indent, allowance, context, level + 1) + del context[objid] + + +def _pformat_dispatch( + object: object, + indent: int = 1, + width: int = 80, + depth: Optional[int] = None, + *, + compact: bool = False, +) -> str: + return AlwaysDispatchingPrettyPrinter( + indent=indent, width=width, depth=depth, compact=compact + ).pformat(object) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_io/terminalwriter.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_io/terminalwriter.py new file mode 100644 index 000000000..379035d85 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_io/terminalwriter.py @@ -0,0 +1,233 @@ +"""Helper functions for writing to terminals and files.""" +import os +import shutil +import sys +from typing import Optional +from typing import Sequence +from typing import TextIO + +from .wcwidth import wcswidth +from _pytest.compat import final + + +# This code was initially copied from py 1.8.1, file _io/terminalwriter.py. + + +def get_terminal_width() -> int: + width, _ = shutil.get_terminal_size(fallback=(80, 24)) + + # The Windows get_terminal_size may be bogus, let's sanify a bit. + if width < 40: + width = 80 + + return width + + +def should_do_markup(file: TextIO) -> bool: + if os.environ.get("PY_COLORS") == "1": + return True + if os.environ.get("PY_COLORS") == "0": + return False + if "NO_COLOR" in os.environ: + return False + if "FORCE_COLOR" in os.environ: + return True + return ( + hasattr(file, "isatty") and file.isatty() and os.environ.get("TERM") != "dumb" + ) + + +@final +class TerminalWriter: + _esctable = dict( + black=30, + red=31, + green=32, + yellow=33, + blue=34, + purple=35, + cyan=36, + white=37, + Black=40, + Red=41, + Green=42, + Yellow=43, + Blue=44, + Purple=45, + Cyan=46, + White=47, + bold=1, + light=2, + blink=5, + invert=7, + ) + + def __init__(self, file: Optional[TextIO] = None) -> None: + if file is None: + file = sys.stdout + if hasattr(file, "isatty") and file.isatty() and sys.platform == "win32": + try: + import colorama + except ImportError: + pass + else: + file = colorama.AnsiToWin32(file).stream + assert file is not None + self._file = file + self.hasmarkup = should_do_markup(file) + self._current_line = "" + self._terminal_width: Optional[int] = None + self.code_highlight = True + + @property + def fullwidth(self) -> int: + if self._terminal_width is not None: + return self._terminal_width + return get_terminal_width() + + @fullwidth.setter + def fullwidth(self, value: int) -> None: + self._terminal_width = value + + @property + def width_of_current_line(self) -> int: + """Return an estimate of the width so far in the current line.""" + return wcswidth(self._current_line) + + def markup(self, text: str, **markup: bool) -> str: + for name in markup: + if name not in self._esctable: + raise ValueError(f"unknown markup: {name!r}") + if self.hasmarkup: + esc = [self._esctable[name] for name, on in markup.items() if on] + if esc: + text = "".join("\x1b[%sm" % cod for cod in esc) + text + "\x1b[0m" + return text + + def sep( + self, + sepchar: str, + title: Optional[str] = None, + fullwidth: Optional[int] = None, + **markup: bool, + ) -> None: + if fullwidth is None: + fullwidth = self.fullwidth + # The goal is to have the line be as long as possible + # under the condition that len(line) <= fullwidth. + if sys.platform == "win32": + # If we print in the last column on windows we are on a + # new line but there is no way to verify/neutralize this + # (we may not know the exact line width). + # So let's be defensive to avoid empty lines in the output. + fullwidth -= 1 + if title is not None: + # we want 2 + 2*len(fill) + len(title) <= fullwidth + # i.e. 2 + 2*len(sepchar)*N + len(title) <= fullwidth + # 2*len(sepchar)*N <= fullwidth - len(title) - 2 + # N <= (fullwidth - len(title) - 2) // (2*len(sepchar)) + N = max((fullwidth - len(title) - 2) // (2 * len(sepchar)), 1) + fill = sepchar * N + line = f"{fill} {title} {fill}" + else: + # we want len(sepchar)*N <= fullwidth + # i.e. N <= fullwidth // len(sepchar) + line = sepchar * (fullwidth // len(sepchar)) + # In some situations there is room for an extra sepchar at the right, + # in particular if we consider that with a sepchar like "_ " the + # trailing space is not important at the end of the line. + if len(line) + len(sepchar.rstrip()) <= fullwidth: + line += sepchar.rstrip() + + self.line(line, **markup) + + def write(self, msg: str, *, flush: bool = False, **markup: bool) -> None: + if msg: + current_line = msg.rsplit("\n", 1)[-1] + if "\n" in msg: + self._current_line = current_line + else: + self._current_line += current_line + + msg = self.markup(msg, **markup) + + try: + self._file.write(msg) + except UnicodeEncodeError: + # Some environments don't support printing general Unicode + # strings, due to misconfiguration or otherwise; in that case, + # print the string escaped to ASCII. + # When the Unicode situation improves we should consider + # letting the error propagate instead of masking it (see #7475 + # for one brief attempt). + msg = msg.encode("unicode-escape").decode("ascii") + self._file.write(msg) + + if flush: + self.flush() + + def line(self, s: str = "", **markup: bool) -> None: + self.write(s, **markup) + self.write("\n") + + def flush(self) -> None: + self._file.flush() + + def _write_source(self, lines: Sequence[str], indents: Sequence[str] = ()) -> None: + """Write lines of source code possibly highlighted. + + Keeping this private for now because the API is clunky. We should discuss how + to evolve the terminal writer so we can have more precise color support, for example + being able to write part of a line in one color and the rest in another, and so on. + """ + if indents and len(indents) != len(lines): + raise ValueError( + "indents size ({}) should have same size as lines ({})".format( + len(indents), len(lines) + ) + ) + if not indents: + indents = [""] * len(lines) + source = "\n".join(lines) + new_lines = self._highlight(source).splitlines() + for indent, new_line in zip(indents, new_lines): + self.line(indent + new_line) + + def _highlight(self, source: str) -> str: + """Highlight the given source code if we have markup support.""" + from _pytest.config.exceptions import UsageError + + if not self.hasmarkup or not self.code_highlight: + return source + try: + from pygments.formatters.terminal import TerminalFormatter + from pygments.lexers.python import PythonLexer + from pygments import highlight + import pygments.util + except ImportError: + return source + else: + try: + highlighted: str = highlight( + source, + PythonLexer(), + TerminalFormatter( + bg=os.getenv("PYTEST_THEME_MODE", "dark"), + style=os.getenv("PYTEST_THEME"), + ), + ) + return highlighted + except pygments.util.ClassNotFound: + raise UsageError( + "PYTEST_THEME environment variable had an invalid value: '{}'. " + "Only valid pygment styles are allowed.".format( + os.getenv("PYTEST_THEME") + ) + ) + except pygments.util.OptionError: + raise UsageError( + "PYTEST_THEME_MODE environment variable had an invalid value: '{}'. " + "The only allowed values are 'dark' and 'light'.".format( + os.getenv("PYTEST_THEME_MODE") + ) + ) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_io/wcwidth.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_io/wcwidth.py new file mode 100644 index 000000000..e5c7bf4d8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_io/wcwidth.py @@ -0,0 +1,55 @@ +import unicodedata +from functools import lru_cache + + +@lru_cache(100) +def wcwidth(c: str) -> int: + """Determine how many columns are needed to display a character in a terminal. + + Returns -1 if the character is not printable. + Returns 0, 1 or 2 for other characters. + """ + o = ord(c) + + # ASCII fast path. + if 0x20 <= o < 0x07F: + return 1 + + # Some Cf/Zp/Zl characters which should be zero-width. + if ( + o == 0x0000 + or 0x200B <= o <= 0x200F + or 0x2028 <= o <= 0x202E + or 0x2060 <= o <= 0x2063 + ): + return 0 + + category = unicodedata.category(c) + + # Control characters. + if category == "Cc": + return -1 + + # Combining characters with zero width. + if category in ("Me", "Mn"): + return 0 + + # Full/Wide east asian characters. + if unicodedata.east_asian_width(c) in ("F", "W"): + return 2 + + return 1 + + +def wcswidth(s: str) -> int: + """Determine how many columns are needed to display a string in a terminal. + + Returns -1 if the string contains non-printable characters. + """ + width = 0 + for c in unicodedata.normalize("NFC", s): + wc = wcwidth(c) + if wc < 0: + return -1 + width += wc + return width diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_py/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_py/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_py/error.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_py/error.py new file mode 100644 index 000000000..0b8f2d535 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_py/error.py @@ -0,0 +1,109 @@ +"""create errno-specific classes for IO or os calls.""" +from __future__ import annotations + +import errno +import os +import sys +from typing import Callable +from typing import TYPE_CHECKING +from typing import TypeVar + +if TYPE_CHECKING: + from typing_extensions import ParamSpec + + P = ParamSpec("P") + +R = TypeVar("R") + + +class Error(EnvironmentError): + def __repr__(self) -> str: + return "{}.{} {!r}: {} ".format( + self.__class__.__module__, + self.__class__.__name__, + self.__class__.__doc__, + " ".join(map(str, self.args)), + # repr(self.args) + ) + + def __str__(self) -> str: + s = "[{}]: {}".format( + self.__class__.__doc__, + " ".join(map(str, self.args)), + ) + return s + + +_winerrnomap = { + 2: errno.ENOENT, + 3: errno.ENOENT, + 17: errno.EEXIST, + 18: errno.EXDEV, + 13: errno.EBUSY, # empty cd drive, but ENOMEDIUM seems unavailiable + 22: errno.ENOTDIR, + 20: errno.ENOTDIR, + 267: errno.ENOTDIR, + 5: errno.EACCES, # anything better? +} + + +class ErrorMaker: + """lazily provides Exception classes for each possible POSIX errno + (as defined per the 'errno' module). All such instances + subclass EnvironmentError. + """ + + _errno2class: dict[int, type[Error]] = {} + + def __getattr__(self, name: str) -> type[Error]: + if name[0] == "_": + raise AttributeError(name) + eno = getattr(errno, name) + cls = self._geterrnoclass(eno) + setattr(self, name, cls) + return cls + + def _geterrnoclass(self, eno: int) -> type[Error]: + try: + return self._errno2class[eno] + except KeyError: + clsname = errno.errorcode.get(eno, "UnknownErrno%d" % (eno,)) + errorcls = type( + clsname, + (Error,), + {"__module__": "py.error", "__doc__": os.strerror(eno)}, + ) + self._errno2class[eno] = errorcls + return errorcls + + def checked_call( + self, func: Callable[P, R], *args: P.args, **kwargs: P.kwargs + ) -> R: + """Call a function and raise an errno-exception if applicable.""" + __tracebackhide__ = True + try: + return func(*args, **kwargs) + except Error: + raise + except OSError as value: + if not hasattr(value, "errno"): + raise + errno = value.errno + if sys.platform == "win32": + try: + cls = self._geterrnoclass(_winerrnomap[errno]) + except KeyError: + raise value + else: + # we are not on Windows, or we got a proper OSError + cls = self._geterrnoclass(errno) + + raise cls(f"{func.__name__}{args!r}") + + +_error_maker = ErrorMaker() +checked_call = _error_maker.checked_call + + +def __getattr__(attr: str) -> type[Error]: + return getattr(_error_maker, attr) # type: ignore[no-any-return] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_py/path.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_py/path.py new file mode 100644 index 000000000..73a070d19 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_py/path.py @@ -0,0 +1,1475 @@ +"""local path implementation.""" +from __future__ import annotations + +import atexit +import fnmatch +import importlib.util +import io +import os +import posixpath +import sys +import uuid +import warnings +from contextlib import contextmanager +from os.path import abspath +from os.path import dirname +from os.path import exists +from os.path import isabs +from os.path import isdir +from os.path import isfile +from os.path import islink +from os.path import normpath +from stat import S_ISDIR +from stat import S_ISLNK +from stat import S_ISREG +from typing import Any +from typing import Callable +from typing import cast +from typing import overload +from typing import TYPE_CHECKING + +from . import error + +if TYPE_CHECKING: + from typing import Literal + +# Moved from local.py. +iswin32 = sys.platform == "win32" or (getattr(os, "_name", False) == "nt") + + +class Checkers: + _depend_on_existence = "exists", "link", "dir", "file" + + def __init__(self, path): + self.path = path + + def dotfile(self): + return self.path.basename.startswith(".") + + def ext(self, arg): + if not arg.startswith("."): + arg = "." + arg + return self.path.ext == arg + + def basename(self, arg): + return self.path.basename == arg + + def basestarts(self, arg): + return self.path.basename.startswith(arg) + + def relto(self, arg): + return self.path.relto(arg) + + def fnmatch(self, arg): + return self.path.fnmatch(arg) + + def endswith(self, arg): + return str(self.path).endswith(arg) + + def _evaluate(self, kw): + from .._code.source import getrawcode + + for name, value in kw.items(): + invert = False + meth = None + try: + meth = getattr(self, name) + except AttributeError: + if name[:3] == "not": + invert = True + try: + meth = getattr(self, name[3:]) + except AttributeError: + pass + if meth is None: + raise TypeError(f"no {name!r} checker available for {self.path!r}") + try: + if getrawcode(meth).co_argcount > 1: + if (not meth(value)) ^ invert: + return False + else: + if bool(value) ^ bool(meth()) ^ invert: + return False + except (error.ENOENT, error.ENOTDIR, error.EBUSY): + # EBUSY feels not entirely correct, + # but its kind of necessary since ENOMEDIUM + # is not accessible in python + for name in self._depend_on_existence: + if name in kw: + if kw.get(name): + return False + name = "not" + name + if name in kw: + if not kw.get(name): + return False + return True + + _statcache: Stat + + def _stat(self) -> Stat: + try: + return self._statcache + except AttributeError: + try: + self._statcache = self.path.stat() + except error.ELOOP: + self._statcache = self.path.lstat() + return self._statcache + + def dir(self): + return S_ISDIR(self._stat().mode) + + def file(self): + return S_ISREG(self._stat().mode) + + def exists(self): + return self._stat() + + def link(self): + st = self.path.lstat() + return S_ISLNK(st.mode) + + +class NeverRaised(Exception): + pass + + +class Visitor: + def __init__(self, fil, rec, ignore, bf, sort): + if isinstance(fil, str): + fil = FNMatcher(fil) + if isinstance(rec, str): + self.rec: Callable[[LocalPath], bool] = FNMatcher(rec) + elif not hasattr(rec, "__call__") and rec: + self.rec = lambda path: True + else: + self.rec = rec + self.fil = fil + self.ignore = ignore + self.breadthfirst = bf + self.optsort = cast(Callable[[Any], Any], sorted) if sort else (lambda x: x) + + def gen(self, path): + try: + entries = path.listdir() + except self.ignore: + return + rec = self.rec + dirs = self.optsort( + [p for p in entries if p.check(dir=1) and (rec is None or rec(p))] + ) + if not self.breadthfirst: + for subdir in dirs: + for p in self.gen(subdir): + yield p + for p in self.optsort(entries): + if self.fil is None or self.fil(p): + yield p + if self.breadthfirst: + for subdir in dirs: + for p in self.gen(subdir): + yield p + + +class FNMatcher: + def __init__(self, pattern): + self.pattern = pattern + + def __call__(self, path): + pattern = self.pattern + + if ( + pattern.find(path.sep) == -1 + and iswin32 + and pattern.find(posixpath.sep) != -1 + ): + # Running on Windows, the pattern has no Windows path separators, + # and the pattern has one or more Posix path separators. Replace + # the Posix path separators with the Windows path separator. + pattern = pattern.replace(posixpath.sep, path.sep) + + if pattern.find(path.sep) == -1: + name = path.basename + else: + name = str(path) # path.strpath # XXX svn? + if not os.path.isabs(pattern): + pattern = "*" + path.sep + pattern + return fnmatch.fnmatch(name, pattern) + + +def map_as_list(func, iter): + return list(map(func, iter)) + + +class Stat: + if TYPE_CHECKING: + + @property + def size(self) -> int: + ... + + @property + def mtime(self) -> float: + ... + + def __getattr__(self, name: str) -> Any: + return getattr(self._osstatresult, "st_" + name) + + def __init__(self, path, osstatresult): + self.path = path + self._osstatresult = osstatresult + + @property + def owner(self): + if iswin32: + raise NotImplementedError("XXX win32") + import pwd + + entry = error.checked_call(pwd.getpwuid, self.uid) # type:ignore[attr-defined] + return entry[0] + + @property + def group(self): + """Return group name of file.""" + if iswin32: + raise NotImplementedError("XXX win32") + import grp + + entry = error.checked_call(grp.getgrgid, self.gid) # type:ignore[attr-defined] + return entry[0] + + def isdir(self): + return S_ISDIR(self._osstatresult.st_mode) + + def isfile(self): + return S_ISREG(self._osstatresult.st_mode) + + def islink(self): + self.path.lstat() + return S_ISLNK(self._osstatresult.st_mode) + + +def getuserid(user): + import pwd + + if not isinstance(user, int): + user = pwd.getpwnam(user)[2] # type:ignore[attr-defined] + return user + + +def getgroupid(group): + import grp + + if not isinstance(group, int): + group = grp.getgrnam(group)[2] # type:ignore[attr-defined] + return group + + +class LocalPath: + """Object oriented interface to os.path and other local filesystem + related information. + """ + + class ImportMismatchError(ImportError): + """raised on pyimport() if there is a mismatch of __file__'s""" + + sep = os.sep + + def __init__(self, path=None, expanduser=False): + """Initialize and return a local Path instance. + + Path can be relative to the current directory. + If path is None it defaults to the current working directory. + If expanduser is True, tilde-expansion is performed. + Note that Path instances always carry an absolute path. + Note also that passing in a local path object will simply return + the exact same path object. Use new() to get a new copy. + """ + if path is None: + self.strpath = error.checked_call(os.getcwd) + else: + try: + path = os.fspath(path) + except TypeError: + raise ValueError( + "can only pass None, Path instances " + "or non-empty strings to LocalPath" + ) + if expanduser: + path = os.path.expanduser(path) + self.strpath = abspath(path) + + if sys.platform != "win32": + + def chown(self, user, group, rec=0): + """Change ownership to the given user and group. + user and group may be specified by a number or + by a name. if rec is True change ownership + recursively. + """ + uid = getuserid(user) + gid = getgroupid(group) + if rec: + for x in self.visit(rec=lambda x: x.check(link=0)): + if x.check(link=0): + error.checked_call(os.chown, str(x), uid, gid) + error.checked_call(os.chown, str(self), uid, gid) + + def readlink(self) -> str: + """Return value of a symbolic link.""" + # https://github.com/python/mypy/issues/12278 + return error.checked_call(os.readlink, self.strpath) # type: ignore[arg-type,return-value] + + def mklinkto(self, oldname): + """Posix style hard link to another name.""" + error.checked_call(os.link, str(oldname), str(self)) + + def mksymlinkto(self, value, absolute=1): + """Create a symbolic link with the given value (pointing to another name).""" + if absolute: + error.checked_call(os.symlink, str(value), self.strpath) + else: + base = self.common(value) + # with posix local paths '/' is always a common base + relsource = self.__class__(value).relto(base) + reldest = self.relto(base) + n = reldest.count(self.sep) + target = self.sep.join(("..",) * n + (relsource,)) + error.checked_call(os.symlink, target, self.strpath) + + def __div__(self, other): + return self.join(os.fspath(other)) + + __truediv__ = __div__ # py3k + + @property + def basename(self): + """Basename part of path.""" + return self._getbyspec("basename")[0] + + @property + def dirname(self): + """Dirname part of path.""" + return self._getbyspec("dirname")[0] + + @property + def purebasename(self): + """Pure base name of the path.""" + return self._getbyspec("purebasename")[0] + + @property + def ext(self): + """Extension of the path (including the '.').""" + return self._getbyspec("ext")[0] + + def read_binary(self): + """Read and return a bytestring from reading the path.""" + with self.open("rb") as f: + return f.read() + + def read_text(self, encoding): + """Read and return a Unicode string from reading the path.""" + with self.open("r", encoding=encoding) as f: + return f.read() + + def read(self, mode="r"): + """Read and return a bytestring from reading the path.""" + with self.open(mode) as f: + return f.read() + + def readlines(self, cr=1): + """Read and return a list of lines from the path. if cr is False, the + newline will be removed from the end of each line.""" + mode = "r" + + if not cr: + content = self.read(mode) + return content.split("\n") + else: + f = self.open(mode) + try: + return f.readlines() + finally: + f.close() + + def load(self): + """(deprecated) return object unpickled from self.read()""" + f = self.open("rb") + try: + import pickle + + return error.checked_call(pickle.load, f) + finally: + f.close() + + def move(self, target): + """Move this path to target.""" + if target.relto(self): + raise error.EINVAL(target, "cannot move path into a subdirectory of itself") + try: + self.rename(target) + except error.EXDEV: # invalid cross-device link + self.copy(target) + self.remove() + + def fnmatch(self, pattern): + """Return true if the basename/fullname matches the glob-'pattern'. + + valid pattern characters:: + + * matches everything + ? matches any single character + [seq] matches any character in seq + [!seq] matches any char not in seq + + If the pattern contains a path-separator then the full path + is used for pattern matching and a '*' is prepended to the + pattern. + + if the pattern doesn't contain a path-separator the pattern + is only matched against the basename. + """ + return FNMatcher(pattern)(self) + + def relto(self, relpath): + """Return a string which is the relative part of the path + to the given 'relpath'. + """ + if not isinstance(relpath, (str, LocalPath)): + raise TypeError(f"{relpath!r}: not a string or path object") + strrelpath = str(relpath) + if strrelpath and strrelpath[-1] != self.sep: + strrelpath += self.sep + # assert strrelpath[-1] == self.sep + # assert strrelpath[-2] != self.sep + strself = self.strpath + if sys.platform == "win32" or getattr(os, "_name", None) == "nt": + if os.path.normcase(strself).startswith(os.path.normcase(strrelpath)): + return strself[len(strrelpath) :] + elif strself.startswith(strrelpath): + return strself[len(strrelpath) :] + return "" + + def ensure_dir(self, *args): + """Ensure the path joined with args is a directory.""" + return self.ensure(*args, **{"dir": True}) + + def bestrelpath(self, dest): + """Return a string which is a relative path from self + (assumed to be a directory) to dest such that + self.join(bestrelpath) == dest and if not such + path can be determined return dest. + """ + try: + if self == dest: + return os.curdir + base = self.common(dest) + if not base: # can be the case on windows + return str(dest) + self2base = self.relto(base) + reldest = dest.relto(base) + if self2base: + n = self2base.count(self.sep) + 1 + else: + n = 0 + lst = [os.pardir] * n + if reldest: + lst.append(reldest) + target = dest.sep.join(lst) + return target + except AttributeError: + return str(dest) + + def exists(self): + return self.check() + + def isdir(self): + return self.check(dir=1) + + def isfile(self): + return self.check(file=1) + + def parts(self, reverse=False): + """Return a root-first list of all ancestor directories + plus the path itself. + """ + current = self + lst = [self] + while 1: + last = current + current = current.dirpath() + if last == current: + break + lst.append(current) + if not reverse: + lst.reverse() + return lst + + def common(self, other): + """Return the common part shared with the other path + or None if there is no common part. + """ + last = None + for x, y in zip(self.parts(), other.parts()): + if x != y: + return last + last = x + return last + + def __add__(self, other): + """Return new path object with 'other' added to the basename""" + return self.new(basename=self.basename + str(other)) + + def visit(self, fil=None, rec=None, ignore=NeverRaised, bf=False, sort=False): + """Yields all paths below the current one + + fil is a filter (glob pattern or callable), if not matching the + path will not be yielded, defaulting to None (everything is + returned) + + rec is a filter (glob pattern or callable) that controls whether + a node is descended, defaulting to None + + ignore is an Exception class that is ignoredwhen calling dirlist() + on any of the paths (by default, all exceptions are reported) + + bf if True will cause a breadthfirst search instead of the + default depthfirst. Default: False + + sort if True will sort entries within each directory level. + """ + yield from Visitor(fil, rec, ignore, bf, sort).gen(self) + + def _sortlist(self, res, sort): + if sort: + if hasattr(sort, "__call__"): + warnings.warn( + DeprecationWarning( + "listdir(sort=callable) is deprecated and breaks on python3" + ), + stacklevel=3, + ) + res.sort(sort) + else: + res.sort() + + def __fspath__(self): + return self.strpath + + def __hash__(self): + s = self.strpath + if iswin32: + s = s.lower() + return hash(s) + + def __eq__(self, other): + s1 = os.fspath(self) + try: + s2 = os.fspath(other) + except TypeError: + return False + if iswin32: + s1 = s1.lower() + try: + s2 = s2.lower() + except AttributeError: + return False + return s1 == s2 + + def __ne__(self, other): + return not (self == other) + + def __lt__(self, other): + return os.fspath(self) < os.fspath(other) + + def __gt__(self, other): + return os.fspath(self) > os.fspath(other) + + def samefile(self, other): + """Return True if 'other' references the same file as 'self'.""" + other = os.fspath(other) + if not isabs(other): + other = abspath(other) + if self == other: + return True + if not hasattr(os.path, "samefile"): + return False + return error.checked_call(os.path.samefile, self.strpath, other) + + def remove(self, rec=1, ignore_errors=False): + """Remove a file or directory (or a directory tree if rec=1). + if ignore_errors is True, errors while removing directories will + be ignored. + """ + if self.check(dir=1, link=0): + if rec: + # force remove of readonly files on windows + if iswin32: + self.chmod(0o700, rec=1) + import shutil + + error.checked_call( + shutil.rmtree, self.strpath, ignore_errors=ignore_errors + ) + else: + error.checked_call(os.rmdir, self.strpath) + else: + if iswin32: + self.chmod(0o700) + error.checked_call(os.remove, self.strpath) + + def computehash(self, hashtype="md5", chunksize=524288): + """Return hexdigest of hashvalue for this file.""" + try: + try: + import hashlib as mod + except ImportError: + if hashtype == "sha1": + hashtype = "sha" + mod = __import__(hashtype) + hash = getattr(mod, hashtype)() + except (AttributeError, ImportError): + raise ValueError(f"Don't know how to compute {hashtype!r} hash") + f = self.open("rb") + try: + while 1: + buf = f.read(chunksize) + if not buf: + return hash.hexdigest() + hash.update(buf) + finally: + f.close() + + def new(self, **kw): + """Create a modified version of this path. + the following keyword arguments modify various path parts:: + + a:/some/path/to/a/file.ext + xx drive + xxxxxxxxxxxxxxxxx dirname + xxxxxxxx basename + xxxx purebasename + xxx ext + """ + obj = object.__new__(self.__class__) + if not kw: + obj.strpath = self.strpath + return obj + drive, dirname, basename, purebasename, ext = self._getbyspec( + "drive,dirname,basename,purebasename,ext" + ) + if "basename" in kw: + if "purebasename" in kw or "ext" in kw: + raise ValueError("invalid specification %r" % kw) + else: + pb = kw.setdefault("purebasename", purebasename) + try: + ext = kw["ext"] + except KeyError: + pass + else: + if ext and not ext.startswith("."): + ext = "." + ext + kw["basename"] = pb + ext + + if "dirname" in kw and not kw["dirname"]: + kw["dirname"] = drive + else: + kw.setdefault("dirname", dirname) + kw.setdefault("sep", self.sep) + obj.strpath = normpath("%(dirname)s%(sep)s%(basename)s" % kw) + return obj + + def _getbyspec(self, spec: str) -> list[str]: + """See new for what 'spec' can be.""" + res = [] + parts = self.strpath.split(self.sep) + + args = filter(None, spec.split(",")) + for name in args: + if name == "drive": + res.append(parts[0]) + elif name == "dirname": + res.append(self.sep.join(parts[:-1])) + else: + basename = parts[-1] + if name == "basename": + res.append(basename) + else: + i = basename.rfind(".") + if i == -1: + purebasename, ext = basename, "" + else: + purebasename, ext = basename[:i], basename[i:] + if name == "purebasename": + res.append(purebasename) + elif name == "ext": + res.append(ext) + else: + raise ValueError("invalid part specification %r" % name) + return res + + def dirpath(self, *args, **kwargs): + """Return the directory path joined with any given path arguments.""" + if not kwargs: + path = object.__new__(self.__class__) + path.strpath = dirname(self.strpath) + if args: + path = path.join(*args) + return path + return self.new(basename="").join(*args, **kwargs) + + def join(self, *args: os.PathLike[str], abs: bool = False) -> LocalPath: + """Return a new path by appending all 'args' as path + components. if abs=1 is used restart from root if any + of the args is an absolute path. + """ + sep = self.sep + strargs = [os.fspath(arg) for arg in args] + strpath = self.strpath + if abs: + newargs: list[str] = [] + for arg in reversed(strargs): + if isabs(arg): + strpath = arg + strargs = newargs + break + newargs.insert(0, arg) + # special case for when we have e.g. strpath == "/" + actual_sep = "" if strpath.endswith(sep) else sep + for arg in strargs: + arg = arg.strip(sep) + if iswin32: + # allow unix style paths even on windows. + arg = arg.strip("/") + arg = arg.replace("/", sep) + strpath = strpath + actual_sep + arg + actual_sep = sep + obj = object.__new__(self.__class__) + obj.strpath = normpath(strpath) + return obj + + def open(self, mode="r", ensure=False, encoding=None): + """Return an opened file with the given mode. + + If ensure is True, create parent directories if needed. + """ + if ensure: + self.dirpath().ensure(dir=1) + if encoding: + return error.checked_call(io.open, self.strpath, mode, encoding=encoding) + return error.checked_call(open, self.strpath, mode) + + def _fastjoin(self, name): + child = object.__new__(self.__class__) + child.strpath = self.strpath + self.sep + name + return child + + def islink(self): + return islink(self.strpath) + + def check(self, **kw): + """Check a path for existence and properties. + + Without arguments, return True if the path exists, otherwise False. + + valid checkers:: + + file=1 # is a file + file=0 # is not a file (may not even exist) + dir=1 # is a dir + link=1 # is a link + exists=1 # exists + + You can specify multiple checker definitions, for example:: + + path.check(file=1, link=1) # a link pointing to a file + """ + if not kw: + return exists(self.strpath) + if len(kw) == 1: + if "dir" in kw: + return not kw["dir"] ^ isdir(self.strpath) + if "file" in kw: + return not kw["file"] ^ isfile(self.strpath) + if not kw: + kw = {"exists": 1} + return Checkers(self)._evaluate(kw) + + _patternchars = set("*?[" + os.sep) + + def listdir(self, fil=None, sort=None): + """List directory contents, possibly filter by the given fil func + and possibly sorted. + """ + if fil is None and sort is None: + names = error.checked_call(os.listdir, self.strpath) + return map_as_list(self._fastjoin, names) + if isinstance(fil, str): + if not self._patternchars.intersection(fil): + child = self._fastjoin(fil) + if exists(child.strpath): + return [child] + return [] + fil = FNMatcher(fil) + names = error.checked_call(os.listdir, self.strpath) + res = [] + for name in names: + child = self._fastjoin(name) + if fil is None or fil(child): + res.append(child) + self._sortlist(res, sort) + return res + + def size(self) -> int: + """Return size of the underlying file object""" + return self.stat().size + + def mtime(self) -> float: + """Return last modification time of the path.""" + return self.stat().mtime + + def copy(self, target, mode=False, stat=False): + """Copy path to target. + + If mode is True, will copy copy permission from path to target. + If stat is True, copy permission, last modification + time, last access time, and flags from path to target. + """ + if self.check(file=1): + if target.check(dir=1): + target = target.join(self.basename) + assert self != target + copychunked(self, target) + if mode: + copymode(self.strpath, target.strpath) + if stat: + copystat(self, target) + else: + + def rec(p): + return p.check(link=0) + + for x in self.visit(rec=rec): + relpath = x.relto(self) + newx = target.join(relpath) + newx.dirpath().ensure(dir=1) + if x.check(link=1): + newx.mksymlinkto(x.readlink()) + continue + elif x.check(file=1): + copychunked(x, newx) + elif x.check(dir=1): + newx.ensure(dir=1) + if mode: + copymode(x.strpath, newx.strpath) + if stat: + copystat(x, newx) + + def rename(self, target): + """Rename this path to target.""" + target = os.fspath(target) + return error.checked_call(os.rename, self.strpath, target) + + def dump(self, obj, bin=1): + """Pickle object into path location""" + f = self.open("wb") + import pickle + + try: + error.checked_call(pickle.dump, obj, f, bin) + finally: + f.close() + + def mkdir(self, *args): + """Create & return the directory joined with args.""" + p = self.join(*args) + error.checked_call(os.mkdir, os.fspath(p)) + return p + + def write_binary(self, data, ensure=False): + """Write binary data into path. If ensure is True create + missing parent directories. + """ + if ensure: + self.dirpath().ensure(dir=1) + with self.open("wb") as f: + f.write(data) + + def write_text(self, data, encoding, ensure=False): + """Write text data into path using the specified encoding. + If ensure is True create missing parent directories. + """ + if ensure: + self.dirpath().ensure(dir=1) + with self.open("w", encoding=encoding) as f: + f.write(data) + + def write(self, data, mode="w", ensure=False): + """Write data into path. If ensure is True create + missing parent directories. + """ + if ensure: + self.dirpath().ensure(dir=1) + if "b" in mode: + if not isinstance(data, bytes): + raise ValueError("can only process bytes") + else: + if not isinstance(data, str): + if not isinstance(data, bytes): + data = str(data) + else: + data = data.decode(sys.getdefaultencoding()) + f = self.open(mode) + try: + f.write(data) + finally: + f.close() + + def _ensuredirs(self): + parent = self.dirpath() + if parent == self: + return self + if parent.check(dir=0): + parent._ensuredirs() + if self.check(dir=0): + try: + self.mkdir() + except error.EEXIST: + # race condition: file/dir created by another thread/process. + # complain if it is not a dir + if self.check(dir=0): + raise + return self + + def ensure(self, *args, **kwargs): + """Ensure that an args-joined path exists (by default as + a file). if you specify a keyword argument 'dir=True' + then the path is forced to be a directory path. + """ + p = self.join(*args) + if kwargs.get("dir", 0): + return p._ensuredirs() + else: + p.dirpath()._ensuredirs() + if not p.check(file=1): + p.open("wb").close() + return p + + @overload + def stat(self, raising: Literal[True] = ...) -> Stat: + ... + + @overload + def stat(self, raising: Literal[False]) -> Stat | None: + ... + + def stat(self, raising: bool = True) -> Stat | None: + """Return an os.stat() tuple.""" + if raising: + return Stat(self, error.checked_call(os.stat, self.strpath)) + try: + return Stat(self, os.stat(self.strpath)) + except KeyboardInterrupt: + raise + except Exception: + return None + + def lstat(self) -> Stat: + """Return an os.lstat() tuple.""" + return Stat(self, error.checked_call(os.lstat, self.strpath)) + + def setmtime(self, mtime=None): + """Set modification time for the given path. if 'mtime' is None + (the default) then the file's mtime is set to current time. + + Note that the resolution for 'mtime' is platform dependent. + """ + if mtime is None: + return error.checked_call(os.utime, self.strpath, mtime) + try: + return error.checked_call(os.utime, self.strpath, (-1, mtime)) + except error.EINVAL: + return error.checked_call(os.utime, self.strpath, (self.atime(), mtime)) + + def chdir(self): + """Change directory to self and return old current directory""" + try: + old = self.__class__() + except error.ENOENT: + old = None + error.checked_call(os.chdir, self.strpath) + return old + + @contextmanager + def as_cwd(self): + """ + Return a context manager, which changes to the path's dir during the + managed "with" context. + On __enter__ it returns the old dir, which might be ``None``. + """ + old = self.chdir() + try: + yield old + finally: + if old is not None: + old.chdir() + + def realpath(self): + """Return a new path which contains no symbolic links.""" + return self.__class__(os.path.realpath(self.strpath)) + + def atime(self): + """Return last access time of the path.""" + return self.stat().atime + + def __repr__(self): + return "local(%r)" % self.strpath + + def __str__(self): + """Return string representation of the Path.""" + return self.strpath + + def chmod(self, mode, rec=0): + """Change permissions to the given mode. If mode is an + integer it directly encodes the os-specific modes. + if rec is True perform recursively. + """ + if not isinstance(mode, int): + raise TypeError(f"mode {mode!r} must be an integer") + if rec: + for x in self.visit(rec=rec): + error.checked_call(os.chmod, str(x), mode) + error.checked_call(os.chmod, self.strpath, mode) + + def pypkgpath(self): + """Return the Python package path by looking for the last + directory upwards which still contains an __init__.py. + Return None if a pkgpath can not be determined. + """ + pkgpath = None + for parent in self.parts(reverse=True): + if parent.isdir(): + if not parent.join("__init__.py").exists(): + break + if not isimportable(parent.basename): + break + pkgpath = parent + return pkgpath + + def _ensuresyspath(self, ensuremode, path): + if ensuremode: + s = str(path) + if ensuremode == "append": + if s not in sys.path: + sys.path.append(s) + else: + if s != sys.path[0]: + sys.path.insert(0, s) + + def pyimport(self, modname=None, ensuresyspath=True): + """Return path as an imported python module. + + If modname is None, look for the containing package + and construct an according module name. + The module will be put/looked up in sys.modules. + if ensuresyspath is True then the root dir for importing + the file (taking __init__.py files into account) will + be prepended to sys.path if it isn't there already. + If ensuresyspath=="append" the root dir will be appended + if it isn't already contained in sys.path. + if ensuresyspath is False no modification of syspath happens. + + Special value of ensuresyspath=="importlib" is intended + purely for using in pytest, it is capable only of importing + separate .py files outside packages, e.g. for test suite + without any __init__.py file. It effectively allows having + same-named test modules in different places and offers + mild opt-in via this option. Note that it works only in + recent versions of python. + """ + if not self.check(): + raise error.ENOENT(self) + + if ensuresyspath == "importlib": + if modname is None: + modname = self.purebasename + spec = importlib.util.spec_from_file_location(modname, str(self)) + if spec is None or spec.loader is None: + raise ImportError( + f"Can't find module {modname} at location {str(self)}" + ) + mod = importlib.util.module_from_spec(spec) + spec.loader.exec_module(mod) + return mod + + pkgpath = None + if modname is None: + pkgpath = self.pypkgpath() + if pkgpath is not None: + pkgroot = pkgpath.dirpath() + names = self.new(ext="").relto(pkgroot).split(self.sep) + if names[-1] == "__init__": + names.pop() + modname = ".".join(names) + else: + pkgroot = self.dirpath() + modname = self.purebasename + + self._ensuresyspath(ensuresyspath, pkgroot) + __import__(modname) + mod = sys.modules[modname] + if self.basename == "__init__.py": + return mod # we don't check anything as we might + # be in a namespace package ... too icky to check + modfile = mod.__file__ + assert modfile is not None + if modfile[-4:] in (".pyc", ".pyo"): + modfile = modfile[:-1] + elif modfile.endswith("$py.class"): + modfile = modfile[:-9] + ".py" + if modfile.endswith(os.sep + "__init__.py"): + if self.basename != "__init__.py": + modfile = modfile[:-12] + try: + issame = self.samefile(modfile) + except error.ENOENT: + issame = False + if not issame: + ignore = os.getenv("PY_IGNORE_IMPORTMISMATCH") + if ignore != "1": + raise self.ImportMismatchError(modname, modfile, self) + return mod + else: + try: + return sys.modules[modname] + except KeyError: + # we have a custom modname, do a pseudo-import + import types + + mod = types.ModuleType(modname) + mod.__file__ = str(self) + sys.modules[modname] = mod + try: + with open(str(self), "rb") as f: + exec(f.read(), mod.__dict__) + except BaseException: + del sys.modules[modname] + raise + return mod + + def sysexec(self, *argv: os.PathLike[str], **popen_opts: Any) -> str: + """Return stdout text from executing a system child process, + where the 'self' path points to executable. + The process is directly invoked and not through a system shell. + """ + from subprocess import Popen, PIPE + + popen_opts.pop("stdout", None) + popen_opts.pop("stderr", None) + proc = Popen( + [str(self)] + [str(arg) for arg in argv], + **popen_opts, + stdout=PIPE, + stderr=PIPE, + ) + stdout: str | bytes + stdout, stderr = proc.communicate() + ret = proc.wait() + if isinstance(stdout, bytes): + stdout = stdout.decode(sys.getdefaultencoding()) + if ret != 0: + if isinstance(stderr, bytes): + stderr = stderr.decode(sys.getdefaultencoding()) + raise RuntimeError( + ret, + ret, + str(self), + stdout, + stderr, + ) + return stdout + + @classmethod + def sysfind(cls, name, checker=None, paths=None): + """Return a path object found by looking at the systems + underlying PATH specification. If the checker is not None + it will be invoked to filter matching paths. If a binary + cannot be found, None is returned + Note: This is probably not working on plain win32 systems + but may work on cygwin. + """ + if isabs(name): + p = local(name) + if p.check(file=1): + return p + else: + if paths is None: + if iswin32: + paths = os.environ["Path"].split(";") + if "" not in paths and "." not in paths: + paths.append(".") + try: + systemroot = os.environ["SYSTEMROOT"] + except KeyError: + pass + else: + paths = [ + path.replace("%SystemRoot%", systemroot) for path in paths + ] + else: + paths = os.environ["PATH"].split(":") + tryadd = [] + if iswin32: + tryadd += os.environ["PATHEXT"].split(os.pathsep) + tryadd.append("") + + for x in paths: + for addext in tryadd: + p = local(x).join(name, abs=True) + addext + try: + if p.check(file=1): + if checker: + if not checker(p): + continue + return p + except error.EACCES: + pass + return None + + @classmethod + def _gethomedir(cls): + try: + x = os.environ["HOME"] + except KeyError: + try: + x = os.environ["HOMEDRIVE"] + os.environ["HOMEPATH"] + except KeyError: + return None + return cls(x) + + # """ + # special class constructors for local filesystem paths + # """ + @classmethod + def get_temproot(cls): + """Return the system's temporary directory + (where tempfiles are usually created in) + """ + import tempfile + + return local(tempfile.gettempdir()) + + @classmethod + def mkdtemp(cls, rootdir=None): + """Return a Path object pointing to a fresh new temporary directory + (which we created ourself). + """ + import tempfile + + if rootdir is None: + rootdir = cls.get_temproot() + return cls(error.checked_call(tempfile.mkdtemp, dir=str(rootdir))) + + @classmethod + def make_numbered_dir( + cls, prefix="session-", rootdir=None, keep=3, lock_timeout=172800 + ): # two days + """Return unique directory with a number greater than the current + maximum one. The number is assumed to start directly after prefix. + if keep is true directories with a number less than (maxnum-keep) + will be removed. If .lock files are used (lock_timeout non-zero), + algorithm is multi-process safe. + """ + if rootdir is None: + rootdir = cls.get_temproot() + + nprefix = prefix.lower() + + def parse_num(path): + """Parse the number out of a path (if it matches the prefix)""" + nbasename = path.basename.lower() + if nbasename.startswith(nprefix): + try: + return int(nbasename[len(nprefix) :]) + except ValueError: + pass + + def create_lockfile(path): + """Exclusively create lockfile. Throws when failed""" + mypid = os.getpid() + lockfile = path.join(".lock") + if hasattr(lockfile, "mksymlinkto"): + lockfile.mksymlinkto(str(mypid)) + else: + fd = error.checked_call( + os.open, str(lockfile), os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644 + ) + with os.fdopen(fd, "w") as f: + f.write(str(mypid)) + return lockfile + + def atexit_remove_lockfile(lockfile): + """Ensure lockfile is removed at process exit""" + mypid = os.getpid() + + def try_remove_lockfile(): + # in a fork() situation, only the last process should + # remove the .lock, otherwise the other processes run the + # risk of seeing their temporary dir disappear. For now + # we remove the .lock in the parent only (i.e. we assume + # that the children finish before the parent). + if os.getpid() != mypid: + return + try: + lockfile.remove() + except error.Error: + pass + + atexit.register(try_remove_lockfile) + + # compute the maximum number currently in use with the prefix + lastmax = None + while True: + maxnum = -1 + for path in rootdir.listdir(): + num = parse_num(path) + if num is not None: + maxnum = max(maxnum, num) + + # make the new directory + try: + udir = rootdir.mkdir(prefix + str(maxnum + 1)) + if lock_timeout: + lockfile = create_lockfile(udir) + atexit_remove_lockfile(lockfile) + except (error.EEXIST, error.ENOENT, error.EBUSY): + # race condition (1): another thread/process created the dir + # in the meantime - try again + # race condition (2): another thread/process spuriously acquired + # lock treating empty directory as candidate + # for removal - try again + # race condition (3): another thread/process tried to create the lock at + # the same time (happened in Python 3.3 on Windows) + # https://ci.appveyor.com/project/pytestbot/py/build/1.0.21/job/ffi85j4c0lqwsfwa + if lastmax == maxnum: + raise + lastmax = maxnum + continue + break + + def get_mtime(path): + """Read file modification time""" + try: + return path.lstat().mtime + except error.Error: + pass + + garbage_prefix = prefix + "garbage-" + + def is_garbage(path): + """Check if path denotes directory scheduled for removal""" + bn = path.basename + return bn.startswith(garbage_prefix) + + # prune old directories + udir_time = get_mtime(udir) + if keep and udir_time: + for path in rootdir.listdir(): + num = parse_num(path) + if num is not None and num <= (maxnum - keep): + try: + # try acquiring lock to remove directory as exclusive user + if lock_timeout: + create_lockfile(path) + except (error.EEXIST, error.ENOENT, error.EBUSY): + path_time = get_mtime(path) + if not path_time: + # assume directory doesn't exist now + continue + if abs(udir_time - path_time) < lock_timeout: + # assume directory with lockfile exists + # and lock timeout hasn't expired yet + continue + + # path dir locked for exclusive use + # and scheduled for removal to avoid another thread/process + # treating it as a new directory or removal candidate + garbage_path = rootdir.join(garbage_prefix + str(uuid.uuid4())) + try: + path.rename(garbage_path) + garbage_path.remove(rec=1) + except KeyboardInterrupt: + raise + except Exception: # this might be error.Error, WindowsError ... + pass + if is_garbage(path): + try: + path.remove(rec=1) + except KeyboardInterrupt: + raise + except Exception: # this might be error.Error, WindowsError ... + pass + + # make link... + try: + username = os.environ["USER"] # linux, et al + except KeyError: + try: + username = os.environ["USERNAME"] # windows + except KeyError: + username = "current" + + src = str(udir) + dest = src[: src.rfind("-")] + "-" + username + try: + os.unlink(dest) + except OSError: + pass + try: + os.symlink(src, dest) + except (OSError, AttributeError, NotImplementedError): + pass + + return udir + + +def copymode(src, dest): + """Copy permission from src to dst.""" + import shutil + + shutil.copymode(src, dest) + + +def copystat(src, dest): + """Copy permission, last modification time, + last access time, and flags from src to dst.""" + import shutil + + shutil.copystat(str(src), str(dest)) + + +def copychunked(src, dest): + chunksize = 524288 # half a meg of bytes + fsrc = src.open("rb") + try: + fdest = dest.open("wb") + try: + while 1: + buf = fsrc.read(chunksize) + if not buf: + break + fdest.write(buf) + finally: + fdest.close() + finally: + fsrc.close() + + +def isimportable(name): + if name and (name[0].isalpha() or name[0] == "_"): + name = name.replace("_", "") + return not name or name.isalnum() + + +local = LocalPath diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_version.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_version.py new file mode 100644 index 000000000..d530ef481 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/_version.py @@ -0,0 +1,16 @@ +# file generated by setuptools_scm +# don't change, don't track in version control +TYPE_CHECKING = False +if TYPE_CHECKING: + from typing import Tuple, Union + VERSION_TUPLE = Tuple[Union[int, str], ...] +else: + VERSION_TUPLE = object + +version: str +__version__: str +__version_tuple__: VERSION_TUPLE +version_tuple: VERSION_TUPLE + +__version__ = version = '7.4.3' +__version_tuple__ = version_tuple = (7, 4, 3) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/assertion/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/assertion/__init__.py new file mode 100644 index 000000000..a46e58136 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/assertion/__init__.py @@ -0,0 +1,181 @@ +"""Support for presenting detailed information in failing assertions.""" +import sys +from typing import Any +from typing import Generator +from typing import List +from typing import Optional +from typing import TYPE_CHECKING + +from _pytest.assertion import rewrite +from _pytest.assertion import truncate +from _pytest.assertion import util +from _pytest.assertion.rewrite import assertstate_key +from _pytest.config import Config +from _pytest.config import hookimpl +from _pytest.config.argparsing import Parser +from _pytest.nodes import Item + +if TYPE_CHECKING: + from _pytest.main import Session + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("debugconfig") + group.addoption( + "--assert", + action="store", + dest="assertmode", + choices=("rewrite", "plain"), + default="rewrite", + metavar="MODE", + help=( + "Control assertion debugging tools.\n" + "'plain' performs no assertion debugging.\n" + "'rewrite' (the default) rewrites assert statements in test modules" + " on import to provide assert expression information." + ), + ) + parser.addini( + "enable_assertion_pass_hook", + type="bool", + default=False, + help="Enables the pytest_assertion_pass hook. " + "Make sure to delete any previously generated pyc cache files.", + ) + + +def register_assert_rewrite(*names: str) -> None: + """Register one or more module names to be rewritten on import. + + This function will make sure that this module or all modules inside + the package will get their assert statements rewritten. + Thus you should make sure to call this before the module is + actually imported, usually in your __init__.py if you are a plugin + using a package. + + :param names: The module names to register. + """ + for name in names: + if not isinstance(name, str): + msg = "expected module names as *args, got {0} instead" # type: ignore[unreachable] + raise TypeError(msg.format(repr(names))) + for hook in sys.meta_path: + if isinstance(hook, rewrite.AssertionRewritingHook): + importhook = hook + break + else: + # TODO(typing): Add a protocol for mark_rewrite() and use it + # for importhook and for PytestPluginManager.rewrite_hook. + importhook = DummyRewriteHook() # type: ignore + importhook.mark_rewrite(*names) + + +class DummyRewriteHook: + """A no-op import hook for when rewriting is disabled.""" + + def mark_rewrite(self, *names: str) -> None: + pass + + +class AssertionState: + """State for the assertion plugin.""" + + def __init__(self, config: Config, mode) -> None: + self.mode = mode + self.trace = config.trace.root.get("assertion") + self.hook: Optional[rewrite.AssertionRewritingHook] = None + + +def install_importhook(config: Config) -> rewrite.AssertionRewritingHook: + """Try to install the rewrite hook, raise SystemError if it fails.""" + config.stash[assertstate_key] = AssertionState(config, "rewrite") + config.stash[assertstate_key].hook = hook = rewrite.AssertionRewritingHook(config) + sys.meta_path.insert(0, hook) + config.stash[assertstate_key].trace("installed rewrite import hook") + + def undo() -> None: + hook = config.stash[assertstate_key].hook + if hook is not None and hook in sys.meta_path: + sys.meta_path.remove(hook) + + config.add_cleanup(undo) + return hook + + +def pytest_collection(session: "Session") -> None: + # This hook is only called when test modules are collected + # so for example not in the managing process of pytest-xdist + # (which does not collect test modules). + assertstate = session.config.stash.get(assertstate_key, None) + if assertstate: + if assertstate.hook is not None: + assertstate.hook.set_session(session) + + +@hookimpl(tryfirst=True, hookwrapper=True) +def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]: + """Setup the pytest_assertrepr_compare and pytest_assertion_pass hooks. + + The rewrite module will use util._reprcompare if it exists to use custom + reporting via the pytest_assertrepr_compare hook. This sets up this custom + comparison for the test. + """ + + ihook = item.ihook + + def callbinrepr(op, left: object, right: object) -> Optional[str]: + """Call the pytest_assertrepr_compare hook and prepare the result. + + This uses the first result from the hook and then ensures the + following: + * Overly verbose explanations are truncated unless configured otherwise + (eg. if running in verbose mode). + * Embedded newlines are escaped to help util.format_explanation() + later. + * If the rewrite mode is used embedded %-characters are replaced + to protect later % formatting. + + The result can be formatted by util.format_explanation() for + pretty printing. + """ + hook_result = ihook.pytest_assertrepr_compare( + config=item.config, op=op, left=left, right=right + ) + for new_expl in hook_result: + if new_expl: + new_expl = truncate.truncate_if_required(new_expl, item) + new_expl = [line.replace("\n", "\\n") for line in new_expl] + res = "\n~".join(new_expl) + if item.config.getvalue("assertmode") == "rewrite": + res = res.replace("%", "%%") + return res + return None + + saved_assert_hooks = util._reprcompare, util._assertion_pass + util._reprcompare = callbinrepr + util._config = item.config + + if ihook.pytest_assertion_pass.get_hookimpls(): + + def call_assertion_pass_hook(lineno: int, orig: str, expl: str) -> None: + ihook.pytest_assertion_pass(item=item, lineno=lineno, orig=orig, expl=expl) + + util._assertion_pass = call_assertion_pass_hook + + yield + + util._reprcompare, util._assertion_pass = saved_assert_hooks + util._config = None + + +def pytest_sessionfinish(session: "Session") -> None: + assertstate = session.config.stash.get(assertstate_key, None) + if assertstate: + if assertstate.hook is not None: + assertstate.hook.set_session(None) + + +def pytest_assertrepr_compare( + config: Config, op: str, left: Any, right: Any +) -> Optional[List[str]]: + return util.assertrepr_compare(config=config, op=op, left=left, right=right) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/assertion/rewrite.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/assertion/rewrite.py new file mode 100644 index 000000000..fd2355297 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/assertion/rewrite.py @@ -0,0 +1,1211 @@ +"""Rewrite assertion AST to produce nice error messages.""" +import ast +import errno +import functools +import importlib.abc +import importlib.machinery +import importlib.util +import io +import itertools +import marshal +import os +import struct +import sys +import tokenize +import types +from collections import defaultdict +from pathlib import Path +from pathlib import PurePath +from typing import Callable +from typing import Dict +from typing import IO +from typing import Iterable +from typing import Iterator +from typing import List +from typing import Optional +from typing import Sequence +from typing import Set +from typing import Tuple +from typing import TYPE_CHECKING +from typing import Union + +from _pytest._io.saferepr import DEFAULT_REPR_MAX_SIZE +from _pytest._io.saferepr import saferepr +from _pytest._version import version +from _pytest.assertion import util +from _pytest.assertion.util import ( # noqa: F401 + format_explanation as _format_explanation, +) +from _pytest.config import Config +from _pytest.main import Session +from _pytest.pathlib import absolutepath +from _pytest.pathlib import fnmatch_ex +from _pytest.stash import StashKey + +if TYPE_CHECKING: + from _pytest.assertion import AssertionState + +if sys.version_info >= (3, 8): + namedExpr = ast.NamedExpr + astNameConstant = ast.Constant + astStr = ast.Constant + astNum = ast.Constant +else: + namedExpr = ast.Expr + astNameConstant = ast.NameConstant + astStr = ast.Str + astNum = ast.Num + + +class Sentinel: + pass + + +assertstate_key = StashKey["AssertionState"]() + +# pytest caches rewritten pycs in pycache dirs +PYTEST_TAG = f"{sys.implementation.cache_tag}-pytest-{version}" +PYC_EXT = ".py" + (__debug__ and "c" or "o") +PYC_TAIL = "." + PYTEST_TAG + PYC_EXT + +# Special marker that denotes we have just left a scope definition +_SCOPE_END_MARKER = Sentinel() + + +class AssertionRewritingHook(importlib.abc.MetaPathFinder, importlib.abc.Loader): + """PEP302/PEP451 import hook which rewrites asserts.""" + + def __init__(self, config: Config) -> None: + self.config = config + try: + self.fnpats = config.getini("python_files") + except ValueError: + self.fnpats = ["test_*.py", "*_test.py"] + self.session: Optional[Session] = None + self._rewritten_names: Dict[str, Path] = {} + self._must_rewrite: Set[str] = set() + # flag to guard against trying to rewrite a pyc file while we are already writing another pyc file, + # which might result in infinite recursion (#3506) + self._writing_pyc = False + self._basenames_to_check_rewrite = {"conftest"} + self._marked_for_rewrite_cache: Dict[str, bool] = {} + self._session_paths_checked = False + + def set_session(self, session: Optional[Session]) -> None: + self.session = session + self._session_paths_checked = False + + # Indirection so we can mock calls to find_spec originated from the hook during testing + _find_spec = importlib.machinery.PathFinder.find_spec + + def find_spec( + self, + name: str, + path: Optional[Sequence[Union[str, bytes]]] = None, + target: Optional[types.ModuleType] = None, + ) -> Optional[importlib.machinery.ModuleSpec]: + if self._writing_pyc: + return None + state = self.config.stash[assertstate_key] + if self._early_rewrite_bailout(name, state): + return None + state.trace("find_module called for: %s" % name) + + # Type ignored because mypy is confused about the `self` binding here. + spec = self._find_spec(name, path) # type: ignore + if ( + # the import machinery could not find a file to import + spec is None + # this is a namespace package (without `__init__.py`) + # there's nothing to rewrite there + or spec.origin is None + # we can only rewrite source files + or not isinstance(spec.loader, importlib.machinery.SourceFileLoader) + # if the file doesn't exist, we can't rewrite it + or not os.path.exists(spec.origin) + ): + return None + else: + fn = spec.origin + + if not self._should_rewrite(name, fn, state): + return None + + return importlib.util.spec_from_file_location( + name, + fn, + loader=self, + submodule_search_locations=spec.submodule_search_locations, + ) + + def create_module( + self, spec: importlib.machinery.ModuleSpec + ) -> Optional[types.ModuleType]: + return None # default behaviour is fine + + def exec_module(self, module: types.ModuleType) -> None: + assert module.__spec__ is not None + assert module.__spec__.origin is not None + fn = Path(module.__spec__.origin) + state = self.config.stash[assertstate_key] + + self._rewritten_names[module.__name__] = fn + + # The requested module looks like a test file, so rewrite it. This is + # the most magical part of the process: load the source, rewrite the + # asserts, and load the rewritten source. We also cache the rewritten + # module code in a special pyc. We must be aware of the possibility of + # concurrent pytest processes rewriting and loading pycs. To avoid + # tricky race conditions, we maintain the following invariant: The + # cached pyc is always a complete, valid pyc. Operations on it must be + # atomic. POSIX's atomic rename comes in handy. + write = not sys.dont_write_bytecode + cache_dir = get_cache_dir(fn) + if write: + ok = try_makedirs(cache_dir) + if not ok: + write = False + state.trace(f"read only directory: {cache_dir}") + + cache_name = fn.name[:-3] + PYC_TAIL + pyc = cache_dir / cache_name + # Notice that even if we're in a read-only directory, I'm going + # to check for a cached pyc. This may not be optimal... + co = _read_pyc(fn, pyc, state.trace) + if co is None: + state.trace(f"rewriting {fn!r}") + source_stat, co = _rewrite_test(fn, self.config) + if write: + self._writing_pyc = True + try: + _write_pyc(state, co, source_stat, pyc) + finally: + self._writing_pyc = False + else: + state.trace(f"found cached rewritten pyc for {fn}") + exec(co, module.__dict__) + + def _early_rewrite_bailout(self, name: str, state: "AssertionState") -> bool: + """A fast way to get out of rewriting modules. + + Profiling has shown that the call to PathFinder.find_spec (inside of + the find_spec from this class) is a major slowdown, so, this method + tries to filter what we're sure won't be rewritten before getting to + it. + """ + if self.session is not None and not self._session_paths_checked: + self._session_paths_checked = True + for initial_path in self.session._initialpaths: + # Make something as c:/projects/my_project/path.py -> + # ['c:', 'projects', 'my_project', 'path.py'] + parts = str(initial_path).split(os.sep) + # add 'path' to basenames to be checked. + self._basenames_to_check_rewrite.add(os.path.splitext(parts[-1])[0]) + + # Note: conftest already by default in _basenames_to_check_rewrite. + parts = name.split(".") + if parts[-1] in self._basenames_to_check_rewrite: + return False + + # For matching the name it must be as if it was a filename. + path = PurePath(*parts).with_suffix(".py") + + for pat in self.fnpats: + # if the pattern contains subdirectories ("tests/**.py" for example) we can't bail out based + # on the name alone because we need to match against the full path + if os.path.dirname(pat): + return False + if fnmatch_ex(pat, path): + return False + + if self._is_marked_for_rewrite(name, state): + return False + + state.trace(f"early skip of rewriting module: {name}") + return True + + def _should_rewrite(self, name: str, fn: str, state: "AssertionState") -> bool: + # always rewrite conftest files + if os.path.basename(fn) == "conftest.py": + state.trace(f"rewriting conftest file: {fn!r}") + return True + + if self.session is not None: + if self.session.isinitpath(absolutepath(fn)): + state.trace(f"matched test file (was specified on cmdline): {fn!r}") + return True + + # modules not passed explicitly on the command line are only + # rewritten if they match the naming convention for test files + fn_path = PurePath(fn) + for pat in self.fnpats: + if fnmatch_ex(pat, fn_path): + state.trace(f"matched test file {fn!r}") + return True + + return self._is_marked_for_rewrite(name, state) + + def _is_marked_for_rewrite(self, name: str, state: "AssertionState") -> bool: + try: + return self._marked_for_rewrite_cache[name] + except KeyError: + for marked in self._must_rewrite: + if name == marked or name.startswith(marked + "."): + state.trace(f"matched marked file {name!r} (from {marked!r})") + self._marked_for_rewrite_cache[name] = True + return True + + self._marked_for_rewrite_cache[name] = False + return False + + def mark_rewrite(self, *names: str) -> None: + """Mark import names as needing to be rewritten. + + The named module or package as well as any nested modules will + be rewritten on import. + """ + already_imported = ( + set(names).intersection(sys.modules).difference(self._rewritten_names) + ) + for name in already_imported: + mod = sys.modules[name] + if not AssertionRewriter.is_rewrite_disabled( + mod.__doc__ or "" + ) and not isinstance(mod.__loader__, type(self)): + self._warn_already_imported(name) + self._must_rewrite.update(names) + self._marked_for_rewrite_cache.clear() + + def _warn_already_imported(self, name: str) -> None: + from _pytest.warning_types import PytestAssertRewriteWarning + + self.config.issue_config_time_warning( + PytestAssertRewriteWarning( + "Module already imported so cannot be rewritten: %s" % name + ), + stacklevel=5, + ) + + def get_data(self, pathname: Union[str, bytes]) -> bytes: + """Optional PEP302 get_data API.""" + with open(pathname, "rb") as f: + return f.read() + + if sys.version_info >= (3, 10): + if sys.version_info >= (3, 12): + from importlib.resources.abc import TraversableResources + else: + from importlib.abc import TraversableResources + + def get_resource_reader(self, name: str) -> TraversableResources: # type: ignore + if sys.version_info < (3, 11): + from importlib.readers import FileReader + else: + from importlib.resources.readers import FileReader + + return FileReader( # type:ignore[no-any-return] + types.SimpleNamespace(path=self._rewritten_names[name]) + ) + + +def _write_pyc_fp( + fp: IO[bytes], source_stat: os.stat_result, co: types.CodeType +) -> None: + # Technically, we don't have to have the same pyc format as + # (C)Python, since these "pycs" should never be seen by builtin + # import. However, there's little reason to deviate. + fp.write(importlib.util.MAGIC_NUMBER) + # https://www.python.org/dev/peps/pep-0552/ + flags = b"\x00\x00\x00\x00" + fp.write(flags) + # as of now, bytecode header expects 32-bit numbers for size and mtime (#4903) + mtime = int(source_stat.st_mtime) & 0xFFFFFFFF + size = source_stat.st_size & 0xFFFFFFFF + # " bool: + proc_pyc = f"{pyc}.{os.getpid()}" + try: + with open(proc_pyc, "wb") as fp: + _write_pyc_fp(fp, source_stat, co) + except OSError as e: + state.trace(f"error writing pyc file at {proc_pyc}: errno={e.errno}") + return False + + try: + os.replace(proc_pyc, pyc) + except OSError as e: + state.trace(f"error writing pyc file at {pyc}: {e}") + # we ignore any failure to write the cache file + # there are many reasons, permission-denied, pycache dir being a + # file etc. + return False + return True + + +def _rewrite_test(fn: Path, config: Config) -> Tuple[os.stat_result, types.CodeType]: + """Read and rewrite *fn* and return the code object.""" + stat = os.stat(fn) + source = fn.read_bytes() + strfn = str(fn) + tree = ast.parse(source, filename=strfn) + rewrite_asserts(tree, source, strfn, config) + co = compile(tree, strfn, "exec", dont_inherit=True) + return stat, co + + +def _read_pyc( + source: Path, pyc: Path, trace: Callable[[str], None] = lambda x: None +) -> Optional[types.CodeType]: + """Possibly read a pytest pyc containing rewritten code. + + Return rewritten code if successful or None if not. + """ + try: + fp = open(pyc, "rb") + except OSError: + return None + with fp: + try: + stat_result = os.stat(source) + mtime = int(stat_result.st_mtime) + size = stat_result.st_size + data = fp.read(16) + except OSError as e: + trace(f"_read_pyc({source}): OSError {e}") + return None + # Check for invalid or out of date pyc file. + if len(data) != (16): + trace("_read_pyc(%s): invalid pyc (too short)" % source) + return None + if data[:4] != importlib.util.MAGIC_NUMBER: + trace("_read_pyc(%s): invalid pyc (bad magic number)" % source) + return None + if data[4:8] != b"\x00\x00\x00\x00": + trace("_read_pyc(%s): invalid pyc (unsupported flags)" % source) + return None + mtime_data = data[8:12] + if int.from_bytes(mtime_data, "little") != mtime & 0xFFFFFFFF: + trace("_read_pyc(%s): out of date" % source) + return None + size_data = data[12:16] + if int.from_bytes(size_data, "little") != size & 0xFFFFFFFF: + trace("_read_pyc(%s): invalid pyc (incorrect size)" % source) + return None + try: + co = marshal.load(fp) + except Exception as e: + trace(f"_read_pyc({source}): marshal.load error {e}") + return None + if not isinstance(co, types.CodeType): + trace("_read_pyc(%s): not a code object" % source) + return None + return co + + +def rewrite_asserts( + mod: ast.Module, + source: bytes, + module_path: Optional[str] = None, + config: Optional[Config] = None, +) -> None: + """Rewrite the assert statements in mod.""" + AssertionRewriter(module_path, config, source).run(mod) + + +def _saferepr(obj: object) -> str: + r"""Get a safe repr of an object for assertion error messages. + + The assertion formatting (util.format_explanation()) requires + newlines to be escaped since they are a special character for it. + Normally assertion.util.format_explanation() does this but for a + custom repr it is possible to contain one of the special escape + sequences, especially '\n{' and '\n}' are likely to be present in + JSON reprs. + """ + maxsize = _get_maxsize_for_saferepr(util._config) + return saferepr(obj, maxsize=maxsize).replace("\n", "\\n") + + +def _get_maxsize_for_saferepr(config: Optional[Config]) -> Optional[int]: + """Get `maxsize` configuration for saferepr based on the given config object.""" + verbosity = config.getoption("verbose") if config is not None else 0 + if verbosity >= 2: + return None + if verbosity >= 1: + return DEFAULT_REPR_MAX_SIZE * 10 + return DEFAULT_REPR_MAX_SIZE + + +def _format_assertmsg(obj: object) -> str: + r"""Format the custom assertion message given. + + For strings this simply replaces newlines with '\n~' so that + util.format_explanation() will preserve them instead of escaping + newlines. For other objects saferepr() is used first. + """ + # reprlib appears to have a bug which means that if a string + # contains a newline it gets escaped, however if an object has a + # .__repr__() which contains newlines it does not get escaped. + # However in either case we want to preserve the newline. + replaces = [("\n", "\n~"), ("%", "%%")] + if not isinstance(obj, str): + obj = saferepr(obj) + replaces.append(("\\n", "\n~")) + + for r1, r2 in replaces: + obj = obj.replace(r1, r2) + + return obj + + +def _should_repr_global_name(obj: object) -> bool: + if callable(obj): + return False + + try: + return not hasattr(obj, "__name__") + except Exception: + return True + + +def _format_boolop(explanations: Iterable[str], is_or: bool) -> str: + explanation = "(" + (is_or and " or " or " and ").join(explanations) + ")" + return explanation.replace("%", "%%") + + +def _call_reprcompare( + ops: Sequence[str], + results: Sequence[bool], + expls: Sequence[str], + each_obj: Sequence[object], +) -> str: + for i, res, expl in zip(range(len(ops)), results, expls): + try: + done = not res + except Exception: + done = True + if done: + break + if util._reprcompare is not None: + custom = util._reprcompare(ops[i], each_obj[i], each_obj[i + 1]) + if custom is not None: + return custom + return expl + + +def _call_assertion_pass(lineno: int, orig: str, expl: str) -> None: + if util._assertion_pass is not None: + util._assertion_pass(lineno, orig, expl) + + +def _check_if_assertion_pass_impl() -> bool: + """Check if any plugins implement the pytest_assertion_pass hook + in order not to generate explanation unnecessarily (might be expensive).""" + return True if util._assertion_pass else False + + +UNARY_MAP = {ast.Not: "not %s", ast.Invert: "~%s", ast.USub: "-%s", ast.UAdd: "+%s"} + +BINOP_MAP = { + ast.BitOr: "|", + ast.BitXor: "^", + ast.BitAnd: "&", + ast.LShift: "<<", + ast.RShift: ">>", + ast.Add: "+", + ast.Sub: "-", + ast.Mult: "*", + ast.Div: "/", + ast.FloorDiv: "//", + ast.Mod: "%%", # escaped for string formatting + ast.Eq: "==", + ast.NotEq: "!=", + ast.Lt: "<", + ast.LtE: "<=", + ast.Gt: ">", + ast.GtE: ">=", + ast.Pow: "**", + ast.Is: "is", + ast.IsNot: "is not", + ast.In: "in", + ast.NotIn: "not in", + ast.MatMult: "@", +} + + +def traverse_node(node: ast.AST) -> Iterator[ast.AST]: + """Recursively yield node and all its children in depth-first order.""" + yield node + for child in ast.iter_child_nodes(node): + yield from traverse_node(child) + + +@functools.lru_cache(maxsize=1) +def _get_assertion_exprs(src: bytes) -> Dict[int, str]: + """Return a mapping from {lineno: "assertion test expression"}.""" + ret: Dict[int, str] = {} + + depth = 0 + lines: List[str] = [] + assert_lineno: Optional[int] = None + seen_lines: Set[int] = set() + + def _write_and_reset() -> None: + nonlocal depth, lines, assert_lineno, seen_lines + assert assert_lineno is not None + ret[assert_lineno] = "".join(lines).rstrip().rstrip("\\") + depth = 0 + lines = [] + assert_lineno = None + seen_lines = set() + + tokens = tokenize.tokenize(io.BytesIO(src).readline) + for tp, source, (lineno, offset), _, line in tokens: + if tp == tokenize.NAME and source == "assert": + assert_lineno = lineno + elif assert_lineno is not None: + # keep track of depth for the assert-message `,` lookup + if tp == tokenize.OP and source in "([{": + depth += 1 + elif tp == tokenize.OP and source in ")]}": + depth -= 1 + + if not lines: + lines.append(line[offset:]) + seen_lines.add(lineno) + # a non-nested comma separates the expression from the message + elif depth == 0 and tp == tokenize.OP and source == ",": + # one line assert with message + if lineno in seen_lines and len(lines) == 1: + offset_in_trimmed = offset + len(lines[-1]) - len(line) + lines[-1] = lines[-1][:offset_in_trimmed] + # multi-line assert with message + elif lineno in seen_lines: + lines[-1] = lines[-1][:offset] + # multi line assert with escapd newline before message + else: + lines.append(line[:offset]) + _write_and_reset() + elif tp in {tokenize.NEWLINE, tokenize.ENDMARKER}: + _write_and_reset() + elif lines and lineno not in seen_lines: + lines.append(line) + seen_lines.add(lineno) + + return ret + + +class AssertionRewriter(ast.NodeVisitor): + """Assertion rewriting implementation. + + The main entrypoint is to call .run() with an ast.Module instance, + this will then find all the assert statements and rewrite them to + provide intermediate values and a detailed assertion error. See + http://pybites.blogspot.be/2011/07/behind-scenes-of-pytests-new-assertion.html + for an overview of how this works. + + The entry point here is .run() which will iterate over all the + statements in an ast.Module and for each ast.Assert statement it + finds call .visit() with it. Then .visit_Assert() takes over and + is responsible for creating new ast statements to replace the + original assert statement: it rewrites the test of an assertion + to provide intermediate values and replace it with an if statement + which raises an assertion error with a detailed explanation in + case the expression is false and calls pytest_assertion_pass hook + if expression is true. + + For this .visit_Assert() uses the visitor pattern to visit all the + AST nodes of the ast.Assert.test field, each visit call returning + an AST node and the corresponding explanation string. During this + state is kept in several instance attributes: + + :statements: All the AST statements which will replace the assert + statement. + + :variables: This is populated by .variable() with each variable + used by the statements so that they can all be set to None at + the end of the statements. + + :variable_counter: Counter to create new unique variables needed + by statements. Variables are created using .variable() and + have the form of "@py_assert0". + + :expl_stmts: The AST statements which will be executed to get + data from the assertion. This is the code which will construct + the detailed assertion message that is used in the AssertionError + or for the pytest_assertion_pass hook. + + :explanation_specifiers: A dict filled by .explanation_param() + with %-formatting placeholders and their corresponding + expressions to use in the building of an assertion message. + This is used by .pop_format_context() to build a message. + + :stack: A stack of the explanation_specifiers dicts maintained by + .push_format_context() and .pop_format_context() which allows + to build another %-formatted string while already building one. + + :scope: A tuple containing the current scope used for variables_overwrite. + + :variables_overwrite: A dict filled with references to variables + that change value within an assert. This happens when a variable is + reassigned with the walrus operator + + This state, except the variables_overwrite, is reset on every new assert + statement visited and used by the other visitors. + """ + + def __init__( + self, module_path: Optional[str], config: Optional[Config], source: bytes + ) -> None: + super().__init__() + self.module_path = module_path + self.config = config + if config is not None: + self.enable_assertion_pass_hook = config.getini( + "enable_assertion_pass_hook" + ) + else: + self.enable_assertion_pass_hook = False + self.source = source + self.scope: tuple[ast.AST, ...] = () + self.variables_overwrite: defaultdict[ + tuple[ast.AST, ...], Dict[str, str] + ] = defaultdict(dict) + + def run(self, mod: ast.Module) -> None: + """Find all assert statements in *mod* and rewrite them.""" + if not mod.body: + # Nothing to do. + return + + # We'll insert some special imports at the top of the module, but after any + # docstrings and __future__ imports, so first figure out where that is. + doc = getattr(mod, "docstring", None) + expect_docstring = doc is None + if doc is not None and self.is_rewrite_disabled(doc): + return + pos = 0 + item = None + for item in mod.body: + if ( + expect_docstring + and isinstance(item, ast.Expr) + and isinstance(item.value, astStr) + ): + if sys.version_info >= (3, 8): + doc = item.value.value + else: + doc = item.value.s + if self.is_rewrite_disabled(doc): + return + expect_docstring = False + elif ( + isinstance(item, ast.ImportFrom) + and item.level == 0 + and item.module == "__future__" + ): + pass + else: + break + pos += 1 + # Special case: for a decorated function, set the lineno to that of the + # first decorator, not the `def`. Issue #4984. + if isinstance(item, ast.FunctionDef) and item.decorator_list: + lineno = item.decorator_list[0].lineno + else: + lineno = item.lineno + # Now actually insert the special imports. + if sys.version_info >= (3, 10): + aliases = [ + ast.alias("builtins", "@py_builtins", lineno=lineno, col_offset=0), + ast.alias( + "_pytest.assertion.rewrite", + "@pytest_ar", + lineno=lineno, + col_offset=0, + ), + ] + else: + aliases = [ + ast.alias("builtins", "@py_builtins"), + ast.alias("_pytest.assertion.rewrite", "@pytest_ar"), + ] + imports = [ + ast.Import([alias], lineno=lineno, col_offset=0) for alias in aliases + ] + mod.body[pos:pos] = imports + + # Collect asserts. + self.scope = (mod,) + nodes: List[Union[ast.AST, Sentinel]] = [mod] + while nodes: + node = nodes.pop() + if isinstance(node, (ast.FunctionDef, ast.AsyncFunctionDef, ast.ClassDef)): + self.scope = tuple((*self.scope, node)) + nodes.append(_SCOPE_END_MARKER) + if node == _SCOPE_END_MARKER: + self.scope = self.scope[:-1] + continue + assert isinstance(node, ast.AST) + for name, field in ast.iter_fields(node): + if isinstance(field, list): + new: List[ast.AST] = [] + for i, child in enumerate(field): + if isinstance(child, ast.Assert): + # Transform assert. + new.extend(self.visit(child)) + else: + new.append(child) + if isinstance(child, ast.AST): + nodes.append(child) + setattr(node, name, new) + elif ( + isinstance(field, ast.AST) + # Don't recurse into expressions as they can't contain + # asserts. + and not isinstance(field, ast.expr) + ): + nodes.append(field) + + @staticmethod + def is_rewrite_disabled(docstring: str) -> bool: + return "PYTEST_DONT_REWRITE" in docstring + + def variable(self) -> str: + """Get a new variable.""" + # Use a character invalid in python identifiers to avoid clashing. + name = "@py_assert" + str(next(self.variable_counter)) + self.variables.append(name) + return name + + def assign(self, expr: ast.expr) -> ast.Name: + """Give *expr* a name.""" + name = self.variable() + self.statements.append(ast.Assign([ast.Name(name, ast.Store())], expr)) + return ast.Name(name, ast.Load()) + + def display(self, expr: ast.expr) -> ast.expr: + """Call saferepr on the expression.""" + return self.helper("_saferepr", expr) + + def helper(self, name: str, *args: ast.expr) -> ast.expr: + """Call a helper in this module.""" + py_name = ast.Name("@pytest_ar", ast.Load()) + attr = ast.Attribute(py_name, name, ast.Load()) + return ast.Call(attr, list(args), []) + + def builtin(self, name: str) -> ast.Attribute: + """Return the builtin called *name*.""" + builtin_name = ast.Name("@py_builtins", ast.Load()) + return ast.Attribute(builtin_name, name, ast.Load()) + + def explanation_param(self, expr: ast.expr) -> str: + """Return a new named %-formatting placeholder for expr. + + This creates a %-formatting placeholder for expr in the + current formatting context, e.g. ``%(py0)s``. The placeholder + and expr are placed in the current format context so that it + can be used on the next call to .pop_format_context(). + """ + specifier = "py" + str(next(self.variable_counter)) + self.explanation_specifiers[specifier] = expr + return "%(" + specifier + ")s" + + def push_format_context(self) -> None: + """Create a new formatting context. + + The format context is used for when an explanation wants to + have a variable value formatted in the assertion message. In + this case the value required can be added using + .explanation_param(). Finally .pop_format_context() is used + to format a string of %-formatted values as added by + .explanation_param(). + """ + self.explanation_specifiers: Dict[str, ast.expr] = {} + self.stack.append(self.explanation_specifiers) + + def pop_format_context(self, expl_expr: ast.expr) -> ast.Name: + """Format the %-formatted string with current format context. + + The expl_expr should be an str ast.expr instance constructed from + the %-placeholders created by .explanation_param(). This will + add the required code to format said string to .expl_stmts and + return the ast.Name instance of the formatted string. + """ + current = self.stack.pop() + if self.stack: + self.explanation_specifiers = self.stack[-1] + keys = [astStr(key) for key in current.keys()] + format_dict = ast.Dict(keys, list(current.values())) + form = ast.BinOp(expl_expr, ast.Mod(), format_dict) + name = "@py_format" + str(next(self.variable_counter)) + if self.enable_assertion_pass_hook: + self.format_variables.append(name) + self.expl_stmts.append(ast.Assign([ast.Name(name, ast.Store())], form)) + return ast.Name(name, ast.Load()) + + def generic_visit(self, node: ast.AST) -> Tuple[ast.Name, str]: + """Handle expressions we don't have custom code for.""" + assert isinstance(node, ast.expr) + res = self.assign(node) + return res, self.explanation_param(self.display(res)) + + def visit_Assert(self, assert_: ast.Assert) -> List[ast.stmt]: + """Return the AST statements to replace the ast.Assert instance. + + This rewrites the test of an assertion to provide + intermediate values and replace it with an if statement which + raises an assertion error with a detailed explanation in case + the expression is false. + """ + if isinstance(assert_.test, ast.Tuple) and len(assert_.test.elts) >= 1: + from _pytest.warning_types import PytestAssertRewriteWarning + import warnings + + # TODO: This assert should not be needed. + assert self.module_path is not None + warnings.warn_explicit( + PytestAssertRewriteWarning( + "assertion is always true, perhaps remove parentheses?" + ), + category=None, + filename=self.module_path, + lineno=assert_.lineno, + ) + + self.statements: List[ast.stmt] = [] + self.variables: List[str] = [] + self.variable_counter = itertools.count() + + if self.enable_assertion_pass_hook: + self.format_variables: List[str] = [] + + self.stack: List[Dict[str, ast.expr]] = [] + self.expl_stmts: List[ast.stmt] = [] + self.push_format_context() + # Rewrite assert into a bunch of statements. + top_condition, explanation = self.visit(assert_.test) + + negation = ast.UnaryOp(ast.Not(), top_condition) + + if self.enable_assertion_pass_hook: # Experimental pytest_assertion_pass hook + msg = self.pop_format_context(astStr(explanation)) + + # Failed + if assert_.msg: + assertmsg = self.helper("_format_assertmsg", assert_.msg) + gluestr = "\n>assert " + else: + assertmsg = astStr("") + gluestr = "assert " + err_explanation = ast.BinOp(astStr(gluestr), ast.Add(), msg) + err_msg = ast.BinOp(assertmsg, ast.Add(), err_explanation) + err_name = ast.Name("AssertionError", ast.Load()) + fmt = self.helper("_format_explanation", err_msg) + exc = ast.Call(err_name, [fmt], []) + raise_ = ast.Raise(exc, None) + statements_fail = [] + statements_fail.extend(self.expl_stmts) + statements_fail.append(raise_) + + # Passed + fmt_pass = self.helper("_format_explanation", msg) + orig = _get_assertion_exprs(self.source)[assert_.lineno] + hook_call_pass = ast.Expr( + self.helper( + "_call_assertion_pass", + astNum(assert_.lineno), + astStr(orig), + fmt_pass, + ) + ) + # If any hooks implement assert_pass hook + hook_impl_test = ast.If( + self.helper("_check_if_assertion_pass_impl"), + self.expl_stmts + [hook_call_pass], + [], + ) + statements_pass = [hook_impl_test] + + # Test for assertion condition + main_test = ast.If(negation, statements_fail, statements_pass) + self.statements.append(main_test) + if self.format_variables: + variables = [ + ast.Name(name, ast.Store()) for name in self.format_variables + ] + clear_format = ast.Assign(variables, astNameConstant(None)) + self.statements.append(clear_format) + + else: # Original assertion rewriting + # Create failure message. + body = self.expl_stmts + self.statements.append(ast.If(negation, body, [])) + if assert_.msg: + assertmsg = self.helper("_format_assertmsg", assert_.msg) + explanation = "\n>assert " + explanation + else: + assertmsg = astStr("") + explanation = "assert " + explanation + template = ast.BinOp(assertmsg, ast.Add(), astStr(explanation)) + msg = self.pop_format_context(template) + fmt = self.helper("_format_explanation", msg) + err_name = ast.Name("AssertionError", ast.Load()) + exc = ast.Call(err_name, [fmt], []) + raise_ = ast.Raise(exc, None) + + body.append(raise_) + + # Clear temporary variables by setting them to None. + if self.variables: + variables = [ast.Name(name, ast.Store()) for name in self.variables] + clear = ast.Assign(variables, astNameConstant(None)) + self.statements.append(clear) + # Fix locations (line numbers/column offsets). + for stmt in self.statements: + for node in traverse_node(stmt): + ast.copy_location(node, assert_) + return self.statements + + def visit_NamedExpr(self, name: namedExpr) -> Tuple[namedExpr, str]: + # This method handles the 'walrus operator' repr of the target + # name if it's a local variable or _should_repr_global_name() + # thinks it's acceptable. + locs = ast.Call(self.builtin("locals"), [], []) + target_id = name.target.id # type: ignore[attr-defined] + inlocs = ast.Compare(astStr(target_id), [ast.In()], [locs]) + dorepr = self.helper("_should_repr_global_name", name) + test = ast.BoolOp(ast.Or(), [inlocs, dorepr]) + expr = ast.IfExp(test, self.display(name), astStr(target_id)) + return name, self.explanation_param(expr) + + def visit_Name(self, name: ast.Name) -> Tuple[ast.Name, str]: + # Display the repr of the name if it's a local variable or + # _should_repr_global_name() thinks it's acceptable. + locs = ast.Call(self.builtin("locals"), [], []) + inlocs = ast.Compare(astStr(name.id), [ast.In()], [locs]) + dorepr = self.helper("_should_repr_global_name", name) + test = ast.BoolOp(ast.Or(), [inlocs, dorepr]) + expr = ast.IfExp(test, self.display(name), astStr(name.id)) + return name, self.explanation_param(expr) + + def visit_BoolOp(self, boolop: ast.BoolOp) -> Tuple[ast.Name, str]: + res_var = self.variable() + expl_list = self.assign(ast.List([], ast.Load())) + app = ast.Attribute(expl_list, "append", ast.Load()) + is_or = int(isinstance(boolop.op, ast.Or)) + body = save = self.statements + fail_save = self.expl_stmts + levels = len(boolop.values) - 1 + self.push_format_context() + # Process each operand, short-circuiting if needed. + for i, v in enumerate(boolop.values): + if i: + fail_inner: List[ast.stmt] = [] + # cond is set in a prior loop iteration below + self.expl_stmts.append(ast.If(cond, fail_inner, [])) # noqa + self.expl_stmts = fail_inner + # Check if the left operand is a namedExpr and the value has already been visited + if ( + isinstance(v, ast.Compare) + and isinstance(v.left, namedExpr) + and v.left.target.id + in [ + ast_expr.id + for ast_expr in boolop.values[:i] + if hasattr(ast_expr, "id") + ] + ): + pytest_temp = self.variable() + self.variables_overwrite[self.scope][ + v.left.target.id + ] = v.left # type:ignore[assignment] + v.left.target.id = pytest_temp + self.push_format_context() + res, expl = self.visit(v) + body.append(ast.Assign([ast.Name(res_var, ast.Store())], res)) + expl_format = self.pop_format_context(astStr(expl)) + call = ast.Call(app, [expl_format], []) + self.expl_stmts.append(ast.Expr(call)) + if i < levels: + cond: ast.expr = res + if is_or: + cond = ast.UnaryOp(ast.Not(), cond) + inner: List[ast.stmt] = [] + self.statements.append(ast.If(cond, inner, [])) + self.statements = body = inner + self.statements = save + self.expl_stmts = fail_save + expl_template = self.helper("_format_boolop", expl_list, astNum(is_or)) + expl = self.pop_format_context(expl_template) + return ast.Name(res_var, ast.Load()), self.explanation_param(expl) + + def visit_UnaryOp(self, unary: ast.UnaryOp) -> Tuple[ast.Name, str]: + pattern = UNARY_MAP[unary.op.__class__] + operand_res, operand_expl = self.visit(unary.operand) + res = self.assign(ast.UnaryOp(unary.op, operand_res)) + return res, pattern % (operand_expl,) + + def visit_BinOp(self, binop: ast.BinOp) -> Tuple[ast.Name, str]: + symbol = BINOP_MAP[binop.op.__class__] + left_expr, left_expl = self.visit(binop.left) + right_expr, right_expl = self.visit(binop.right) + explanation = f"({left_expl} {symbol} {right_expl})" + res = self.assign(ast.BinOp(left_expr, binop.op, right_expr)) + return res, explanation + + def visit_Call(self, call: ast.Call) -> Tuple[ast.Name, str]: + new_func, func_expl = self.visit(call.func) + arg_expls = [] + new_args = [] + new_kwargs = [] + for arg in call.args: + if isinstance(arg, ast.Name) and arg.id in self.variables_overwrite.get( + self.scope, {} + ): + arg = self.variables_overwrite[self.scope][ + arg.id + ] # type:ignore[assignment] + res, expl = self.visit(arg) + arg_expls.append(expl) + new_args.append(res) + for keyword in call.keywords: + if isinstance( + keyword.value, ast.Name + ) and keyword.value.id in self.variables_overwrite.get(self.scope, {}): + keyword.value = self.variables_overwrite[self.scope][ + keyword.value.id + ] # type:ignore[assignment] + res, expl = self.visit(keyword.value) + new_kwargs.append(ast.keyword(keyword.arg, res)) + if keyword.arg: + arg_expls.append(keyword.arg + "=" + expl) + else: # **args have `arg` keywords with an .arg of None + arg_expls.append("**" + expl) + + expl = "{}({})".format(func_expl, ", ".join(arg_expls)) + new_call = ast.Call(new_func, new_args, new_kwargs) + res = self.assign(new_call) + res_expl = self.explanation_param(self.display(res)) + outer_expl = f"{res_expl}\n{{{res_expl} = {expl}\n}}" + return res, outer_expl + + def visit_Starred(self, starred: ast.Starred) -> Tuple[ast.Starred, str]: + # A Starred node can appear in a function call. + res, expl = self.visit(starred.value) + new_starred = ast.Starred(res, starred.ctx) + return new_starred, "*" + expl + + def visit_Attribute(self, attr: ast.Attribute) -> Tuple[ast.Name, str]: + if not isinstance(attr.ctx, ast.Load): + return self.generic_visit(attr) + value, value_expl = self.visit(attr.value) + res = self.assign(ast.Attribute(value, attr.attr, ast.Load())) + res_expl = self.explanation_param(self.display(res)) + pat = "%s\n{%s = %s.%s\n}" + expl = pat % (res_expl, res_expl, value_expl, attr.attr) + return res, expl + + def visit_Compare(self, comp: ast.Compare) -> Tuple[ast.expr, str]: + self.push_format_context() + # We first check if we have overwritten a variable in the previous assert + if isinstance( + comp.left, ast.Name + ) and comp.left.id in self.variables_overwrite.get(self.scope, {}): + comp.left = self.variables_overwrite[self.scope][ + comp.left.id + ] # type:ignore[assignment] + if isinstance(comp.left, namedExpr): + self.variables_overwrite[self.scope][ + comp.left.target.id + ] = comp.left # type:ignore[assignment] + left_res, left_expl = self.visit(comp.left) + if isinstance(comp.left, (ast.Compare, ast.BoolOp)): + left_expl = f"({left_expl})" + res_variables = [self.variable() for i in range(len(comp.ops))] + load_names = [ast.Name(v, ast.Load()) for v in res_variables] + store_names = [ast.Name(v, ast.Store()) for v in res_variables] + it = zip(range(len(comp.ops)), comp.ops, comp.comparators) + expls = [] + syms = [] + results = [left_res] + for i, op, next_operand in it: + if ( + isinstance(next_operand, namedExpr) + and isinstance(left_res, ast.Name) + and next_operand.target.id == left_res.id + ): + next_operand.target.id = self.variable() + self.variables_overwrite[self.scope][ + left_res.id + ] = next_operand # type:ignore[assignment] + next_res, next_expl = self.visit(next_operand) + if isinstance(next_operand, (ast.Compare, ast.BoolOp)): + next_expl = f"({next_expl})" + results.append(next_res) + sym = BINOP_MAP[op.__class__] + syms.append(astStr(sym)) + expl = f"{left_expl} {sym} {next_expl}" + expls.append(astStr(expl)) + res_expr = ast.Compare(left_res, [op], [next_res]) + self.statements.append(ast.Assign([store_names[i]], res_expr)) + left_res, left_expl = next_res, next_expl + # Use pytest.assertion.util._reprcompare if that's available. + expl_call = self.helper( + "_call_reprcompare", + ast.Tuple(syms, ast.Load()), + ast.Tuple(load_names, ast.Load()), + ast.Tuple(expls, ast.Load()), + ast.Tuple(results, ast.Load()), + ) + if len(comp.ops) > 1: + res: ast.expr = ast.BoolOp(ast.And(), load_names) + else: + res = load_names[0] + + return res, self.explanation_param(self.pop_format_context(expl_call)) + + +def try_makedirs(cache_dir: Path) -> bool: + """Attempt to create the given directory and sub-directories exist. + + Returns True if successful or if it already exists. + """ + try: + os.makedirs(cache_dir, exist_ok=True) + except (FileNotFoundError, NotADirectoryError, FileExistsError): + # One of the path components was not a directory: + # - we're in a zip file + # - it is a file + return False + except PermissionError: + return False + except OSError as e: + # as of now, EROFS doesn't have an equivalent OSError-subclass + if e.errno == errno.EROFS: + return False + raise + return True + + +def get_cache_dir(file_path: Path) -> Path: + """Return the cache directory to write .pyc files for the given .py file path.""" + if sys.version_info >= (3, 8) and sys.pycache_prefix: + # given: + # prefix = '/tmp/pycs' + # path = '/home/user/proj/test_app.py' + # we want: + # '/tmp/pycs/home/user/proj' + return Path(sys.pycache_prefix) / Path(*file_path.parts[1:-1]) + else: + # classic pycache directory + return file_path.parent / "__pycache__" diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/assertion/truncate.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/assertion/truncate.py new file mode 100644 index 000000000..dfd6f65d2 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/assertion/truncate.py @@ -0,0 +1,115 @@ +"""Utilities for truncating assertion output. + +Current default behaviour is to truncate assertion explanations at +~8 terminal lines, unless running in "-vv" mode or running on CI. +""" +from typing import List +from typing import Optional + +from _pytest.assertion import util +from _pytest.nodes import Item + + +DEFAULT_MAX_LINES = 8 +DEFAULT_MAX_CHARS = 8 * 80 +USAGE_MSG = "use '-vv' to show" + + +def truncate_if_required( + explanation: List[str], item: Item, max_length: Optional[int] = None +) -> List[str]: + """Truncate this assertion explanation if the given test item is eligible.""" + if _should_truncate_item(item): + return _truncate_explanation(explanation) + return explanation + + +def _should_truncate_item(item: Item) -> bool: + """Whether or not this test item is eligible for truncation.""" + verbose = item.config.option.verbose + return verbose < 2 and not util.running_on_ci() + + +def _truncate_explanation( + input_lines: List[str], + max_lines: Optional[int] = None, + max_chars: Optional[int] = None, +) -> List[str]: + """Truncate given list of strings that makes up the assertion explanation. + + Truncates to either 8 lines, or 640 characters - whichever the input reaches + first, taking the truncation explanation into account. The remaining lines + will be replaced by a usage message. + """ + if max_lines is None: + max_lines = DEFAULT_MAX_LINES + if max_chars is None: + max_chars = DEFAULT_MAX_CHARS + + # Check if truncation required + input_char_count = len("".join(input_lines)) + # The length of the truncation explanation depends on the number of lines + # removed but is at least 68 characters: + # The real value is + # 64 (for the base message: + # '...\n...Full output truncated (1 line hidden), use '-vv' to show")' + # ) + # + 1 (for plural) + # + int(math.log10(len(input_lines) - max_lines)) (number of hidden line, at least 1) + # + 3 for the '...' added to the truncated line + # But if there's more than 100 lines it's very likely that we're going to + # truncate, so we don't need the exact value using log10. + tolerable_max_chars = ( + max_chars + 70 # 64 + 1 (for plural) + 2 (for '99') + 3 for '...' + ) + # The truncation explanation add two lines to the output + tolerable_max_lines = max_lines + 2 + if ( + len(input_lines) <= tolerable_max_lines + and input_char_count <= tolerable_max_chars + ): + return input_lines + # Truncate first to max_lines, and then truncate to max_chars if necessary + truncated_explanation = input_lines[:max_lines] + truncated_char = True + # We reevaluate the need to truncate chars following removal of some lines + if len("".join(truncated_explanation)) > tolerable_max_chars: + truncated_explanation = _truncate_by_char_count( + truncated_explanation, max_chars + ) + else: + truncated_char = False + + truncated_line_count = len(input_lines) - len(truncated_explanation) + if truncated_explanation[-1]: + # Add ellipsis and take into account part-truncated final line + truncated_explanation[-1] = truncated_explanation[-1] + "..." + if truncated_char: + # It's possible that we did not remove any char from this line + truncated_line_count += 1 + else: + # Add proper ellipsis when we were able to fit a full line exactly + truncated_explanation[-1] = "..." + return truncated_explanation + [ + "", + f"...Full output truncated ({truncated_line_count} line" + f"{'' if truncated_line_count == 1 else 's'} hidden), {USAGE_MSG}", + ] + + +def _truncate_by_char_count(input_lines: List[str], max_chars: int) -> List[str]: + # Find point at which input length exceeds total allowed length + iterated_char_count = 0 + for iterated_index, input_line in enumerate(input_lines): + if iterated_char_count + len(input_line) > max_chars: + break + iterated_char_count += len(input_line) + + # Create truncated explanation with modified final line + truncated_result = input_lines[:iterated_index] + final_line = input_lines[iterated_index] + if final_line: + final_line_truncate_point = max_chars - iterated_char_count + final_line = final_line[:final_line_truncate_point] + truncated_result.append(final_line) + return truncated_result diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/assertion/util.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/assertion/util.py new file mode 100644 index 000000000..fc5dfdbd5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/assertion/util.py @@ -0,0 +1,522 @@ +"""Utilities for assertion debugging.""" +import collections.abc +import os +import pprint +from typing import AbstractSet +from typing import Any +from typing import Callable +from typing import Iterable +from typing import List +from typing import Mapping +from typing import Optional +from typing import Sequence +from unicodedata import normalize + +import _pytest._code +from _pytest import outcomes +from _pytest._io.saferepr import _pformat_dispatch +from _pytest._io.saferepr import saferepr +from _pytest._io.saferepr import saferepr_unlimited +from _pytest.config import Config + +# The _reprcompare attribute on the util module is used by the new assertion +# interpretation code and assertion rewriter to detect this plugin was +# loaded and in turn call the hooks defined here as part of the +# DebugInterpreter. +_reprcompare: Optional[Callable[[str, object, object], Optional[str]]] = None + +# Works similarly as _reprcompare attribute. Is populated with the hook call +# when pytest_runtest_setup is called. +_assertion_pass: Optional[Callable[[int, str, str], None]] = None + +# Config object which is assigned during pytest_runtest_protocol. +_config: Optional[Config] = None + + +def format_explanation(explanation: str) -> str: + r"""Format an explanation. + + Normally all embedded newlines are escaped, however there are + three exceptions: \n{, \n} and \n~. The first two are intended + cover nested explanations, see function and attribute explanations + for examples (.visit_Call(), visit_Attribute()). The last one is + for when one explanation needs to span multiple lines, e.g. when + displaying diffs. + """ + lines = _split_explanation(explanation) + result = _format_lines(lines) + return "\n".join(result) + + +def _split_explanation(explanation: str) -> List[str]: + r"""Return a list of individual lines in the explanation. + + This will return a list of lines split on '\n{', '\n}' and '\n~'. + Any other newlines will be escaped and appear in the line as the + literal '\n' characters. + """ + raw_lines = (explanation or "").split("\n") + lines = [raw_lines[0]] + for values in raw_lines[1:]: + if values and values[0] in ["{", "}", "~", ">"]: + lines.append(values) + else: + lines[-1] += "\\n" + values + return lines + + +def _format_lines(lines: Sequence[str]) -> List[str]: + """Format the individual lines. + + This will replace the '{', '}' and '~' characters of our mini formatting + language with the proper 'where ...', 'and ...' and ' + ...' text, taking + care of indentation along the way. + + Return a list of formatted lines. + """ + result = list(lines[:1]) + stack = [0] + stackcnt = [0] + for line in lines[1:]: + if line.startswith("{"): + if stackcnt[-1]: + s = "and " + else: + s = "where " + stack.append(len(result)) + stackcnt[-1] += 1 + stackcnt.append(0) + result.append(" +" + " " * (len(stack) - 1) + s + line[1:]) + elif line.startswith("}"): + stack.pop() + stackcnt.pop() + result[stack[-1]] += line[1:] + else: + assert line[0] in ["~", ">"] + stack[-1] += 1 + indent = len(stack) if line.startswith("~") else len(stack) - 1 + result.append(" " * indent + line[1:]) + assert len(stack) == 1 + return result + + +def issequence(x: Any) -> bool: + return isinstance(x, collections.abc.Sequence) and not isinstance(x, str) + + +def istext(x: Any) -> bool: + return isinstance(x, str) + + +def isdict(x: Any) -> bool: + return isinstance(x, dict) + + +def isset(x: Any) -> bool: + return isinstance(x, (set, frozenset)) + + +def isnamedtuple(obj: Any) -> bool: + return isinstance(obj, tuple) and getattr(obj, "_fields", None) is not None + + +def isdatacls(obj: Any) -> bool: + return getattr(obj, "__dataclass_fields__", None) is not None + + +def isattrs(obj: Any) -> bool: + return getattr(obj, "__attrs_attrs__", None) is not None + + +def isiterable(obj: Any) -> bool: + try: + iter(obj) + return not istext(obj) + except TypeError: + return False + + +def has_default_eq( + obj: object, +) -> bool: + """Check if an instance of an object contains the default eq + + First, we check if the object's __eq__ attribute has __code__, + if so, we check the equally of the method code filename (__code__.co_filename) + to the default one generated by the dataclass and attr module + for dataclasses the default co_filename is , for attrs class, the __eq__ should contain "attrs eq generated" + """ + # inspired from https://github.com/willmcgugan/rich/blob/07d51ffc1aee6f16bd2e5a25b4e82850fb9ed778/rich/pretty.py#L68 + if hasattr(obj.__eq__, "__code__") and hasattr(obj.__eq__.__code__, "co_filename"): + code_filename = obj.__eq__.__code__.co_filename + + if isattrs(obj): + return "attrs generated eq" in code_filename + + return code_filename == "" # data class + return True + + +def assertrepr_compare( + config, op: str, left: Any, right: Any, use_ascii: bool = False +) -> Optional[List[str]]: + """Return specialised explanations for some operators/operands.""" + verbose = config.getoption("verbose") + + # Strings which normalize equal are often hard to distinguish when printed; use ascii() to make this easier. + # See issue #3246. + use_ascii = ( + isinstance(left, str) + and isinstance(right, str) + and normalize("NFD", left) == normalize("NFD", right) + ) + + if verbose > 1: + left_repr = saferepr_unlimited(left, use_ascii=use_ascii) + right_repr = saferepr_unlimited(right, use_ascii=use_ascii) + else: + # XXX: "15 chars indentation" is wrong + # ("E AssertionError: assert "); should use term width. + maxsize = ( + 80 - 15 - len(op) - 2 + ) // 2 # 15 chars indentation, 1 space around op + + left_repr = saferepr(left, maxsize=maxsize, use_ascii=use_ascii) + right_repr = saferepr(right, maxsize=maxsize, use_ascii=use_ascii) + + summary = f"{left_repr} {op} {right_repr}" + + explanation = None + try: + if op == "==": + explanation = _compare_eq_any(left, right, verbose) + elif op == "not in": + if istext(left) and istext(right): + explanation = _notin_text(left, right, verbose) + except outcomes.Exit: + raise + except Exception: + explanation = [ + "(pytest_assertion plugin: representation of details failed: {}.".format( + _pytest._code.ExceptionInfo.from_current()._getreprcrash() + ), + " Probably an object has a faulty __repr__.)", + ] + + if not explanation: + return None + + return [summary] + explanation + + +def _compare_eq_any(left: Any, right: Any, verbose: int = 0) -> List[str]: + explanation = [] + if istext(left) and istext(right): + explanation = _diff_text(left, right, verbose) + else: + from _pytest.python_api import ApproxBase + + if isinstance(left, ApproxBase) or isinstance(right, ApproxBase): + # Although the common order should be obtained == expected, this ensures both ways + approx_side = left if isinstance(left, ApproxBase) else right + other_side = right if isinstance(left, ApproxBase) else left + + explanation = approx_side._repr_compare(other_side) + elif type(left) == type(right) and ( + isdatacls(left) or isattrs(left) or isnamedtuple(left) + ): + # Note: unlike dataclasses/attrs, namedtuples compare only the + # field values, not the type or field names. But this branch + # intentionally only handles the same-type case, which was often + # used in older code bases before dataclasses/attrs were available. + explanation = _compare_eq_cls(left, right, verbose) + elif issequence(left) and issequence(right): + explanation = _compare_eq_sequence(left, right, verbose) + elif isset(left) and isset(right): + explanation = _compare_eq_set(left, right, verbose) + elif isdict(left) and isdict(right): + explanation = _compare_eq_dict(left, right, verbose) + + if isiterable(left) and isiterable(right): + expl = _compare_eq_iterable(left, right, verbose) + explanation.extend(expl) + + return explanation + + +def _diff_text(left: str, right: str, verbose: int = 0) -> List[str]: + """Return the explanation for the diff between text. + + Unless --verbose is used this will skip leading and trailing + characters which are identical to keep the diff minimal. + """ + from difflib import ndiff + + explanation: List[str] = [] + + if verbose < 1: + i = 0 # just in case left or right has zero length + for i in range(min(len(left), len(right))): + if left[i] != right[i]: + break + if i > 42: + i -= 10 # Provide some context + explanation = [ + "Skipping %s identical leading characters in diff, use -v to show" % i + ] + left = left[i:] + right = right[i:] + if len(left) == len(right): + for i in range(len(left)): + if left[-i] != right[-i]: + break + if i > 42: + i -= 10 # Provide some context + explanation += [ + "Skipping {} identical trailing " + "characters in diff, use -v to show".format(i) + ] + left = left[:-i] + right = right[:-i] + keepends = True + if left.isspace() or right.isspace(): + left = repr(str(left)) + right = repr(str(right)) + explanation += ["Strings contain only whitespace, escaping them using repr()"] + # "right" is the expected base against which we compare "left", + # see https://github.com/pytest-dev/pytest/issues/3333 + explanation += [ + line.strip("\n") + for line in ndiff(right.splitlines(keepends), left.splitlines(keepends)) + ] + return explanation + + +def _surrounding_parens_on_own_lines(lines: List[str]) -> None: + """Move opening/closing parenthesis/bracket to own lines.""" + opening = lines[0][:1] + if opening in ["(", "[", "{"]: + lines[0] = " " + lines[0][1:] + lines[:] = [opening] + lines + closing = lines[-1][-1:] + if closing in [")", "]", "}"]: + lines[-1] = lines[-1][:-1] + "," + lines[:] = lines + [closing] + + +def _compare_eq_iterable( + left: Iterable[Any], right: Iterable[Any], verbose: int = 0 +) -> List[str]: + if verbose <= 0 and not running_on_ci(): + return ["Use -v to get more diff"] + # dynamic import to speedup pytest + import difflib + + left_formatting = pprint.pformat(left).splitlines() + right_formatting = pprint.pformat(right).splitlines() + + # Re-format for different output lengths. + lines_left = len(left_formatting) + lines_right = len(right_formatting) + if lines_left != lines_right: + left_formatting = _pformat_dispatch(left).splitlines() + right_formatting = _pformat_dispatch(right).splitlines() + + if lines_left > 1 or lines_right > 1: + _surrounding_parens_on_own_lines(left_formatting) + _surrounding_parens_on_own_lines(right_formatting) + + explanation = ["Full diff:"] + # "right" is the expected base against which we compare "left", + # see https://github.com/pytest-dev/pytest/issues/3333 + explanation.extend( + line.rstrip() for line in difflib.ndiff(right_formatting, left_formatting) + ) + return explanation + + +def _compare_eq_sequence( + left: Sequence[Any], right: Sequence[Any], verbose: int = 0 +) -> List[str]: + comparing_bytes = isinstance(left, bytes) and isinstance(right, bytes) + explanation: List[str] = [] + len_left = len(left) + len_right = len(right) + for i in range(min(len_left, len_right)): + if left[i] != right[i]: + if comparing_bytes: + # when comparing bytes, we want to see their ascii representation + # instead of their numeric values (#5260) + # using a slice gives us the ascii representation: + # >>> s = b'foo' + # >>> s[0] + # 102 + # >>> s[0:1] + # b'f' + left_value = left[i : i + 1] + right_value = right[i : i + 1] + else: + left_value = left[i] + right_value = right[i] + + explanation += [f"At index {i} diff: {left_value!r} != {right_value!r}"] + break + + if comparing_bytes: + # when comparing bytes, it doesn't help to show the "sides contain one or more + # items" longer explanation, so skip it + + return explanation + + len_diff = len_left - len_right + if len_diff: + if len_diff > 0: + dir_with_more = "Left" + extra = saferepr(left[len_right]) + else: + len_diff = 0 - len_diff + dir_with_more = "Right" + extra = saferepr(right[len_left]) + + if len_diff == 1: + explanation += [f"{dir_with_more} contains one more item: {extra}"] + else: + explanation += [ + "%s contains %d more items, first extra item: %s" + % (dir_with_more, len_diff, extra) + ] + return explanation + + +def _compare_eq_set( + left: AbstractSet[Any], right: AbstractSet[Any], verbose: int = 0 +) -> List[str]: + explanation = [] + diff_left = left - right + diff_right = right - left + if diff_left: + explanation.append("Extra items in the left set:") + for item in diff_left: + explanation.append(saferepr(item)) + if diff_right: + explanation.append("Extra items in the right set:") + for item in diff_right: + explanation.append(saferepr(item)) + return explanation + + +def _compare_eq_dict( + left: Mapping[Any, Any], right: Mapping[Any, Any], verbose: int = 0 +) -> List[str]: + explanation: List[str] = [] + set_left = set(left) + set_right = set(right) + common = set_left.intersection(set_right) + same = {k: left[k] for k in common if left[k] == right[k]} + if same and verbose < 2: + explanation += ["Omitting %s identical items, use -vv to show" % len(same)] + elif same: + explanation += ["Common items:"] + explanation += pprint.pformat(same).splitlines() + diff = {k for k in common if left[k] != right[k]} + if diff: + explanation += ["Differing items:"] + for k in diff: + explanation += [saferepr({k: left[k]}) + " != " + saferepr({k: right[k]})] + extra_left = set_left - set_right + len_extra_left = len(extra_left) + if len_extra_left: + explanation.append( + "Left contains %d more item%s:" + % (len_extra_left, "" if len_extra_left == 1 else "s") + ) + explanation.extend( + pprint.pformat({k: left[k] for k in extra_left}).splitlines() + ) + extra_right = set_right - set_left + len_extra_right = len(extra_right) + if len_extra_right: + explanation.append( + "Right contains %d more item%s:" + % (len_extra_right, "" if len_extra_right == 1 else "s") + ) + explanation.extend( + pprint.pformat({k: right[k] for k in extra_right}).splitlines() + ) + return explanation + + +def _compare_eq_cls(left: Any, right: Any, verbose: int) -> List[str]: + if not has_default_eq(left): + return [] + if isdatacls(left): + import dataclasses + + all_fields = dataclasses.fields(left) + fields_to_check = [info.name for info in all_fields if info.compare] + elif isattrs(left): + all_fields = left.__attrs_attrs__ + fields_to_check = [field.name for field in all_fields if getattr(field, "eq")] + elif isnamedtuple(left): + fields_to_check = left._fields + else: + assert False + + indent = " " + same = [] + diff = [] + for field in fields_to_check: + if getattr(left, field) == getattr(right, field): + same.append(field) + else: + diff.append(field) + + explanation = [] + if same or diff: + explanation += [""] + if same and verbose < 2: + explanation.append("Omitting %s identical items, use -vv to show" % len(same)) + elif same: + explanation += ["Matching attributes:"] + explanation += pprint.pformat(same).splitlines() + if diff: + explanation += ["Differing attributes:"] + explanation += pprint.pformat(diff).splitlines() + for field in diff: + field_left = getattr(left, field) + field_right = getattr(right, field) + explanation += [ + "", + "Drill down into differing attribute %s:" % field, + ("%s%s: %r != %r") % (indent, field, field_left, field_right), + ] + explanation += [ + indent + line + for line in _compare_eq_any(field_left, field_right, verbose) + ] + return explanation + + +def _notin_text(term: str, text: str, verbose: int = 0) -> List[str]: + index = text.find(term) + head = text[:index] + tail = text[index + len(term) :] + correct_text = head + tail + diff = _diff_text(text, correct_text, verbose) + newdiff = ["%s is contained here:" % saferepr(term, maxsize=42)] + for line in diff: + if line.startswith("Skipping"): + continue + if line.startswith("- "): + continue + if line.startswith("+ "): + newdiff.append(" " + line[2:]) + else: + newdiff.append(line) + return newdiff + + +def running_on_ci() -> bool: + """Check if we're currently running on a CI system.""" + env_vars = ["CI", "BUILD_NUMBER"] + return any(var in os.environ for var in env_vars) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/cacheprovider.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/cacheprovider.py new file mode 100644 index 000000000..1ecb86505 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/cacheprovider.py @@ -0,0 +1,602 @@ +"""Implementation of the cache provider.""" +# This plugin was not named "cache" to avoid conflicts with the external +# pytest-cache version. +import dataclasses +import json +import os +from pathlib import Path +from typing import Dict +from typing import Generator +from typing import Iterable +from typing import List +from typing import Optional +from typing import Set +from typing import Union + +from .pathlib import resolve_from_str +from .pathlib import rm_rf +from .reports import CollectReport +from _pytest import nodes +from _pytest._io import TerminalWriter +from _pytest.compat import final +from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config import hookimpl +from _pytest.config.argparsing import Parser +from _pytest.deprecated import check_ispytest +from _pytest.fixtures import fixture +from _pytest.fixtures import FixtureRequest +from _pytest.main import Session +from _pytest.nodes import File +from _pytest.python import Package +from _pytest.reports import TestReport + +README_CONTENT = """\ +# pytest cache directory # + +This directory contains data from the pytest's cache plugin, +which provides the `--lf` and `--ff` options, as well as the `cache` fixture. + +**Do not** commit this to version control. + +See [the docs](https://docs.pytest.org/en/stable/how-to/cache.html) for more information. +""" + +CACHEDIR_TAG_CONTENT = b"""\ +Signature: 8a477f597d28d172789f06886806bc55 +# This file is a cache directory tag created by pytest. +# For information about cache directory tags, see: +# https://bford.info/cachedir/spec.html +""" + + +@final +@dataclasses.dataclass +class Cache: + """Instance of the `cache` fixture.""" + + _cachedir: Path = dataclasses.field(repr=False) + _config: Config = dataclasses.field(repr=False) + + # Sub-directory under cache-dir for directories created by `mkdir()`. + _CACHE_PREFIX_DIRS = "d" + + # Sub-directory under cache-dir for values created by `set()`. + _CACHE_PREFIX_VALUES = "v" + + def __init__( + self, cachedir: Path, config: Config, *, _ispytest: bool = False + ) -> None: + check_ispytest(_ispytest) + self._cachedir = cachedir + self._config = config + + @classmethod + def for_config(cls, config: Config, *, _ispytest: bool = False) -> "Cache": + """Create the Cache instance for a Config. + + :meta private: + """ + check_ispytest(_ispytest) + cachedir = cls.cache_dir_from_config(config, _ispytest=True) + if config.getoption("cacheclear") and cachedir.is_dir(): + cls.clear_cache(cachedir, _ispytest=True) + return cls(cachedir, config, _ispytest=True) + + @classmethod + def clear_cache(cls, cachedir: Path, _ispytest: bool = False) -> None: + """Clear the sub-directories used to hold cached directories and values. + + :meta private: + """ + check_ispytest(_ispytest) + for prefix in (cls._CACHE_PREFIX_DIRS, cls._CACHE_PREFIX_VALUES): + d = cachedir / prefix + if d.is_dir(): + rm_rf(d) + + @staticmethod + def cache_dir_from_config(config: Config, *, _ispytest: bool = False) -> Path: + """Get the path to the cache directory for a Config. + + :meta private: + """ + check_ispytest(_ispytest) + return resolve_from_str(config.getini("cache_dir"), config.rootpath) + + def warn(self, fmt: str, *, _ispytest: bool = False, **args: object) -> None: + """Issue a cache warning. + + :meta private: + """ + check_ispytest(_ispytest) + import warnings + from _pytest.warning_types import PytestCacheWarning + + warnings.warn( + PytestCacheWarning(fmt.format(**args) if args else fmt), + self._config.hook, + stacklevel=3, + ) + + def mkdir(self, name: str) -> Path: + """Return a directory path object with the given name. + + If the directory does not yet exist, it will be created. You can use + it to manage files to e.g. store/retrieve database dumps across test + sessions. + + .. versionadded:: 7.0 + + :param name: + Must be a string not containing a ``/`` separator. + Make sure the name contains your plugin or application + identifiers to prevent clashes with other cache users. + """ + path = Path(name) + if len(path.parts) > 1: + raise ValueError("name is not allowed to contain path separators") + res = self._cachedir.joinpath(self._CACHE_PREFIX_DIRS, path) + res.mkdir(exist_ok=True, parents=True) + return res + + def _getvaluepath(self, key: str) -> Path: + return self._cachedir.joinpath(self._CACHE_PREFIX_VALUES, Path(key)) + + def get(self, key: str, default): + """Return the cached value for the given key. + + If no value was yet cached or the value cannot be read, the specified + default is returned. + + :param key: + Must be a ``/`` separated value. Usually the first + name is the name of your plugin or your application. + :param default: + The value to return in case of a cache-miss or invalid cache value. + """ + path = self._getvaluepath(key) + try: + with path.open("r", encoding="UTF-8") as f: + return json.load(f) + except (ValueError, OSError): + return default + + def set(self, key: str, value: object) -> None: + """Save value for the given key. + + :param key: + Must be a ``/`` separated value. Usually the first + name is the name of your plugin or your application. + :param value: + Must be of any combination of basic python types, + including nested types like lists of dictionaries. + """ + path = self._getvaluepath(key) + try: + if path.parent.is_dir(): + cache_dir_exists_already = True + else: + cache_dir_exists_already = self._cachedir.exists() + path.parent.mkdir(exist_ok=True, parents=True) + except OSError as exc: + self.warn( + f"could not create cache path {path}: {exc}", + _ispytest=True, + ) + return + if not cache_dir_exists_already: + self._ensure_supporting_files() + data = json.dumps(value, ensure_ascii=False, indent=2) + try: + f = path.open("w", encoding="UTF-8") + except OSError as exc: + self.warn( + f"cache could not write path {path}: {exc}", + _ispytest=True, + ) + else: + with f: + f.write(data) + + def _ensure_supporting_files(self) -> None: + """Create supporting files in the cache dir that are not really part of the cache.""" + readme_path = self._cachedir / "README.md" + readme_path.write_text(README_CONTENT, encoding="UTF-8") + + gitignore_path = self._cachedir.joinpath(".gitignore") + msg = "# Created by pytest automatically.\n*\n" + gitignore_path.write_text(msg, encoding="UTF-8") + + cachedir_tag_path = self._cachedir.joinpath("CACHEDIR.TAG") + cachedir_tag_path.write_bytes(CACHEDIR_TAG_CONTENT) + + +class LFPluginCollWrapper: + def __init__(self, lfplugin: "LFPlugin") -> None: + self.lfplugin = lfplugin + self._collected_at_least_one_failure = False + + @hookimpl(hookwrapper=True) + def pytest_make_collect_report(self, collector: nodes.Collector): + if isinstance(collector, (Session, Package)): + out = yield + res: CollectReport = out.get_result() + + # Sort any lf-paths to the beginning. + lf_paths = self.lfplugin._last_failed_paths + + # Use stable sort to priorize last failed. + def sort_key(node: Union[nodes.Item, nodes.Collector]) -> bool: + # Package.path is the __init__.py file, we need the directory. + if isinstance(node, Package): + path = node.path.parent + else: + path = node.path + return path in lf_paths + + res.result = sorted( + res.result, + key=sort_key, + reverse=True, + ) + return + + elif isinstance(collector, File): + if collector.path in self.lfplugin._last_failed_paths: + out = yield + res = out.get_result() + result = res.result + lastfailed = self.lfplugin.lastfailed + + # Only filter with known failures. + if not self._collected_at_least_one_failure: + if not any(x.nodeid in lastfailed for x in result): + return + self.lfplugin.config.pluginmanager.register( + LFPluginCollSkipfiles(self.lfplugin), "lfplugin-collskip" + ) + self._collected_at_least_one_failure = True + + session = collector.session + result[:] = [ + x + for x in result + if x.nodeid in lastfailed + # Include any passed arguments (not trivial to filter). + or session.isinitpath(x.path) + # Keep all sub-collectors. + or isinstance(x, nodes.Collector) + ] + return + yield + + +class LFPluginCollSkipfiles: + def __init__(self, lfplugin: "LFPlugin") -> None: + self.lfplugin = lfplugin + + @hookimpl + def pytest_make_collect_report( + self, collector: nodes.Collector + ) -> Optional[CollectReport]: + # Packages are Files, but we only want to skip test-bearing Files, + # so don't filter Packages. + if isinstance(collector, File) and not isinstance(collector, Package): + if collector.path not in self.lfplugin._last_failed_paths: + self.lfplugin._skipped_files += 1 + + return CollectReport( + collector.nodeid, "passed", longrepr=None, result=[] + ) + return None + + +class LFPlugin: + """Plugin which implements the --lf (run last-failing) option.""" + + def __init__(self, config: Config) -> None: + self.config = config + active_keys = "lf", "failedfirst" + self.active = any(config.getoption(key) for key in active_keys) + assert config.cache + self.lastfailed: Dict[str, bool] = config.cache.get("cache/lastfailed", {}) + self._previously_failed_count: Optional[int] = None + self._report_status: Optional[str] = None + self._skipped_files = 0 # count skipped files during collection due to --lf + + if config.getoption("lf"): + self._last_failed_paths = self.get_last_failed_paths() + config.pluginmanager.register( + LFPluginCollWrapper(self), "lfplugin-collwrapper" + ) + + def get_last_failed_paths(self) -> Set[Path]: + """Return a set with all Paths of the previously failed nodeids and + their parents.""" + rootpath = self.config.rootpath + result = set() + for nodeid in self.lastfailed: + path = rootpath / nodeid.split("::")[0] + result.add(path) + result.update(path.parents) + return {x for x in result if x.exists()} + + def pytest_report_collectionfinish(self) -> Optional[str]: + if self.active and self.config.getoption("verbose") >= 0: + return "run-last-failure: %s" % self._report_status + return None + + def pytest_runtest_logreport(self, report: TestReport) -> None: + if (report.when == "call" and report.passed) or report.skipped: + self.lastfailed.pop(report.nodeid, None) + elif report.failed: + self.lastfailed[report.nodeid] = True + + def pytest_collectreport(self, report: CollectReport) -> None: + passed = report.outcome in ("passed", "skipped") + if passed: + if report.nodeid in self.lastfailed: + self.lastfailed.pop(report.nodeid) + self.lastfailed.update((item.nodeid, True) for item in report.result) + else: + self.lastfailed[report.nodeid] = True + + @hookimpl(hookwrapper=True, tryfirst=True) + def pytest_collection_modifyitems( + self, config: Config, items: List[nodes.Item] + ) -> Generator[None, None, None]: + yield + + if not self.active: + return + + if self.lastfailed: + previously_failed = [] + previously_passed = [] + for item in items: + if item.nodeid in self.lastfailed: + previously_failed.append(item) + else: + previously_passed.append(item) + self._previously_failed_count = len(previously_failed) + + if not previously_failed: + # Running a subset of all tests with recorded failures + # only outside of it. + self._report_status = "%d known failures not in selected tests" % ( + len(self.lastfailed), + ) + else: + if self.config.getoption("lf"): + items[:] = previously_failed + config.hook.pytest_deselected(items=previously_passed) + else: # --failedfirst + items[:] = previously_failed + previously_passed + + noun = "failure" if self._previously_failed_count == 1 else "failures" + suffix = " first" if self.config.getoption("failedfirst") else "" + self._report_status = "rerun previous {count} {noun}{suffix}".format( + count=self._previously_failed_count, suffix=suffix, noun=noun + ) + + if self._skipped_files > 0: + files_noun = "file" if self._skipped_files == 1 else "files" + self._report_status += " (skipped {files} {files_noun})".format( + files=self._skipped_files, files_noun=files_noun + ) + else: + self._report_status = "no previously failed tests, " + if self.config.getoption("last_failed_no_failures") == "none": + self._report_status += "deselecting all items." + config.hook.pytest_deselected(items=items[:]) + items[:] = [] + else: + self._report_status += "not deselecting items." + + def pytest_sessionfinish(self, session: Session) -> None: + config = self.config + if config.getoption("cacheshow") or hasattr(config, "workerinput"): + return + + assert config.cache is not None + saved_lastfailed = config.cache.get("cache/lastfailed", {}) + if saved_lastfailed != self.lastfailed: + config.cache.set("cache/lastfailed", self.lastfailed) + + +class NFPlugin: + """Plugin which implements the --nf (run new-first) option.""" + + def __init__(self, config: Config) -> None: + self.config = config + self.active = config.option.newfirst + assert config.cache is not None + self.cached_nodeids = set(config.cache.get("cache/nodeids", [])) + + @hookimpl(hookwrapper=True, tryfirst=True) + def pytest_collection_modifyitems( + self, items: List[nodes.Item] + ) -> Generator[None, None, None]: + yield + + if self.active: + new_items: Dict[str, nodes.Item] = {} + other_items: Dict[str, nodes.Item] = {} + for item in items: + if item.nodeid not in self.cached_nodeids: + new_items[item.nodeid] = item + else: + other_items[item.nodeid] = item + + items[:] = self._get_increasing_order( + new_items.values() + ) + self._get_increasing_order(other_items.values()) + self.cached_nodeids.update(new_items) + else: + self.cached_nodeids.update(item.nodeid for item in items) + + def _get_increasing_order(self, items: Iterable[nodes.Item]) -> List[nodes.Item]: + return sorted(items, key=lambda item: item.path.stat().st_mtime, reverse=True) # type: ignore[no-any-return] + + def pytest_sessionfinish(self) -> None: + config = self.config + if config.getoption("cacheshow") or hasattr(config, "workerinput"): + return + + if config.getoption("collectonly"): + return + + assert config.cache is not None + config.cache.set("cache/nodeids", sorted(self.cached_nodeids)) + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("general") + group.addoption( + "--lf", + "--last-failed", + action="store_true", + dest="lf", + help="Rerun only the tests that failed " + "at the last run (or all if none failed)", + ) + group.addoption( + "--ff", + "--failed-first", + action="store_true", + dest="failedfirst", + help="Run all tests, but run the last failures first. " + "This may re-order tests and thus lead to " + "repeated fixture setup/teardown.", + ) + group.addoption( + "--nf", + "--new-first", + action="store_true", + dest="newfirst", + help="Run tests from new files first, then the rest of the tests " + "sorted by file mtime", + ) + group.addoption( + "--cache-show", + action="append", + nargs="?", + dest="cacheshow", + help=( + "Show cache contents, don't perform collection or tests. " + "Optional argument: glob (default: '*')." + ), + ) + group.addoption( + "--cache-clear", + action="store_true", + dest="cacheclear", + help="Remove all cache contents at start of test run", + ) + cache_dir_default = ".pytest_cache" + if "TOX_ENV_DIR" in os.environ: + cache_dir_default = os.path.join(os.environ["TOX_ENV_DIR"], cache_dir_default) + parser.addini("cache_dir", default=cache_dir_default, help="Cache directory path") + group.addoption( + "--lfnf", + "--last-failed-no-failures", + action="store", + dest="last_failed_no_failures", + choices=("all", "none"), + default="all", + help="With ``--lf``, determines whether to execute tests when there " + "are no previously (known) failures or when no " + "cached ``lastfailed`` data was found. " + "``all`` (the default) runs the full test suite again. " + "``none`` just emits a message about no known failures and exits successfully.", + ) + + +def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]: + if config.option.cacheshow and not config.option.help: + from _pytest.main import wrap_session + + return wrap_session(config, cacheshow) + return None + + +@hookimpl(tryfirst=True) +def pytest_configure(config: Config) -> None: + config.cache = Cache.for_config(config, _ispytest=True) + config.pluginmanager.register(LFPlugin(config), "lfplugin") + config.pluginmanager.register(NFPlugin(config), "nfplugin") + + +@fixture +def cache(request: FixtureRequest) -> Cache: + """Return a cache object that can persist state between testing sessions. + + cache.get(key, default) + cache.set(key, value) + + Keys must be ``/`` separated strings, where the first part is usually the + name of your plugin or application to avoid clashes with other cache users. + + Values can be any object handled by the json stdlib module. + """ + assert request.config.cache is not None + return request.config.cache + + +def pytest_report_header(config: Config) -> Optional[str]: + """Display cachedir with --cache-show and if non-default.""" + if config.option.verbose > 0 or config.getini("cache_dir") != ".pytest_cache": + assert config.cache is not None + cachedir = config.cache._cachedir + # TODO: evaluate generating upward relative paths + # starting with .., ../.. if sensible + + try: + displaypath = cachedir.relative_to(config.rootpath) + except ValueError: + displaypath = cachedir + return f"cachedir: {displaypath}" + return None + + +def cacheshow(config: Config, session: Session) -> int: + from pprint import pformat + + assert config.cache is not None + + tw = TerminalWriter() + tw.line("cachedir: " + str(config.cache._cachedir)) + if not config.cache._cachedir.is_dir(): + tw.line("cache is empty") + return 0 + + glob = config.option.cacheshow[0] + if glob is None: + glob = "*" + + dummy = object() + basedir = config.cache._cachedir + vdir = basedir / Cache._CACHE_PREFIX_VALUES + tw.sep("-", "cache values for %r" % glob) + for valpath in sorted(x for x in vdir.rglob(glob) if x.is_file()): + key = str(valpath.relative_to(vdir)) + val = config.cache.get(key, dummy) + if val is dummy: + tw.line("%s contains unreadable content, will be ignored" % key) + else: + tw.line("%s contains:" % key) + for line in pformat(val).splitlines(): + tw.line(" " + line) + + ddir = basedir / Cache._CACHE_PREFIX_DIRS + if ddir.is_dir(): + contents = sorted(ddir.rglob(glob)) + tw.sep("-", "cache directories for %r" % glob) + for p in contents: + # if p.is_dir(): + # print("%s/" % p.relative_to(basedir)) + if p.is_file(): + key = str(p.relative_to(basedir)) + tw.line(f"{key} is a file of length {p.stat().st_size:d}") + return 0 diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/capture.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/capture.py new file mode 100644 index 000000000..a8ca0869f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/capture.py @@ -0,0 +1,1082 @@ +"""Per-test stdout/stderr capturing mechanism.""" +import abc +import collections +import contextlib +import io +import os +import sys +from io import UnsupportedOperation +from tempfile import TemporaryFile +from types import TracebackType +from typing import Any +from typing import AnyStr +from typing import BinaryIO +from typing import Generator +from typing import Generic +from typing import Iterable +from typing import Iterator +from typing import List +from typing import NamedTuple +from typing import Optional +from typing import TextIO +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import Union + +from _pytest.compat import final +from _pytest.config import Config +from _pytest.config import hookimpl +from _pytest.config.argparsing import Parser +from _pytest.deprecated import check_ispytest +from _pytest.fixtures import fixture +from _pytest.fixtures import SubRequest +from _pytest.nodes import Collector +from _pytest.nodes import File +from _pytest.nodes import Item + +if TYPE_CHECKING: + from typing_extensions import Final + from typing_extensions import Literal + + _CaptureMethod = Literal["fd", "sys", "no", "tee-sys"] + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("general") + group._addoption( + "--capture", + action="store", + default="fd", + metavar="method", + choices=["fd", "sys", "no", "tee-sys"], + help="Per-test capturing method: one of fd|sys|no|tee-sys", + ) + group._addoption( + "-s", + action="store_const", + const="no", + dest="capture", + help="Shortcut for --capture=no", + ) + + +def _colorama_workaround() -> None: + """Ensure colorama is imported so that it attaches to the correct stdio + handles on Windows. + + colorama uses the terminal on import time. So if something does the + first import of colorama while I/O capture is active, colorama will + fail in various ways. + """ + if sys.platform.startswith("win32"): + try: + import colorama # noqa: F401 + except ImportError: + pass + + +def _windowsconsoleio_workaround(stream: TextIO) -> None: + """Workaround for Windows Unicode console handling. + + Python 3.6 implemented Unicode console handling for Windows. This works + by reading/writing to the raw console handle using + ``{Read,Write}ConsoleW``. + + The problem is that we are going to ``dup2`` over the stdio file + descriptors when doing ``FDCapture`` and this will ``CloseHandle`` the + handles used by Python to write to the console. Though there is still some + weirdness and the console handle seems to only be closed randomly and not + on the first call to ``CloseHandle``, or maybe it gets reopened with the + same handle value when we suspend capturing. + + The workaround in this case will reopen stdio with a different fd which + also means a different handle by replicating the logic in + "Py_lifecycle.c:initstdio/create_stdio". + + :param stream: + In practice ``sys.stdout`` or ``sys.stderr``, but given + here as parameter for unittesting purposes. + + See https://github.com/pytest-dev/py/issues/103. + """ + if not sys.platform.startswith("win32") or hasattr(sys, "pypy_version_info"): + return + + # Bail out if ``stream`` doesn't seem like a proper ``io`` stream (#2666). + if not hasattr(stream, "buffer"): # type: ignore[unreachable] + return + + buffered = hasattr(stream.buffer, "raw") + raw_stdout = stream.buffer.raw if buffered else stream.buffer # type: ignore[attr-defined] + + if not isinstance(raw_stdout, io._WindowsConsoleIO): # type: ignore[attr-defined] + return + + def _reopen_stdio(f, mode): + if not buffered and mode[0] == "w": + buffering = 0 + else: + buffering = -1 + + return io.TextIOWrapper( + open(os.dup(f.fileno()), mode, buffering), + f.encoding, + f.errors, + f.newlines, + f.line_buffering, + ) + + sys.stdin = _reopen_stdio(sys.stdin, "rb") + sys.stdout = _reopen_stdio(sys.stdout, "wb") + sys.stderr = _reopen_stdio(sys.stderr, "wb") + + +@hookimpl(hookwrapper=True) +def pytest_load_initial_conftests(early_config: Config): + ns = early_config.known_args_namespace + if ns.capture == "fd": + _windowsconsoleio_workaround(sys.stdout) + _colorama_workaround() + pluginmanager = early_config.pluginmanager + capman = CaptureManager(ns.capture) + pluginmanager.register(capman, "capturemanager") + + # Make sure that capturemanager is properly reset at final shutdown. + early_config.add_cleanup(capman.stop_global_capturing) + + # Finally trigger conftest loading but while capturing (issue #93). + capman.start_global_capturing() + outcome = yield + capman.suspend_global_capture() + if outcome.excinfo is not None: + out, err = capman.read_global_capture() + sys.stdout.write(out) + sys.stderr.write(err) + + +# IO Helpers. + + +class EncodedFile(io.TextIOWrapper): + __slots__ = () + + @property + def name(self) -> str: + # Ensure that file.name is a string. Workaround for a Python bug + # fixed in >=3.7.4: https://bugs.python.org/issue36015 + return repr(self.buffer) + + @property + def mode(self) -> str: + # TextIOWrapper doesn't expose a mode, but at least some of our + # tests check it. + return self.buffer.mode.replace("b", "") + + +class CaptureIO(io.TextIOWrapper): + def __init__(self) -> None: + super().__init__(io.BytesIO(), encoding="UTF-8", newline="", write_through=True) + + def getvalue(self) -> str: + assert isinstance(self.buffer, io.BytesIO) + return self.buffer.getvalue().decode("UTF-8") + + +class TeeCaptureIO(CaptureIO): + def __init__(self, other: TextIO) -> None: + self._other = other + super().__init__() + + def write(self, s: str) -> int: + super().write(s) + return self._other.write(s) + + +class DontReadFromInput(TextIO): + @property + def encoding(self) -> str: + return sys.__stdin__.encoding + + def read(self, size: int = -1) -> str: + raise OSError( + "pytest: reading from stdin while output is captured! Consider using `-s`." + ) + + readline = read + + def __next__(self) -> str: + return self.readline() + + def readlines(self, hint: Optional[int] = -1) -> List[str]: + raise OSError( + "pytest: reading from stdin while output is captured! Consider using `-s`." + ) + + def __iter__(self) -> Iterator[str]: + return self + + def fileno(self) -> int: + raise UnsupportedOperation("redirected stdin is pseudofile, has no fileno()") + + def flush(self) -> None: + raise UnsupportedOperation("redirected stdin is pseudofile, has no flush()") + + def isatty(self) -> bool: + return False + + def close(self) -> None: + pass + + def readable(self) -> bool: + return False + + def seek(self, offset: int, whence: int = 0) -> int: + raise UnsupportedOperation("redirected stdin is pseudofile, has no seek(int)") + + def seekable(self) -> bool: + return False + + def tell(self) -> int: + raise UnsupportedOperation("redirected stdin is pseudofile, has no tell()") + + def truncate(self, size: Optional[int] = None) -> int: + raise UnsupportedOperation("cannot truncate stdin") + + def write(self, data: str) -> int: + raise UnsupportedOperation("cannot write to stdin") + + def writelines(self, lines: Iterable[str]) -> None: + raise UnsupportedOperation("Cannot write to stdin") + + def writable(self) -> bool: + return False + + def __enter__(self) -> "DontReadFromInput": + return self + + def __exit__( + self, + type: Optional[Type[BaseException]], + value: Optional[BaseException], + traceback: Optional[TracebackType], + ) -> None: + pass + + @property + def buffer(self) -> BinaryIO: + # The str/bytes doesn't actually matter in this type, so OK to fake. + return self # type: ignore[return-value] + + +# Capture classes. + + +class CaptureBase(abc.ABC, Generic[AnyStr]): + EMPTY_BUFFER: AnyStr + + @abc.abstractmethod + def __init__(self, fd: int) -> None: + raise NotImplementedError() + + @abc.abstractmethod + def start(self) -> None: + raise NotImplementedError() + + @abc.abstractmethod + def done(self) -> None: + raise NotImplementedError() + + @abc.abstractmethod + def suspend(self) -> None: + raise NotImplementedError() + + @abc.abstractmethod + def resume(self) -> None: + raise NotImplementedError() + + @abc.abstractmethod + def writeorg(self, data: AnyStr) -> None: + raise NotImplementedError() + + @abc.abstractmethod + def snap(self) -> AnyStr: + raise NotImplementedError() + + +patchsysdict = {0: "stdin", 1: "stdout", 2: "stderr"} + + +class NoCapture(CaptureBase[str]): + EMPTY_BUFFER = "" + + def __init__(self, fd: int) -> None: + pass + + def start(self) -> None: + pass + + def done(self) -> None: + pass + + def suspend(self) -> None: + pass + + def resume(self) -> None: + pass + + def snap(self) -> str: + return "" + + def writeorg(self, data: str) -> None: + pass + + +class SysCaptureBase(CaptureBase[AnyStr]): + def __init__( + self, fd: int, tmpfile: Optional[TextIO] = None, *, tee: bool = False + ) -> None: + name = patchsysdict[fd] + self._old: TextIO = getattr(sys, name) + self.name = name + if tmpfile is None: + if name == "stdin": + tmpfile = DontReadFromInput() + else: + tmpfile = CaptureIO() if not tee else TeeCaptureIO(self._old) + self.tmpfile = tmpfile + self._state = "initialized" + + def repr(self, class_name: str) -> str: + return "<{} {} _old={} _state={!r} tmpfile={!r}>".format( + class_name, + self.name, + hasattr(self, "_old") and repr(self._old) or "", + self._state, + self.tmpfile, + ) + + def __repr__(self) -> str: + return "<{} {} _old={} _state={!r} tmpfile={!r}>".format( + self.__class__.__name__, + self.name, + hasattr(self, "_old") and repr(self._old) or "", + self._state, + self.tmpfile, + ) + + def _assert_state(self, op: str, states: Tuple[str, ...]) -> None: + assert ( + self._state in states + ), "cannot {} in state {!r}: expected one of {}".format( + op, self._state, ", ".join(states) + ) + + def start(self) -> None: + self._assert_state("start", ("initialized",)) + setattr(sys, self.name, self.tmpfile) + self._state = "started" + + def done(self) -> None: + self._assert_state("done", ("initialized", "started", "suspended", "done")) + if self._state == "done": + return + setattr(sys, self.name, self._old) + del self._old + self.tmpfile.close() + self._state = "done" + + def suspend(self) -> None: + self._assert_state("suspend", ("started", "suspended")) + setattr(sys, self.name, self._old) + self._state = "suspended" + + def resume(self) -> None: + self._assert_state("resume", ("started", "suspended")) + if self._state == "started": + return + setattr(sys, self.name, self.tmpfile) + self._state = "started" + + +class SysCaptureBinary(SysCaptureBase[bytes]): + EMPTY_BUFFER = b"" + + def snap(self) -> bytes: + self._assert_state("snap", ("started", "suspended")) + self.tmpfile.seek(0) + res = self.tmpfile.buffer.read() + self.tmpfile.seek(0) + self.tmpfile.truncate() + return res + + def writeorg(self, data: bytes) -> None: + self._assert_state("writeorg", ("started", "suspended")) + self._old.flush() + self._old.buffer.write(data) + self._old.buffer.flush() + + +class SysCapture(SysCaptureBase[str]): + EMPTY_BUFFER = "" + + def snap(self) -> str: + self._assert_state("snap", ("started", "suspended")) + assert isinstance(self.tmpfile, CaptureIO) + res = self.tmpfile.getvalue() + self.tmpfile.seek(0) + self.tmpfile.truncate() + return res + + def writeorg(self, data: str) -> None: + self._assert_state("writeorg", ("started", "suspended")) + self._old.write(data) + self._old.flush() + + +class FDCaptureBase(CaptureBase[AnyStr]): + def __init__(self, targetfd: int) -> None: + self.targetfd = targetfd + + try: + os.fstat(targetfd) + except OSError: + # FD capturing is conceptually simple -- create a temporary file, + # redirect the FD to it, redirect back when done. But when the + # target FD is invalid it throws a wrench into this lovely scheme. + # + # Tests themselves shouldn't care if the FD is valid, FD capturing + # should work regardless of external circumstances. So falling back + # to just sys capturing is not a good option. + # + # Further complications are the need to support suspend() and the + # possibility of FD reuse (e.g. the tmpfile getting the very same + # target FD). The following approach is robust, I believe. + self.targetfd_invalid: Optional[int] = os.open(os.devnull, os.O_RDWR) + os.dup2(self.targetfd_invalid, targetfd) + else: + self.targetfd_invalid = None + self.targetfd_save = os.dup(targetfd) + + if targetfd == 0: + self.tmpfile = open(os.devnull, encoding="utf-8") + self.syscapture: CaptureBase[str] = SysCapture(targetfd) + else: + self.tmpfile = EncodedFile( + TemporaryFile(buffering=0), + encoding="utf-8", + errors="replace", + newline="", + write_through=True, + ) + if targetfd in patchsysdict: + self.syscapture = SysCapture(targetfd, self.tmpfile) + else: + self.syscapture = NoCapture(targetfd) + + self._state = "initialized" + + def __repr__(self) -> str: + return "<{} {} oldfd={} _state={!r} tmpfile={!r}>".format( + self.__class__.__name__, + self.targetfd, + self.targetfd_save, + self._state, + self.tmpfile, + ) + + def _assert_state(self, op: str, states: Tuple[str, ...]) -> None: + assert ( + self._state in states + ), "cannot {} in state {!r}: expected one of {}".format( + op, self._state, ", ".join(states) + ) + + def start(self) -> None: + """Start capturing on targetfd using memorized tmpfile.""" + self._assert_state("start", ("initialized",)) + os.dup2(self.tmpfile.fileno(), self.targetfd) + self.syscapture.start() + self._state = "started" + + def done(self) -> None: + """Stop capturing, restore streams, return original capture file, + seeked to position zero.""" + self._assert_state("done", ("initialized", "started", "suspended", "done")) + if self._state == "done": + return + os.dup2(self.targetfd_save, self.targetfd) + os.close(self.targetfd_save) + if self.targetfd_invalid is not None: + if self.targetfd_invalid != self.targetfd: + os.close(self.targetfd) + os.close(self.targetfd_invalid) + self.syscapture.done() + self.tmpfile.close() + self._state = "done" + + def suspend(self) -> None: + self._assert_state("suspend", ("started", "suspended")) + if self._state == "suspended": + return + self.syscapture.suspend() + os.dup2(self.targetfd_save, self.targetfd) + self._state = "suspended" + + def resume(self) -> None: + self._assert_state("resume", ("started", "suspended")) + if self._state == "started": + return + self.syscapture.resume() + os.dup2(self.tmpfile.fileno(), self.targetfd) + self._state = "started" + + +class FDCaptureBinary(FDCaptureBase[bytes]): + """Capture IO to/from a given OS-level file descriptor. + + snap() produces `bytes`. + """ + + EMPTY_BUFFER = b"" + + def snap(self) -> bytes: + self._assert_state("snap", ("started", "suspended")) + self.tmpfile.seek(0) + res = self.tmpfile.buffer.read() + self.tmpfile.seek(0) + self.tmpfile.truncate() + return res + + def writeorg(self, data: bytes) -> None: + """Write to original file descriptor.""" + self._assert_state("writeorg", ("started", "suspended")) + os.write(self.targetfd_save, data) + + +class FDCapture(FDCaptureBase[str]): + """Capture IO to/from a given OS-level file descriptor. + + snap() produces text. + """ + + EMPTY_BUFFER = "" + + def snap(self) -> str: + self._assert_state("snap", ("started", "suspended")) + self.tmpfile.seek(0) + res = self.tmpfile.read() + self.tmpfile.seek(0) + self.tmpfile.truncate() + return res + + def writeorg(self, data: str) -> None: + """Write to original file descriptor.""" + self._assert_state("writeorg", ("started", "suspended")) + # XXX use encoding of original stream + os.write(self.targetfd_save, data.encode("utf-8")) + + +# MultiCapture + + +# Generic NamedTuple only supported since Python 3.11. +if sys.version_info >= (3, 11) or TYPE_CHECKING: + + @final + class CaptureResult(NamedTuple, Generic[AnyStr]): + """The result of :method:`CaptureFixture.readouterr`.""" + + out: AnyStr + err: AnyStr + +else: + + class CaptureResult( + collections.namedtuple("CaptureResult", ["out", "err"]), Generic[AnyStr] + ): + """The result of :method:`CaptureFixture.readouterr`.""" + + __slots__ = () + + +class MultiCapture(Generic[AnyStr]): + _state = None + _in_suspended = False + + def __init__( + self, + in_: Optional[CaptureBase[AnyStr]], + out: Optional[CaptureBase[AnyStr]], + err: Optional[CaptureBase[AnyStr]], + ) -> None: + self.in_: Optional[CaptureBase[AnyStr]] = in_ + self.out: Optional[CaptureBase[AnyStr]] = out + self.err: Optional[CaptureBase[AnyStr]] = err + + def __repr__(self) -> str: + return "".format( + self.out, + self.err, + self.in_, + self._state, + self._in_suspended, + ) + + def start_capturing(self) -> None: + self._state = "started" + if self.in_: + self.in_.start() + if self.out: + self.out.start() + if self.err: + self.err.start() + + def pop_outerr_to_orig(self) -> Tuple[AnyStr, AnyStr]: + """Pop current snapshot out/err capture and flush to orig streams.""" + out, err = self.readouterr() + if out: + assert self.out is not None + self.out.writeorg(out) + if err: + assert self.err is not None + self.err.writeorg(err) + return out, err + + def suspend_capturing(self, in_: bool = False) -> None: + self._state = "suspended" + if self.out: + self.out.suspend() + if self.err: + self.err.suspend() + if in_ and self.in_: + self.in_.suspend() + self._in_suspended = True + + def resume_capturing(self) -> None: + self._state = "started" + if self.out: + self.out.resume() + if self.err: + self.err.resume() + if self._in_suspended: + assert self.in_ is not None + self.in_.resume() + self._in_suspended = False + + def stop_capturing(self) -> None: + """Stop capturing and reset capturing streams.""" + if self._state == "stopped": + raise ValueError("was already stopped") + self._state = "stopped" + if self.out: + self.out.done() + if self.err: + self.err.done() + if self.in_: + self.in_.done() + + def is_started(self) -> bool: + """Whether actively capturing -- not suspended or stopped.""" + return self._state == "started" + + def readouterr(self) -> CaptureResult[AnyStr]: + out = self.out.snap() if self.out else "" + err = self.err.snap() if self.err else "" + # TODO: This type error is real, need to fix. + return CaptureResult(out, err) # type: ignore[arg-type] + + +def _get_multicapture(method: "_CaptureMethod") -> MultiCapture[str]: + if method == "fd": + return MultiCapture(in_=FDCapture(0), out=FDCapture(1), err=FDCapture(2)) + elif method == "sys": + return MultiCapture(in_=SysCapture(0), out=SysCapture(1), err=SysCapture(2)) + elif method == "no": + return MultiCapture(in_=None, out=None, err=None) + elif method == "tee-sys": + return MultiCapture( + in_=None, out=SysCapture(1, tee=True), err=SysCapture(2, tee=True) + ) + raise ValueError(f"unknown capturing method: {method!r}") + + +# CaptureManager and CaptureFixture + + +class CaptureManager: + """The capture plugin. + + Manages that the appropriate capture method is enabled/disabled during + collection and each test phase (setup, call, teardown). After each of + those points, the captured output is obtained and attached to the + collection/runtest report. + + There are two levels of capture: + + * global: enabled by default and can be suppressed by the ``-s`` + option. This is always enabled/disabled during collection and each test + phase. + + * fixture: when a test function or one of its fixture depend on the + ``capsys`` or ``capfd`` fixtures. In this case special handling is + needed to ensure the fixtures take precedence over the global capture. + """ + + def __init__(self, method: "_CaptureMethod") -> None: + self._method: Final = method + self._global_capturing: Optional[MultiCapture[str]] = None + self._capture_fixture: Optional[CaptureFixture[Any]] = None + + def __repr__(self) -> str: + return "".format( + self._method, self._global_capturing, self._capture_fixture + ) + + def is_capturing(self) -> Union[str, bool]: + if self.is_globally_capturing(): + return "global" + if self._capture_fixture: + return "fixture %s" % self._capture_fixture.request.fixturename + return False + + # Global capturing control + + def is_globally_capturing(self) -> bool: + return self._method != "no" + + def start_global_capturing(self) -> None: + assert self._global_capturing is None + self._global_capturing = _get_multicapture(self._method) + self._global_capturing.start_capturing() + + def stop_global_capturing(self) -> None: + if self._global_capturing is not None: + self._global_capturing.pop_outerr_to_orig() + self._global_capturing.stop_capturing() + self._global_capturing = None + + def resume_global_capture(self) -> None: + # During teardown of the python process, and on rare occasions, capture + # attributes can be `None` while trying to resume global capture. + if self._global_capturing is not None: + self._global_capturing.resume_capturing() + + def suspend_global_capture(self, in_: bool = False) -> None: + if self._global_capturing is not None: + self._global_capturing.suspend_capturing(in_=in_) + + def suspend(self, in_: bool = False) -> None: + # Need to undo local capsys-et-al if it exists before disabling global capture. + self.suspend_fixture() + self.suspend_global_capture(in_) + + def resume(self) -> None: + self.resume_global_capture() + self.resume_fixture() + + def read_global_capture(self) -> CaptureResult[str]: + assert self._global_capturing is not None + return self._global_capturing.readouterr() + + # Fixture Control + + def set_fixture(self, capture_fixture: "CaptureFixture[Any]") -> None: + if self._capture_fixture: + current_fixture = self._capture_fixture.request.fixturename + requested_fixture = capture_fixture.request.fixturename + capture_fixture.request.raiseerror( + "cannot use {} and {} at the same time".format( + requested_fixture, current_fixture + ) + ) + self._capture_fixture = capture_fixture + + def unset_fixture(self) -> None: + self._capture_fixture = None + + def activate_fixture(self) -> None: + """If the current item is using ``capsys`` or ``capfd``, activate + them so they take precedence over the global capture.""" + if self._capture_fixture: + self._capture_fixture._start() + + def deactivate_fixture(self) -> None: + """Deactivate the ``capsys`` or ``capfd`` fixture of this item, if any.""" + if self._capture_fixture: + self._capture_fixture.close() + + def suspend_fixture(self) -> None: + if self._capture_fixture: + self._capture_fixture._suspend() + + def resume_fixture(self) -> None: + if self._capture_fixture: + self._capture_fixture._resume() + + # Helper context managers + + @contextlib.contextmanager + def global_and_fixture_disabled(self) -> Generator[None, None, None]: + """Context manager to temporarily disable global and current fixture capturing.""" + do_fixture = self._capture_fixture and self._capture_fixture._is_started() + if do_fixture: + self.suspend_fixture() + do_global = self._global_capturing and self._global_capturing.is_started() + if do_global: + self.suspend_global_capture() + try: + yield + finally: + if do_global: + self.resume_global_capture() + if do_fixture: + self.resume_fixture() + + @contextlib.contextmanager + def item_capture(self, when: str, item: Item) -> Generator[None, None, None]: + self.resume_global_capture() + self.activate_fixture() + try: + yield + finally: + self.deactivate_fixture() + self.suspend_global_capture(in_=False) + + out, err = self.read_global_capture() + item.add_report_section(when, "stdout", out) + item.add_report_section(when, "stderr", err) + + # Hooks + + @hookimpl(hookwrapper=True) + def pytest_make_collect_report(self, collector: Collector): + if isinstance(collector, File): + self.resume_global_capture() + outcome = yield + self.suspend_global_capture() + out, err = self.read_global_capture() + rep = outcome.get_result() + if out: + rep.sections.append(("Captured stdout", out)) + if err: + rep.sections.append(("Captured stderr", err)) + else: + yield + + @hookimpl(hookwrapper=True) + def pytest_runtest_setup(self, item: Item) -> Generator[None, None, None]: + with self.item_capture("setup", item): + yield + + @hookimpl(hookwrapper=True) + def pytest_runtest_call(self, item: Item) -> Generator[None, None, None]: + with self.item_capture("call", item): + yield + + @hookimpl(hookwrapper=True) + def pytest_runtest_teardown(self, item: Item) -> Generator[None, None, None]: + with self.item_capture("teardown", item): + yield + + @hookimpl(tryfirst=True) + def pytest_keyboard_interrupt(self) -> None: + self.stop_global_capturing() + + @hookimpl(tryfirst=True) + def pytest_internalerror(self) -> None: + self.stop_global_capturing() + + +class CaptureFixture(Generic[AnyStr]): + """Object returned by the :fixture:`capsys`, :fixture:`capsysbinary`, + :fixture:`capfd` and :fixture:`capfdbinary` fixtures.""" + + def __init__( + self, + captureclass: Type[CaptureBase[AnyStr]], + request: SubRequest, + *, + _ispytest: bool = False, + ) -> None: + check_ispytest(_ispytest) + self.captureclass: Type[CaptureBase[AnyStr]] = captureclass + self.request = request + self._capture: Optional[MultiCapture[AnyStr]] = None + self._captured_out: AnyStr = self.captureclass.EMPTY_BUFFER + self._captured_err: AnyStr = self.captureclass.EMPTY_BUFFER + + def _start(self) -> None: + if self._capture is None: + self._capture = MultiCapture( + in_=None, + out=self.captureclass(1), + err=self.captureclass(2), + ) + self._capture.start_capturing() + + def close(self) -> None: + if self._capture is not None: + out, err = self._capture.pop_outerr_to_orig() + self._captured_out += out + self._captured_err += err + self._capture.stop_capturing() + self._capture = None + + def readouterr(self) -> CaptureResult[AnyStr]: + """Read and return the captured output so far, resetting the internal + buffer. + + :returns: + The captured content as a namedtuple with ``out`` and ``err`` + string attributes. + """ + captured_out, captured_err = self._captured_out, self._captured_err + if self._capture is not None: + out, err = self._capture.readouterr() + captured_out += out + captured_err += err + self._captured_out = self.captureclass.EMPTY_BUFFER + self._captured_err = self.captureclass.EMPTY_BUFFER + return CaptureResult(captured_out, captured_err) + + def _suspend(self) -> None: + """Suspend this fixture's own capturing temporarily.""" + if self._capture is not None: + self._capture.suspend_capturing() + + def _resume(self) -> None: + """Resume this fixture's own capturing temporarily.""" + if self._capture is not None: + self._capture.resume_capturing() + + def _is_started(self) -> bool: + """Whether actively capturing -- not disabled or closed.""" + if self._capture is not None: + return self._capture.is_started() + return False + + @contextlib.contextmanager + def disabled(self) -> Generator[None, None, None]: + """Temporarily disable capturing while inside the ``with`` block.""" + capmanager: CaptureManager = self.request.config.pluginmanager.getplugin( + "capturemanager" + ) + with capmanager.global_and_fixture_disabled(): + yield + + +# The fixtures. + + +@fixture +def capsys(request: SubRequest) -> Generator[CaptureFixture[str], None, None]: + r"""Enable text capturing of writes to ``sys.stdout`` and ``sys.stderr``. + + The captured output is made available via ``capsys.readouterr()`` method + calls, which return a ``(out, err)`` namedtuple. + ``out`` and ``err`` will be ``text`` objects. + + Returns an instance of :class:`CaptureFixture[str] `. + + Example: + + .. code-block:: python + + def test_output(capsys): + print("hello") + captured = capsys.readouterr() + assert captured.out == "hello\n" + """ + capman: CaptureManager = request.config.pluginmanager.getplugin("capturemanager") + capture_fixture = CaptureFixture(SysCapture, request, _ispytest=True) + capman.set_fixture(capture_fixture) + capture_fixture._start() + yield capture_fixture + capture_fixture.close() + capman.unset_fixture() + + +@fixture +def capsysbinary(request: SubRequest) -> Generator[CaptureFixture[bytes], None, None]: + r"""Enable bytes capturing of writes to ``sys.stdout`` and ``sys.stderr``. + + The captured output is made available via ``capsysbinary.readouterr()`` + method calls, which return a ``(out, err)`` namedtuple. + ``out`` and ``err`` will be ``bytes`` objects. + + Returns an instance of :class:`CaptureFixture[bytes] `. + + Example: + + .. code-block:: python + + def test_output(capsysbinary): + print("hello") + captured = capsysbinary.readouterr() + assert captured.out == b"hello\n" + """ + capman: CaptureManager = request.config.pluginmanager.getplugin("capturemanager") + capture_fixture = CaptureFixture(SysCaptureBinary, request, _ispytest=True) + capman.set_fixture(capture_fixture) + capture_fixture._start() + yield capture_fixture + capture_fixture.close() + capman.unset_fixture() + + +@fixture +def capfd(request: SubRequest) -> Generator[CaptureFixture[str], None, None]: + r"""Enable text capturing of writes to file descriptors ``1`` and ``2``. + + The captured output is made available via ``capfd.readouterr()`` method + calls, which return a ``(out, err)`` namedtuple. + ``out`` and ``err`` will be ``text`` objects. + + Returns an instance of :class:`CaptureFixture[str] `. + + Example: + + .. code-block:: python + + def test_system_echo(capfd): + os.system('echo "hello"') + captured = capfd.readouterr() + assert captured.out == "hello\n" + """ + capman: CaptureManager = request.config.pluginmanager.getplugin("capturemanager") + capture_fixture = CaptureFixture(FDCapture, request, _ispytest=True) + capman.set_fixture(capture_fixture) + capture_fixture._start() + yield capture_fixture + capture_fixture.close() + capman.unset_fixture() + + +@fixture +def capfdbinary(request: SubRequest) -> Generator[CaptureFixture[bytes], None, None]: + r"""Enable bytes capturing of writes to file descriptors ``1`` and ``2``. + + The captured output is made available via ``capfd.readouterr()`` method + calls, which return a ``(out, err)`` namedtuple. + ``out`` and ``err`` will be ``byte`` objects. + + Returns an instance of :class:`CaptureFixture[bytes] `. + + Example: + + .. code-block:: python + + def test_system_echo(capfdbinary): + os.system('echo "hello"') + captured = capfdbinary.readouterr() + assert captured.out == b"hello\n" + + """ + capman: CaptureManager = request.config.pluginmanager.getplugin("capturemanager") + capture_fixture = CaptureFixture(FDCaptureBinary, request, _ispytest=True) + capman.set_fixture(capture_fixture) + capture_fixture._start() + yield capture_fixture + capture_fixture.close() + capman.unset_fixture() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/compat.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/compat.py new file mode 100644 index 000000000..1d0add736 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/compat.py @@ -0,0 +1,435 @@ +"""Python version compatibility code.""" +from __future__ import annotations + +import dataclasses +import enum +import functools +import inspect +import os +import sys +from inspect import Parameter +from inspect import signature +from pathlib import Path +from typing import Any +from typing import Callable +from typing import Generic +from typing import NoReturn +from typing import TYPE_CHECKING +from typing import TypeVar + +import py + +# fmt: off +# Workaround for https://github.com/sphinx-doc/sphinx/issues/10351. +# If `overload` is imported from `compat` instead of from `typing`, +# Sphinx doesn't recognize it as `overload` and the API docs for +# overloaded functions look good again. But type checkers handle +# it fine. +# fmt: on +if True: + from typing import overload as overload + +if TYPE_CHECKING: + from typing_extensions import Final + + +_T = TypeVar("_T") +_S = TypeVar("_S") + +#: constant to prepare valuing pylib path replacements/lazy proxies later on +# intended for removal in pytest 8.0 or 9.0 + +# fmt: off +# intentional space to create a fake difference for the verification +LEGACY_PATH = py.path. local +# fmt: on + + +def legacy_path(path: str | os.PathLike[str]) -> LEGACY_PATH: + """Internal wrapper to prepare lazy proxies for legacy_path instances""" + return LEGACY_PATH(path) + + +# fmt: off +# Singleton type for NOTSET, as described in: +# https://www.python.org/dev/peps/pep-0484/#support-for-singleton-types-in-unions +class NotSetType(enum.Enum): + token = 0 +NOTSET: Final = NotSetType.token # noqa: E305 +# fmt: on + +if sys.version_info >= (3, 8): + import importlib.metadata + + importlib_metadata = importlib.metadata +else: + import importlib_metadata as importlib_metadata # noqa: F401 + + +def _format_args(func: Callable[..., Any]) -> str: + return str(signature(func)) + + +def is_generator(func: object) -> bool: + genfunc = inspect.isgeneratorfunction(func) + return genfunc and not iscoroutinefunction(func) + + +def iscoroutinefunction(func: object) -> bool: + """Return True if func is a coroutine function (a function defined with async + def syntax, and doesn't contain yield), or a function decorated with + @asyncio.coroutine. + + Note: copied and modified from Python 3.5's builtin couroutines.py to avoid + importing asyncio directly, which in turns also initializes the "logging" + module as a side-effect (see issue #8). + """ + return inspect.iscoroutinefunction(func) or getattr(func, "_is_coroutine", False) + + +def is_async_function(func: object) -> bool: + """Return True if the given function seems to be an async function or + an async generator.""" + return iscoroutinefunction(func) or inspect.isasyncgenfunction(func) + + +def getlocation(function, curdir: str | None = None) -> str: + function = get_real_func(function) + fn = Path(inspect.getfile(function)) + lineno = function.__code__.co_firstlineno + if curdir is not None: + try: + relfn = fn.relative_to(curdir) + except ValueError: + pass + else: + return "%s:%d" % (relfn, lineno + 1) + return "%s:%d" % (fn, lineno + 1) + + +def num_mock_patch_args(function) -> int: + """Return number of arguments used up by mock arguments (if any).""" + patchings = getattr(function, "patchings", None) + if not patchings: + return 0 + + mock_sentinel = getattr(sys.modules.get("mock"), "DEFAULT", object()) + ut_mock_sentinel = getattr(sys.modules.get("unittest.mock"), "DEFAULT", object()) + + return len( + [ + p + for p in patchings + if not p.attribute_name + and (p.new is mock_sentinel or p.new is ut_mock_sentinel) + ] + ) + + +def getfuncargnames( + function: Callable[..., Any], + *, + name: str = "", + is_method: bool = False, + cls: type | None = None, +) -> tuple[str, ...]: + """Return the names of a function's mandatory arguments. + + Should return the names of all function arguments that: + * Aren't bound to an instance or type as in instance or class methods. + * Don't have default values. + * Aren't bound with functools.partial. + * Aren't replaced with mocks. + + The is_method and cls arguments indicate that the function should + be treated as a bound method even though it's not unless, only in + the case of cls, the function is a static method. + + The name parameter should be the original name in which the function was collected. + """ + # TODO(RonnyPfannschmidt): This function should be refactored when we + # revisit fixtures. The fixture mechanism should ask the node for + # the fixture names, and not try to obtain directly from the + # function object well after collection has occurred. + + # The parameters attribute of a Signature object contains an + # ordered mapping of parameter names to Parameter instances. This + # creates a tuple of the names of the parameters that don't have + # defaults. + try: + parameters = signature(function).parameters + except (ValueError, TypeError) as e: + from _pytest.outcomes import fail + + fail( + f"Could not determine arguments of {function!r}: {e}", + pytrace=False, + ) + + arg_names = tuple( + p.name + for p in parameters.values() + if ( + p.kind is Parameter.POSITIONAL_OR_KEYWORD + or p.kind is Parameter.KEYWORD_ONLY + ) + and p.default is Parameter.empty + ) + if not name: + name = function.__name__ + + # If this function should be treated as a bound method even though + # it's passed as an unbound method or function, remove the first + # parameter name. + if is_method or ( + # Not using `getattr` because we don't want to resolve the staticmethod. + # Not using `cls.__dict__` because we want to check the entire MRO. + cls + and not isinstance( + inspect.getattr_static(cls, name, default=None), staticmethod + ) + ): + arg_names = arg_names[1:] + # Remove any names that will be replaced with mocks. + if hasattr(function, "__wrapped__"): + arg_names = arg_names[num_mock_patch_args(function) :] + return arg_names + + +def get_default_arg_names(function: Callable[..., Any]) -> tuple[str, ...]: + # Note: this code intentionally mirrors the code at the beginning of + # getfuncargnames, to get the arguments which were excluded from its result + # because they had default values. + return tuple( + p.name + for p in signature(function).parameters.values() + if p.kind in (Parameter.POSITIONAL_OR_KEYWORD, Parameter.KEYWORD_ONLY) + and p.default is not Parameter.empty + ) + + +_non_printable_ascii_translate_table = { + i: f"\\x{i:02x}" for i in range(128) if i not in range(32, 127) +} +_non_printable_ascii_translate_table.update( + {ord("\t"): "\\t", ord("\r"): "\\r", ord("\n"): "\\n"} +) + + +def _translate_non_printable(s: str) -> str: + return s.translate(_non_printable_ascii_translate_table) + + +STRING_TYPES = bytes, str + + +def _bytes_to_ascii(val: bytes) -> str: + return val.decode("ascii", "backslashreplace") + + +def ascii_escaped(val: bytes | str) -> str: + r"""If val is pure ASCII, return it as an str, otherwise, escape + bytes objects into a sequence of escaped bytes: + + b'\xc3\xb4\xc5\xd6' -> r'\xc3\xb4\xc5\xd6' + + and escapes unicode objects into a sequence of escaped unicode + ids, e.g.: + + r'4\nV\U00043efa\x0eMXWB\x1e\u3028\u15fd\xcd\U0007d944' + + Note: + The obvious "v.decode('unicode-escape')" will return + valid UTF-8 unicode if it finds them in bytes, but we + want to return escaped bytes for any byte, even if they match + a UTF-8 string. + """ + if isinstance(val, bytes): + ret = _bytes_to_ascii(val) + else: + ret = val.encode("unicode_escape").decode("ascii") + return _translate_non_printable(ret) + + +@dataclasses.dataclass +class _PytestWrapper: + """Dummy wrapper around a function object for internal use only. + + Used to correctly unwrap the underlying function object when we are + creating fixtures, because we wrap the function object ourselves with a + decorator to issue warnings when the fixture function is called directly. + """ + + obj: Any + + +def get_real_func(obj): + """Get the real function object of the (possibly) wrapped object by + functools.wraps or functools.partial.""" + start_obj = obj + for i in range(100): + # __pytest_wrapped__ is set by @pytest.fixture when wrapping the fixture function + # to trigger a warning if it gets called directly instead of by pytest: we don't + # want to unwrap further than this otherwise we lose useful wrappings like @mock.patch (#3774) + new_obj = getattr(obj, "__pytest_wrapped__", None) + if isinstance(new_obj, _PytestWrapper): + obj = new_obj.obj + break + new_obj = getattr(obj, "__wrapped__", None) + if new_obj is None: + break + obj = new_obj + else: + from _pytest._io.saferepr import saferepr + + raise ValueError( + ("could not find real function of {start}\nstopped at {current}").format( + start=saferepr(start_obj), current=saferepr(obj) + ) + ) + if isinstance(obj, functools.partial): + obj = obj.func + return obj + + +def get_real_method(obj, holder): + """Attempt to obtain the real function object that might be wrapping + ``obj``, while at the same time returning a bound method to ``holder`` if + the original object was a bound method.""" + try: + is_method = hasattr(obj, "__func__") + obj = get_real_func(obj) + except Exception: # pragma: no cover + return obj + if is_method and hasattr(obj, "__get__") and callable(obj.__get__): + obj = obj.__get__(holder) + return obj + + +def getimfunc(func): + try: + return func.__func__ + except AttributeError: + return func + + +def safe_getattr(object: Any, name: str, default: Any) -> Any: + """Like getattr but return default upon any Exception or any OutcomeException. + + Attribute access can potentially fail for 'evil' Python objects. + See issue #214. + It catches OutcomeException because of #2490 (issue #580), new outcomes + are derived from BaseException instead of Exception (for more details + check #2707). + """ + from _pytest.outcomes import TEST_OUTCOME + + try: + return getattr(object, name, default) + except TEST_OUTCOME: + return default + + +def safe_isclass(obj: object) -> bool: + """Ignore any exception via isinstance on Python 3.""" + try: + return inspect.isclass(obj) + except Exception: + return False + + +if TYPE_CHECKING: + if sys.version_info >= (3, 8): + from typing import final as final + else: + from typing_extensions import final as final +elif sys.version_info >= (3, 8): + from typing import final as final +else: + + def final(f): + return f + + +if sys.version_info >= (3, 8): + from functools import cached_property as cached_property +else: + + class cached_property(Generic[_S, _T]): + __slots__ = ("func", "__doc__") + + def __init__(self, func: Callable[[_S], _T]) -> None: + self.func = func + self.__doc__ = func.__doc__ + + @overload + def __get__( + self, instance: None, owner: type[_S] | None = ... + ) -> cached_property[_S, _T]: + ... + + @overload + def __get__(self, instance: _S, owner: type[_S] | None = ...) -> _T: + ... + + def __get__(self, instance, owner=None): + if instance is None: + return self + value = instance.__dict__[self.func.__name__] = self.func(instance) + return value + + +def get_user_id() -> int | None: + """Return the current process's real user id or None if it could not be + determined. + + :return: The user id or None if it could not be determined. + """ + # mypy follows the version and platform checking expectation of PEP 484: + # https://mypy.readthedocs.io/en/stable/common_issues.html?highlight=platform#python-version-and-system-platform-checks + # Containment checks are too complex for mypy v1.5.0 and cause failure. + if sys.platform == "win32" or sys.platform == "emscripten": + # win32 does not have a getuid() function. + # Emscripten has a return 0 stub. + return None + else: + # On other platforms, a return value of -1 is assumed to indicate that + # the current process's real user id could not be determined. + ERROR = -1 + uid = os.getuid() + return uid if uid != ERROR else None + + +# Perform exhaustiveness checking. +# +# Consider this example: +# +# MyUnion = Union[int, str] +# +# def handle(x: MyUnion) -> int { +# if isinstance(x, int): +# return 1 +# elif isinstance(x, str): +# return 2 +# else: +# raise Exception('unreachable') +# +# Now suppose we add a new variant: +# +# MyUnion = Union[int, str, bytes] +# +# After doing this, we must remember ourselves to go and update the handle +# function to handle the new variant. +# +# With `assert_never` we can do better: +# +# // raise Exception('unreachable') +# return assert_never(x) +# +# Now, if we forget to handle the new variant, the type-checker will emit a +# compile-time error, instead of the runtime error we would have gotten +# previously. +# +# This also work for Enums (if you use `is` to compare) and Literals. +def assert_never(value: NoReturn) -> NoReturn: + assert False, f"Unhandled value: {value} ({type(value).__name__})" diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/config/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/config/__init__.py new file mode 100644 index 000000000..e3990d175 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/config/__init__.py @@ -0,0 +1,1816 @@ +"""Command line options, ini-file and conftest.py processing.""" +import argparse +import collections.abc +import copy +import dataclasses +import enum +import glob +import inspect +import os +import re +import shlex +import sys +import types +import warnings +from functools import lru_cache +from pathlib import Path +from textwrap import dedent +from types import FunctionType +from types import TracebackType +from typing import Any +from typing import Callable +from typing import cast +from typing import Dict +from typing import Generator +from typing import IO +from typing import Iterable +from typing import Iterator +from typing import List +from typing import Optional +from typing import Sequence +from typing import Set +from typing import TextIO +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import Union + +from pluggy import HookimplMarker +from pluggy import HookspecMarker +from pluggy import PluginManager + +import _pytest._code +import _pytest.deprecated +import _pytest.hookspec +from .exceptions import PrintHelp as PrintHelp +from .exceptions import UsageError as UsageError +from .findpaths import determine_setup +from _pytest._code import ExceptionInfo +from _pytest._code import filter_traceback +from _pytest._io import TerminalWriter +from _pytest.compat import final +from _pytest.compat import importlib_metadata # type: ignore[attr-defined] +from _pytest.outcomes import fail +from _pytest.outcomes import Skipped +from _pytest.pathlib import absolutepath +from _pytest.pathlib import bestrelpath +from _pytest.pathlib import import_path +from _pytest.pathlib import ImportMode +from _pytest.pathlib import resolve_package_path +from _pytest.pathlib import safe_exists +from _pytest.stash import Stash +from _pytest.warning_types import PytestConfigWarning +from _pytest.warning_types import warn_explicit_for + +if TYPE_CHECKING: + from _pytest._code.code import _TracebackStyle + from _pytest.terminal import TerminalReporter + from .argparsing import Argument + + +_PluggyPlugin = object +"""A type to represent plugin objects. + +Plugins can be any namespace, so we can't narrow it down much, but we use an +alias to make the intent clear. + +Ideally this type would be provided by pluggy itself. +""" + + +hookimpl = HookimplMarker("pytest") +hookspec = HookspecMarker("pytest") + + +@final +class ExitCode(enum.IntEnum): + """Encodes the valid exit codes by pytest. + + Currently users and plugins may supply other exit codes as well. + + .. versionadded:: 5.0 + """ + + #: Tests passed. + OK = 0 + #: Tests failed. + TESTS_FAILED = 1 + #: pytest was interrupted. + INTERRUPTED = 2 + #: An internal error got in the way. + INTERNAL_ERROR = 3 + #: pytest was misused. + USAGE_ERROR = 4 + #: pytest couldn't find tests. + NO_TESTS_COLLECTED = 5 + + +class ConftestImportFailure(Exception): + def __init__( + self, + path: Path, + excinfo: Tuple[Type[Exception], Exception, TracebackType], + ) -> None: + super().__init__(path, excinfo) + self.path = path + self.excinfo = excinfo + + def __str__(self) -> str: + return "{}: {} (from {})".format( + self.excinfo[0].__name__, self.excinfo[1], self.path + ) + + +def filter_traceback_for_conftest_import_failure( + entry: _pytest._code.TracebackEntry, +) -> bool: + """Filter tracebacks entries which point to pytest internals or importlib. + + Make a special case for importlib because we use it to import test modules and conftest files + in _pytest.pathlib.import_path. + """ + return filter_traceback(entry) and "importlib" not in str(entry.path).split(os.sep) + + +def main( + args: Optional[Union[List[str], "os.PathLike[str]"]] = None, + plugins: Optional[Sequence[Union[str, _PluggyPlugin]]] = None, +) -> Union[int, ExitCode]: + """Perform an in-process test run. + + :param args: + List of command line arguments. If `None` or not given, defaults to reading + arguments directly from the process command line (:data:`sys.argv`). + :param plugins: List of plugin objects to be auto-registered during initialization. + + :returns: An exit code. + """ + try: + try: + config = _prepareconfig(args, plugins) + except ConftestImportFailure as e: + exc_info = ExceptionInfo.from_exc_info(e.excinfo) + tw = TerminalWriter(sys.stderr) + tw.line(f"ImportError while loading conftest '{e.path}'.", red=True) + exc_info.traceback = exc_info.traceback.filter( + filter_traceback_for_conftest_import_failure + ) + exc_repr = ( + exc_info.getrepr(style="short", chain=False) + if exc_info.traceback + else exc_info.exconly() + ) + formatted_tb = str(exc_repr) + for line in formatted_tb.splitlines(): + tw.line(line.rstrip(), red=True) + return ExitCode.USAGE_ERROR + else: + try: + ret: Union[ExitCode, int] = config.hook.pytest_cmdline_main( + config=config + ) + try: + return ExitCode(ret) + except ValueError: + return ret + finally: + config._ensure_unconfigure() + except UsageError as e: + tw = TerminalWriter(sys.stderr) + for msg in e.args: + tw.line(f"ERROR: {msg}\n", red=True) + return ExitCode.USAGE_ERROR + + +def console_main() -> int: + """The CLI entry point of pytest. + + This function is not meant for programmable use; use `main()` instead. + """ + # https://docs.python.org/3/library/signal.html#note-on-sigpipe + try: + code = main() + sys.stdout.flush() + return code + except BrokenPipeError: + # Python flushes standard streams on exit; redirect remaining output + # to devnull to avoid another BrokenPipeError at shutdown + devnull = os.open(os.devnull, os.O_WRONLY) + os.dup2(devnull, sys.stdout.fileno()) + return 1 # Python exits with error code 1 on EPIPE + + +class cmdline: # compatibility namespace + main = staticmethod(main) + + +def filename_arg(path: str, optname: str) -> str: + """Argparse type validator for filename arguments. + + :path: Path of filename. + :optname: Name of the option. + """ + if os.path.isdir(path): + raise UsageError(f"{optname} must be a filename, given: {path}") + return path + + +def directory_arg(path: str, optname: str) -> str: + """Argparse type validator for directory arguments. + + :path: Path of directory. + :optname: Name of the option. + """ + if not os.path.isdir(path): + raise UsageError(f"{optname} must be a directory, given: {path}") + return path + + +# Plugins that cannot be disabled via "-p no:X" currently. +essential_plugins = ( + "mark", + "main", + "runner", + "fixtures", + "helpconfig", # Provides -p. +) + +default_plugins = essential_plugins + ( + "python", + "terminal", + "debugging", + "unittest", + "capture", + "skipping", + "legacypath", + "tmpdir", + "monkeypatch", + "recwarn", + "pastebin", + "nose", + "assertion", + "junitxml", + "doctest", + "cacheprovider", + "freeze_support", + "setuponly", + "setupplan", + "stepwise", + "warnings", + "logging", + "reports", + "python_path", + *(["unraisableexception", "threadexception"] if sys.version_info >= (3, 8) else []), + "faulthandler", +) + +builtin_plugins = set(default_plugins) +builtin_plugins.add("pytester") +builtin_plugins.add("pytester_assertions") + + +def get_config( + args: Optional[List[str]] = None, + plugins: Optional[Sequence[Union[str, _PluggyPlugin]]] = None, +) -> "Config": + # subsequent calls to main will create a fresh instance + pluginmanager = PytestPluginManager() + config = Config( + pluginmanager, + invocation_params=Config.InvocationParams( + args=args or (), + plugins=plugins, + dir=Path.cwd(), + ), + ) + + if args is not None: + # Handle any "-p no:plugin" args. + pluginmanager.consider_preparse(args, exclude_only=True) + + for spec in default_plugins: + pluginmanager.import_plugin(spec) + + return config + + +def get_plugin_manager() -> "PytestPluginManager": + """Obtain a new instance of the + :py:class:`pytest.PytestPluginManager`, with default plugins + already loaded. + + This function can be used by integration with other tools, like hooking + into pytest to run tests into an IDE. + """ + return get_config().pluginmanager + + +def _prepareconfig( + args: Optional[Union[List[str], "os.PathLike[str]"]] = None, + plugins: Optional[Sequence[Union[str, _PluggyPlugin]]] = None, +) -> "Config": + if args is None: + args = sys.argv[1:] + elif isinstance(args, os.PathLike): + args = [os.fspath(args)] + elif not isinstance(args, list): + msg = ( # type:ignore[unreachable] + "`args` parameter expected to be a list of strings, got: {!r} (type: {})" + ) + raise TypeError(msg.format(args, type(args))) + + config = get_config(args, plugins) + pluginmanager = config.pluginmanager + try: + if plugins: + for plugin in plugins: + if isinstance(plugin, str): + pluginmanager.consider_pluginarg(plugin) + else: + pluginmanager.register(plugin) + config = pluginmanager.hook.pytest_cmdline_parse( + pluginmanager=pluginmanager, args=args + ) + return config + except BaseException: + config._ensure_unconfigure() + raise + + +def _get_directory(path: Path) -> Path: + """Get the directory of a path - itself if already a directory.""" + if path.is_file(): + return path.parent + else: + return path + + +def _get_legacy_hook_marks( + method: Any, + hook_type: str, + opt_names: Tuple[str, ...], +) -> Dict[str, bool]: + if TYPE_CHECKING: + # abuse typeguard from importlib to avoid massive method type union thats lacking a alias + assert inspect.isroutine(method) + known_marks: set[str] = {m.name for m in getattr(method, "pytestmark", [])} + must_warn: list[str] = [] + opts: dict[str, bool] = {} + for opt_name in opt_names: + opt_attr = getattr(method, opt_name, AttributeError) + if opt_attr is not AttributeError: + must_warn.append(f"{opt_name}={opt_attr}") + opts[opt_name] = True + elif opt_name in known_marks: + must_warn.append(f"{opt_name}=True") + opts[opt_name] = True + else: + opts[opt_name] = False + if must_warn: + hook_opts = ", ".join(must_warn) + message = _pytest.deprecated.HOOK_LEGACY_MARKING.format( + type=hook_type, + fullname=method.__qualname__, + hook_opts=hook_opts, + ) + warn_explicit_for(cast(FunctionType, method), message) + return opts + + +@final +class PytestPluginManager(PluginManager): + """A :py:class:`pluggy.PluginManager ` with + additional pytest-specific functionality: + + * Loading plugins from the command line, ``PYTEST_PLUGINS`` env variable and + ``pytest_plugins`` global variables found in plugins being loaded. + * ``conftest.py`` loading during start-up. + """ + + def __init__(self) -> None: + import _pytest.assertion + + super().__init__("pytest") + + # -- State related to local conftest plugins. + # All loaded conftest modules. + self._conftest_plugins: Set[types.ModuleType] = set() + # All conftest modules applicable for a directory. + # This includes the directory's own conftest modules as well + # as those of its parent directories. + self._dirpath2confmods: Dict[Path, List[types.ModuleType]] = {} + # Cutoff directory above which conftests are no longer discovered. + self._confcutdir: Optional[Path] = None + # If set, conftest loading is skipped. + self._noconftest = False + + # _getconftestmodules()'s call to _get_directory() causes a stat + # storm when it's called potentially thousands of times in a test + # session (#9478), often with the same path, so cache it. + self._get_directory = lru_cache(256)(_get_directory) + + self._duplicatepaths: Set[Path] = set() + + # plugins that were explicitly skipped with pytest.skip + # list of (module name, skip reason) + # previously we would issue a warning when a plugin was skipped, but + # since we refactored warnings as first citizens of Config, they are + # just stored here to be used later. + self.skipped_plugins: List[Tuple[str, str]] = [] + + self.add_hookspecs(_pytest.hookspec) + self.register(self) + if os.environ.get("PYTEST_DEBUG"): + err: IO[str] = sys.stderr + encoding: str = getattr(err, "encoding", "utf8") + try: + err = open( + os.dup(err.fileno()), + mode=err.mode, + buffering=1, + encoding=encoding, + ) + except Exception: + pass + self.trace.root.setwriter(err.write) + self.enable_tracing() + + # Config._consider_importhook will set a real object if required. + self.rewrite_hook = _pytest.assertion.DummyRewriteHook() + # Used to know when we are importing conftests after the pytest_configure stage. + self._configured = False + + def parse_hookimpl_opts(self, plugin: _PluggyPlugin, name: str): + # pytest hooks are always prefixed with "pytest_", + # so we avoid accessing possibly non-readable attributes + # (see issue #1073). + if not name.startswith("pytest_"): + return None + # Ignore names which can not be hooks. + if name == "pytest_plugins": + return None + + opts = super().parse_hookimpl_opts(plugin, name) + if opts is not None: + return opts + + method = getattr(plugin, name) + # Consider only actual functions for hooks (#3775). + if not inspect.isroutine(method): + return None + # Collect unmarked hooks as long as they have the `pytest_' prefix. + return _get_legacy_hook_marks( # type: ignore[return-value] + method, "impl", ("tryfirst", "trylast", "optionalhook", "hookwrapper") + ) + + def parse_hookspec_opts(self, module_or_class, name: str): + opts = super().parse_hookspec_opts(module_or_class, name) + if opts is None: + method = getattr(module_or_class, name) + if name.startswith("pytest_"): + opts = _get_legacy_hook_marks( # type: ignore[assignment] + method, + "spec", + ("firstresult", "historic"), + ) + return opts + + def register( + self, plugin: _PluggyPlugin, name: Optional[str] = None + ) -> Optional[str]: + if name in _pytest.deprecated.DEPRECATED_EXTERNAL_PLUGINS: + warnings.warn( + PytestConfigWarning( + "{} plugin has been merged into the core, " + "please remove it from your requirements.".format( + name.replace("_", "-") + ) + ) + ) + return None + ret: Optional[str] = super().register(plugin, name) + if ret: + self.hook.pytest_plugin_registered.call_historic( + kwargs=dict(plugin=plugin, manager=self) + ) + + if isinstance(plugin, types.ModuleType): + self.consider_module(plugin) + return ret + + def getplugin(self, name: str): + # Support deprecated naming because plugins (xdist e.g.) use it. + plugin: Optional[_PluggyPlugin] = self.get_plugin(name) + return plugin + + def hasplugin(self, name: str) -> bool: + """Return whether a plugin with the given name is registered.""" + return bool(self.get_plugin(name)) + + def pytest_configure(self, config: "Config") -> None: + """:meta private:""" + # XXX now that the pluginmanager exposes hookimpl(tryfirst...) + # we should remove tryfirst/trylast as markers. + config.addinivalue_line( + "markers", + "tryfirst: mark a hook implementation function such that the " + "plugin machinery will try to call it first/as early as possible. " + "DEPRECATED, use @pytest.hookimpl(tryfirst=True) instead.", + ) + config.addinivalue_line( + "markers", + "trylast: mark a hook implementation function such that the " + "plugin machinery will try to call it last/as late as possible. " + "DEPRECATED, use @pytest.hookimpl(trylast=True) instead.", + ) + self._configured = True + + # + # Internal API for local conftest plugin handling. + # + def _set_initial_conftests( + self, + args: Sequence[Union[str, Path]], + pyargs: bool, + noconftest: bool, + rootpath: Path, + confcutdir: Optional[Path], + importmode: Union[ImportMode, str], + ) -> None: + """Load initial conftest files given a preparsed "namespace". + + As conftest files may add their own command line options which have + arguments ('--my-opt somepath') we might get some false positives. + All builtin and 3rd party plugins will have been loaded, however, so + common options will not confuse our logic here. + """ + current = Path.cwd() + self._confcutdir = absolutepath(current / confcutdir) if confcutdir else None + self._noconftest = noconftest + self._using_pyargs = pyargs + foundanchor = False + for intitial_path in args: + path = str(intitial_path) + # remove node-id syntax + i = path.find("::") + if i != -1: + path = path[:i] + anchor = absolutepath(current / path) + + # Ensure we do not break if what appears to be an anchor + # is in fact a very long option (#10169, #11394). + if safe_exists(anchor): + self._try_load_conftest(anchor, importmode, rootpath) + foundanchor = True + if not foundanchor: + self._try_load_conftest(current, importmode, rootpath) + + def _is_in_confcutdir(self, path: Path) -> bool: + """Whether a path is within the confcutdir. + + When false, should not load conftest. + """ + if self._confcutdir is None: + return True + return path not in self._confcutdir.parents + + def _try_load_conftest( + self, anchor: Path, importmode: Union[str, ImportMode], rootpath: Path + ) -> None: + self._getconftestmodules(anchor, importmode, rootpath) + # let's also consider test* subdirs + if anchor.is_dir(): + for x in anchor.glob("test*"): + if x.is_dir(): + self._getconftestmodules(x, importmode, rootpath) + + def _getconftestmodules( + self, path: Path, importmode: Union[str, ImportMode], rootpath: Path + ) -> Sequence[types.ModuleType]: + if self._noconftest: + return [] + + directory = self._get_directory(path) + + # Optimization: avoid repeated searches in the same directory. + # Assumes always called with same importmode and rootpath. + existing_clist = self._dirpath2confmods.get(directory) + if existing_clist is not None: + return existing_clist + + # XXX these days we may rather want to use config.rootpath + # and allow users to opt into looking into the rootdir parent + # directories instead of requiring to specify confcutdir. + clist = [] + for parent in reversed((directory, *directory.parents)): + if self._is_in_confcutdir(parent): + conftestpath = parent / "conftest.py" + if conftestpath.is_file(): + mod = self._importconftest(conftestpath, importmode, rootpath) + clist.append(mod) + self._dirpath2confmods[directory] = clist + return clist + + def _rget_with_confmod( + self, + name: str, + path: Path, + importmode: Union[str, ImportMode], + rootpath: Path, + ) -> Tuple[types.ModuleType, Any]: + modules = self._getconftestmodules(path, importmode, rootpath=rootpath) + for mod in reversed(modules): + try: + return mod, getattr(mod, name) + except AttributeError: + continue + raise KeyError(name) + + def _importconftest( + self, conftestpath: Path, importmode: Union[str, ImportMode], rootpath: Path + ) -> types.ModuleType: + existing = self.get_plugin(str(conftestpath)) + if existing is not None: + return cast(types.ModuleType, existing) + + pkgpath = resolve_package_path(conftestpath) + if pkgpath is None: + _ensure_removed_sysmodule(conftestpath.stem) + + try: + mod = import_path(conftestpath, mode=importmode, root=rootpath) + except Exception as e: + assert e.__traceback__ is not None + exc_info = (type(e), e, e.__traceback__) + raise ConftestImportFailure(conftestpath, exc_info) from e + + self._check_non_top_pytest_plugins(mod, conftestpath) + + self._conftest_plugins.add(mod) + dirpath = conftestpath.parent + if dirpath in self._dirpath2confmods: + for path, mods in self._dirpath2confmods.items(): + if dirpath in path.parents or path == dirpath: + assert mod not in mods + mods.append(mod) + self.trace(f"loading conftestmodule {mod!r}") + self.consider_conftest(mod) + return mod + + def _check_non_top_pytest_plugins( + self, + mod: types.ModuleType, + conftestpath: Path, + ) -> None: + if ( + hasattr(mod, "pytest_plugins") + and self._configured + and not self._using_pyargs + ): + msg = ( + "Defining 'pytest_plugins' in a non-top-level conftest is no longer supported:\n" + "It affects the entire test suite instead of just below the conftest as expected.\n" + " {}\n" + "Please move it to a top level conftest file at the rootdir:\n" + " {}\n" + "For more information, visit:\n" + " https://docs.pytest.org/en/stable/deprecations.html#pytest-plugins-in-non-top-level-conftest-files" + ) + fail(msg.format(conftestpath, self._confcutdir), pytrace=False) + + # + # API for bootstrapping plugin loading + # + # + + def consider_preparse( + self, args: Sequence[str], *, exclude_only: bool = False + ) -> None: + """:meta private:""" + i = 0 + n = len(args) + while i < n: + opt = args[i] + i += 1 + if isinstance(opt, str): + if opt == "-p": + try: + parg = args[i] + except IndexError: + return + i += 1 + elif opt.startswith("-p"): + parg = opt[2:] + else: + continue + parg = parg.strip() + if exclude_only and not parg.startswith("no:"): + continue + self.consider_pluginarg(parg) + + def consider_pluginarg(self, arg: str) -> None: + """:meta private:""" + if arg.startswith("no:"): + name = arg[3:] + if name in essential_plugins: + raise UsageError("plugin %s cannot be disabled" % name) + + # PR #4304: remove stepwise if cacheprovider is blocked. + if name == "cacheprovider": + self.set_blocked("stepwise") + self.set_blocked("pytest_stepwise") + + self.set_blocked(name) + if not name.startswith("pytest_"): + self.set_blocked("pytest_" + name) + else: + name = arg + # Unblock the plugin. None indicates that it has been blocked. + # There is no interface with pluggy for this. + if self._name2plugin.get(name, -1) is None: + del self._name2plugin[name] + if not name.startswith("pytest_"): + if self._name2plugin.get("pytest_" + name, -1) is None: + del self._name2plugin["pytest_" + name] + self.import_plugin(arg, consider_entry_points=True) + + def consider_conftest(self, conftestmodule: types.ModuleType) -> None: + """:meta private:""" + self.register(conftestmodule, name=conftestmodule.__file__) + + def consider_env(self) -> None: + """:meta private:""" + self._import_plugin_specs(os.environ.get("PYTEST_PLUGINS")) + + def consider_module(self, mod: types.ModuleType) -> None: + """:meta private:""" + self._import_plugin_specs(getattr(mod, "pytest_plugins", [])) + + def _import_plugin_specs( + self, spec: Union[None, types.ModuleType, str, Sequence[str]] + ) -> None: + plugins = _get_plugin_specs_as_list(spec) + for import_spec in plugins: + self.import_plugin(import_spec) + + def import_plugin(self, modname: str, consider_entry_points: bool = False) -> None: + """Import a plugin with ``modname``. + + If ``consider_entry_points`` is True, entry point names are also + considered to find a plugin. + """ + # Most often modname refers to builtin modules, e.g. "pytester", + # "terminal" or "capture". Those plugins are registered under their + # basename for historic purposes but must be imported with the + # _pytest prefix. + assert isinstance(modname, str), ( + "module name as text required, got %r" % modname + ) + if self.is_blocked(modname) or self.get_plugin(modname) is not None: + return + + importspec = "_pytest." + modname if modname in builtin_plugins else modname + self.rewrite_hook.mark_rewrite(importspec) + + if consider_entry_points: + loaded = self.load_setuptools_entrypoints("pytest11", name=modname) + if loaded: + return + + try: + __import__(importspec) + except ImportError as e: + raise ImportError( + f'Error importing plugin "{modname}": {e.args[0]}' + ).with_traceback(e.__traceback__) from e + + except Skipped as e: + self.skipped_plugins.append((modname, e.msg or "")) + else: + mod = sys.modules[importspec] + self.register(mod, modname) + + +def _get_plugin_specs_as_list( + specs: Union[None, types.ModuleType, str, Sequence[str]] +) -> List[str]: + """Parse a plugins specification into a list of plugin names.""" + # None means empty. + if specs is None: + return [] + # Workaround for #3899 - a submodule which happens to be called "pytest_plugins". + if isinstance(specs, types.ModuleType): + return [] + # Comma-separated list. + if isinstance(specs, str): + return specs.split(",") if specs else [] + # Direct specification. + if isinstance(specs, collections.abc.Sequence): + return list(specs) + raise UsageError( + "Plugins may be specified as a sequence or a ','-separated string of plugin names. Got: %r" + % specs + ) + + +def _ensure_removed_sysmodule(modname: str) -> None: + try: + del sys.modules[modname] + except KeyError: + pass + + +class Notset: + def __repr__(self): + return "" + + +notset = Notset() + + +def _iter_rewritable_modules(package_files: Iterable[str]) -> Iterator[str]: + """Given an iterable of file names in a source distribution, return the "names" that should + be marked for assertion rewrite. + + For example the package "pytest_mock/__init__.py" should be added as "pytest_mock" in + the assertion rewrite mechanism. + + This function has to deal with dist-info based distributions and egg based distributions + (which are still very much in use for "editable" installs). + + Here are the file names as seen in a dist-info based distribution: + + pytest_mock/__init__.py + pytest_mock/_version.py + pytest_mock/plugin.py + pytest_mock.egg-info/PKG-INFO + + Here are the file names as seen in an egg based distribution: + + src/pytest_mock/__init__.py + src/pytest_mock/_version.py + src/pytest_mock/plugin.py + src/pytest_mock.egg-info/PKG-INFO + LICENSE + setup.py + + We have to take in account those two distribution flavors in order to determine which + names should be considered for assertion rewriting. + + More information: + https://github.com/pytest-dev/pytest-mock/issues/167 + """ + package_files = list(package_files) + seen_some = False + for fn in package_files: + is_simple_module = "/" not in fn and fn.endswith(".py") + is_package = fn.count("/") == 1 and fn.endswith("__init__.py") + if is_simple_module: + module_name, _ = os.path.splitext(fn) + # we ignore "setup.py" at the root of the distribution + # as well as editable installation finder modules made by setuptools + if module_name != "setup" and not module_name.startswith("__editable__"): + seen_some = True + yield module_name + elif is_package: + package_name = os.path.dirname(fn) + seen_some = True + yield package_name + + if not seen_some: + # At this point we did not find any packages or modules suitable for assertion + # rewriting, so we try again by stripping the first path component (to account for + # "src" based source trees for example). + # This approach lets us have the common case continue to be fast, as egg-distributions + # are rarer. + new_package_files = [] + for fn in package_files: + parts = fn.split("/") + new_fn = "/".join(parts[1:]) + if new_fn: + new_package_files.append(new_fn) + if new_package_files: + yield from _iter_rewritable_modules(new_package_files) + + +@final +class Config: + """Access to configuration values, pluginmanager and plugin hooks. + + :param PytestPluginManager pluginmanager: + A pytest PluginManager. + + :param InvocationParams invocation_params: + Object containing parameters regarding the :func:`pytest.main` + invocation. + """ + + @final + @dataclasses.dataclass(frozen=True) + class InvocationParams: + """Holds parameters passed during :func:`pytest.main`. + + The object attributes are read-only. + + .. versionadded:: 5.1 + + .. note:: + + Note that the environment variable ``PYTEST_ADDOPTS`` and the ``addopts`` + ini option are handled by pytest, not being included in the ``args`` attribute. + + Plugins accessing ``InvocationParams`` must be aware of that. + """ + + args: Tuple[str, ...] + """The command-line arguments as passed to :func:`pytest.main`.""" + plugins: Optional[Sequence[Union[str, _PluggyPlugin]]] + """Extra plugins, might be `None`.""" + dir: Path + """The directory from which :func:`pytest.main` was invoked.""" + + def __init__( + self, + *, + args: Iterable[str], + plugins: Optional[Sequence[Union[str, _PluggyPlugin]]], + dir: Path, + ) -> None: + object.__setattr__(self, "args", tuple(args)) + object.__setattr__(self, "plugins", plugins) + object.__setattr__(self, "dir", dir) + + class ArgsSource(enum.Enum): + """Indicates the source of the test arguments. + + .. versionadded:: 7.2 + """ + + #: Command line arguments. + ARGS = enum.auto() + #: Invocation directory. + INCOVATION_DIR = enum.auto() + #: 'testpaths' configuration value. + TESTPATHS = enum.auto() + + def __init__( + self, + pluginmanager: PytestPluginManager, + *, + invocation_params: Optional[InvocationParams] = None, + ) -> None: + from .argparsing import Parser, FILE_OR_DIR + + if invocation_params is None: + invocation_params = self.InvocationParams( + args=(), plugins=None, dir=Path.cwd() + ) + + self.option = argparse.Namespace() + """Access to command line option as attributes. + + :type: argparse.Namespace + """ + + self.invocation_params = invocation_params + """The parameters with which pytest was invoked. + + :type: InvocationParams + """ + + _a = FILE_OR_DIR + self._parser = Parser( + usage=f"%(prog)s [options] [{_a}] [{_a}] [...]", + processopt=self._processopt, + _ispytest=True, + ) + self.pluginmanager = pluginmanager + """The plugin manager handles plugin registration and hook invocation. + + :type: PytestPluginManager + """ + + self.stash = Stash() + """A place where plugins can store information on the config for their + own use. + + :type: Stash + """ + # Deprecated alias. Was never public. Can be removed in a few releases. + self._store = self.stash + + from .compat import PathAwareHookProxy + + self.trace = self.pluginmanager.trace.root.get("config") + self.hook = PathAwareHookProxy(self.pluginmanager.hook) + self._inicache: Dict[str, Any] = {} + self._override_ini: Sequence[str] = () + self._opt2dest: Dict[str, str] = {} + self._cleanup: List[Callable[[], None]] = [] + self.pluginmanager.register(self, "pytestconfig") + self._configured = False + self.hook.pytest_addoption.call_historic( + kwargs=dict(parser=self._parser, pluginmanager=self.pluginmanager) + ) + self.args_source = Config.ArgsSource.ARGS + self.args: List[str] = [] + + if TYPE_CHECKING: + from _pytest.cacheprovider import Cache + + self.cache: Optional[Cache] = None + + @property + def rootpath(self) -> Path: + """The path to the :ref:`rootdir `. + + :type: pathlib.Path + + .. versionadded:: 6.1 + """ + return self._rootpath + + @property + def inipath(self) -> Optional[Path]: + """The path to the :ref:`configfile `. + + :type: Optional[pathlib.Path] + + .. versionadded:: 6.1 + """ + return self._inipath + + def add_cleanup(self, func: Callable[[], None]) -> None: + """Add a function to be called when the config object gets out of + use (usually coinciding with pytest_unconfigure).""" + self._cleanup.append(func) + + def _do_configure(self) -> None: + assert not self._configured + self._configured = True + with warnings.catch_warnings(): + warnings.simplefilter("default") + self.hook.pytest_configure.call_historic(kwargs=dict(config=self)) + + def _ensure_unconfigure(self) -> None: + if self._configured: + self._configured = False + self.hook.pytest_unconfigure(config=self) + self.hook.pytest_configure._call_history = [] + while self._cleanup: + fin = self._cleanup.pop() + fin() + + def get_terminal_writer(self) -> TerminalWriter: + terminalreporter: Optional[TerminalReporter] = self.pluginmanager.get_plugin( + "terminalreporter" + ) + assert terminalreporter is not None + return terminalreporter._tw + + def pytest_cmdline_parse( + self, pluginmanager: PytestPluginManager, args: List[str] + ) -> "Config": + try: + self.parse(args) + except UsageError: + # Handle --version and --help here in a minimal fashion. + # This gets done via helpconfig normally, but its + # pytest_cmdline_main is not called in case of errors. + if getattr(self.option, "version", False) or "--version" in args: + from _pytest.helpconfig import showversion + + showversion(self) + elif ( + getattr(self.option, "help", False) or "--help" in args or "-h" in args + ): + self._parser._getparser().print_help() + sys.stdout.write( + "\nNOTE: displaying only minimal help due to UsageError.\n\n" + ) + + raise + + return self + + def notify_exception( + self, + excinfo: ExceptionInfo[BaseException], + option: Optional[argparse.Namespace] = None, + ) -> None: + if option and getattr(option, "fulltrace", False): + style: _TracebackStyle = "long" + else: + style = "native" + excrepr = excinfo.getrepr( + funcargs=True, showlocals=getattr(option, "showlocals", False), style=style + ) + res = self.hook.pytest_internalerror(excrepr=excrepr, excinfo=excinfo) + if not any(res): + for line in str(excrepr).split("\n"): + sys.stderr.write("INTERNALERROR> %s\n" % line) + sys.stderr.flush() + + def cwd_relative_nodeid(self, nodeid: str) -> str: + # nodeid's are relative to the rootpath, compute relative to cwd. + if self.invocation_params.dir != self.rootpath: + fullpath = self.rootpath / nodeid + nodeid = bestrelpath(self.invocation_params.dir, fullpath) + return nodeid + + @classmethod + def fromdictargs(cls, option_dict, args) -> "Config": + """Constructor usable for subprocesses.""" + config = get_config(args) + config.option.__dict__.update(option_dict) + config.parse(args, addopts=False) + for x in config.option.plugins: + config.pluginmanager.consider_pluginarg(x) + return config + + def _processopt(self, opt: "Argument") -> None: + for name in opt._short_opts + opt._long_opts: + self._opt2dest[name] = opt.dest + + if hasattr(opt, "default"): + if not hasattr(self.option, opt.dest): + setattr(self.option, opt.dest, opt.default) + + @hookimpl(trylast=True) + def pytest_load_initial_conftests(self, early_config: "Config") -> None: + # We haven't fully parsed the command line arguments yet, so + # early_config.args it not set yet. But we need it for + # discovering the initial conftests. So "pre-run" the logic here. + # It will be done for real in `parse()`. + args, args_source = early_config._decide_args( + args=early_config.known_args_namespace.file_or_dir, + pyargs=early_config.known_args_namespace.pyargs, + testpaths=early_config.getini("testpaths"), + invocation_dir=early_config.invocation_params.dir, + rootpath=early_config.rootpath, + warn=False, + ) + self.pluginmanager._set_initial_conftests( + args=args, + pyargs=early_config.known_args_namespace.pyargs, + noconftest=early_config.known_args_namespace.noconftest, + rootpath=early_config.rootpath, + confcutdir=early_config.known_args_namespace.confcutdir, + importmode=early_config.known_args_namespace.importmode, + ) + + def _initini(self, args: Sequence[str]) -> None: + ns, unknown_args = self._parser.parse_known_and_unknown_args( + args, namespace=copy.copy(self.option) + ) + rootpath, inipath, inicfg = determine_setup( + ns.inifilename, + ns.file_or_dir + unknown_args, + rootdir_cmd_arg=ns.rootdir or None, + config=self, + ) + self._rootpath = rootpath + self._inipath = inipath + self.inicfg = inicfg + self._parser.extra_info["rootdir"] = str(self.rootpath) + self._parser.extra_info["inifile"] = str(self.inipath) + self._parser.addini("addopts", "Extra command line options", "args") + self._parser.addini("minversion", "Minimally required pytest version") + self._parser.addini( + "required_plugins", + "Plugins that must be present for pytest to run", + type="args", + default=[], + ) + self._override_ini = ns.override_ini or () + + def _consider_importhook(self, args: Sequence[str]) -> None: + """Install the PEP 302 import hook if using assertion rewriting. + + Needs to parse the --assert= option from the commandline + and find all the installed plugins to mark them for rewriting + by the importhook. + """ + ns, unknown_args = self._parser.parse_known_and_unknown_args(args) + mode = getattr(ns, "assertmode", "plain") + if mode == "rewrite": + import _pytest.assertion + + try: + hook = _pytest.assertion.install_importhook(self) + except SystemError: + mode = "plain" + else: + self._mark_plugins_for_rewrite(hook) + self._warn_about_missing_assertion(mode) + + def _mark_plugins_for_rewrite(self, hook) -> None: + """Given an importhook, mark for rewrite any top-level + modules or packages in the distribution package for + all pytest plugins.""" + self.pluginmanager.rewrite_hook = hook + + if os.environ.get("PYTEST_DISABLE_PLUGIN_AUTOLOAD"): + # We don't autoload from setuptools entry points, no need to continue. + return + + package_files = ( + str(file) + for dist in importlib_metadata.distributions() + if any(ep.group == "pytest11" for ep in dist.entry_points) + for file in dist.files or [] + ) + + for name in _iter_rewritable_modules(package_files): + hook.mark_rewrite(name) + + def _validate_args(self, args: List[str], via: str) -> List[str]: + """Validate known args.""" + self._parser._config_source_hint = via # type: ignore + try: + self._parser.parse_known_and_unknown_args( + args, namespace=copy.copy(self.option) + ) + finally: + del self._parser._config_source_hint # type: ignore + + return args + + def _decide_args( + self, + *, + args: List[str], + pyargs: List[str], + testpaths: List[str], + invocation_dir: Path, + rootpath: Path, + warn: bool, + ) -> Tuple[List[str], ArgsSource]: + """Decide the args (initial paths/nodeids) to use given the relevant inputs. + + :param warn: Whether can issue warnings. + """ + if args: + source = Config.ArgsSource.ARGS + result = args + else: + if invocation_dir == rootpath: + source = Config.ArgsSource.TESTPATHS + if pyargs: + result = testpaths + else: + result = [] + for path in testpaths: + result.extend(sorted(glob.iglob(path, recursive=True))) + if testpaths and not result: + if warn: + warning_text = ( + "No files were found in testpaths; " + "consider removing or adjusting your testpaths configuration. " + "Searching recursively from the current directory instead." + ) + self.issue_config_time_warning( + PytestConfigWarning(warning_text), stacklevel=3 + ) + else: + result = [] + if not result: + source = Config.ArgsSource.INCOVATION_DIR + result = [str(invocation_dir)] + return result, source + + def _preparse(self, args: List[str], addopts: bool = True) -> None: + if addopts: + env_addopts = os.environ.get("PYTEST_ADDOPTS", "") + if len(env_addopts): + args[:] = ( + self._validate_args(shlex.split(env_addopts), "via PYTEST_ADDOPTS") + + args + ) + self._initini(args) + if addopts: + args[:] = ( + self._validate_args(self.getini("addopts"), "via addopts config") + args + ) + + self.known_args_namespace = self._parser.parse_known_args( + args, namespace=copy.copy(self.option) + ) + self._checkversion() + self._consider_importhook(args) + self.pluginmanager.consider_preparse(args, exclude_only=False) + if not os.environ.get("PYTEST_DISABLE_PLUGIN_AUTOLOAD"): + # Don't autoload from setuptools entry point. Only explicitly specified + # plugins are going to be loaded. + self.pluginmanager.load_setuptools_entrypoints("pytest11") + self.pluginmanager.consider_env() + + self.known_args_namespace = self._parser.parse_known_args( + args, namespace=copy.copy(self.known_args_namespace) + ) + + self._validate_plugins() + self._warn_about_skipped_plugins() + + if self.known_args_namespace.strict: + self.issue_config_time_warning( + _pytest.deprecated.STRICT_OPTION, stacklevel=2 + ) + + if self.known_args_namespace.confcutdir is None: + if self.inipath is not None: + confcutdir = str(self.inipath.parent) + else: + confcutdir = str(self.rootpath) + self.known_args_namespace.confcutdir = confcutdir + try: + self.hook.pytest_load_initial_conftests( + early_config=self, args=args, parser=self._parser + ) + except ConftestImportFailure as e: + if self.known_args_namespace.help or self.known_args_namespace.version: + # we don't want to prevent --help/--version to work + # so just let is pass and print a warning at the end + self.issue_config_time_warning( + PytestConfigWarning(f"could not load initial conftests: {e.path}"), + stacklevel=2, + ) + else: + raise + + @hookimpl(hookwrapper=True) + def pytest_collection(self) -> Generator[None, None, None]: + # Validate invalid ini keys after collection is done so we take in account + # options added by late-loading conftest files. + yield + self._validate_config_options() + + def _checkversion(self) -> None: + import pytest + + minver = self.inicfg.get("minversion", None) + if minver: + # Imported lazily to improve start-up time. + from packaging.version import Version + + if not isinstance(minver, str): + raise pytest.UsageError( + "%s: 'minversion' must be a single value" % self.inipath + ) + + if Version(minver) > Version(pytest.__version__): + raise pytest.UsageError( + "%s: 'minversion' requires pytest-%s, actual pytest-%s'" + % ( + self.inipath, + minver, + pytest.__version__, + ) + ) + + def _validate_config_options(self) -> None: + for key in sorted(self._get_unknown_ini_keys()): + self._warn_or_fail_if_strict(f"Unknown config option: {key}\n") + + def _validate_plugins(self) -> None: + required_plugins = sorted(self.getini("required_plugins")) + if not required_plugins: + return + + # Imported lazily to improve start-up time. + from packaging.version import Version + from packaging.requirements import InvalidRequirement, Requirement + + plugin_info = self.pluginmanager.list_plugin_distinfo() + plugin_dist_info = {dist.project_name: dist.version for _, dist in plugin_info} + + missing_plugins = [] + for required_plugin in required_plugins: + try: + req = Requirement(required_plugin) + except InvalidRequirement: + missing_plugins.append(required_plugin) + continue + + if req.name not in plugin_dist_info: + missing_plugins.append(required_plugin) + elif not req.specifier.contains( + Version(plugin_dist_info[req.name]), prereleases=True + ): + missing_plugins.append(required_plugin) + + if missing_plugins: + raise UsageError( + "Missing required plugins: {}".format(", ".join(missing_plugins)), + ) + + def _warn_or_fail_if_strict(self, message: str) -> None: + if self.known_args_namespace.strict_config: + raise UsageError(message) + + self.issue_config_time_warning(PytestConfigWarning(message), stacklevel=3) + + def _get_unknown_ini_keys(self) -> List[str]: + parser_inicfg = self._parser._inidict + return [name for name in self.inicfg if name not in parser_inicfg] + + def parse(self, args: List[str], addopts: bool = True) -> None: + # Parse given cmdline arguments into this config object. + assert ( + self.args == [] + ), "can only parse cmdline args at most once per Config object" + self.hook.pytest_addhooks.call_historic( + kwargs=dict(pluginmanager=self.pluginmanager) + ) + self._preparse(args, addopts=addopts) + # XXX deprecated hook: + self.hook.pytest_cmdline_preparse(config=self, args=args) + self._parser.after_preparse = True # type: ignore + try: + args = self._parser.parse_setoption( + args, self.option, namespace=self.option + ) + self.args, self.args_source = self._decide_args( + args=args, + pyargs=self.known_args_namespace.pyargs, + testpaths=self.getini("testpaths"), + invocation_dir=self.invocation_params.dir, + rootpath=self.rootpath, + warn=True, + ) + except PrintHelp: + pass + + def issue_config_time_warning(self, warning: Warning, stacklevel: int) -> None: + """Issue and handle a warning during the "configure" stage. + + During ``pytest_configure`` we can't capture warnings using the ``catch_warnings_for_item`` + function because it is not possible to have hookwrappers around ``pytest_configure``. + + This function is mainly intended for plugins that need to issue warnings during + ``pytest_configure`` (or similar stages). + + :param warning: The warning instance. + :param stacklevel: stacklevel forwarded to warnings.warn. + """ + if self.pluginmanager.is_blocked("warnings"): + return + + cmdline_filters = self.known_args_namespace.pythonwarnings or [] + config_filters = self.getini("filterwarnings") + + with warnings.catch_warnings(record=True) as records: + warnings.simplefilter("always", type(warning)) + apply_warning_filters(config_filters, cmdline_filters) + warnings.warn(warning, stacklevel=stacklevel) + + if records: + frame = sys._getframe(stacklevel - 1) + location = frame.f_code.co_filename, frame.f_lineno, frame.f_code.co_name + self.hook.pytest_warning_recorded.call_historic( + kwargs=dict( + warning_message=records[0], + when="config", + nodeid="", + location=location, + ) + ) + + def addinivalue_line(self, name: str, line: str) -> None: + """Add a line to an ini-file option. The option must have been + declared but might not yet be set in which case the line becomes + the first line in its value.""" + x = self.getini(name) + assert isinstance(x, list) + x.append(line) # modifies the cached list inline + + def getini(self, name: str): + """Return configuration value from an :ref:`ini file `. + + If the specified name hasn't been registered through a prior + :func:`parser.addini ` call (usually from a + plugin), a ValueError is raised. + """ + try: + return self._inicache[name] + except KeyError: + self._inicache[name] = val = self._getini(name) + return val + + # Meant for easy monkeypatching by legacypath plugin. + # Can be inlined back (with no cover removed) once legacypath is gone. + def _getini_unknown_type(self, name: str, type: str, value: Union[str, List[str]]): + msg = f"unknown configuration type: {type}" + raise ValueError(msg, value) # pragma: no cover + + def _getini(self, name: str): + try: + description, type, default = self._parser._inidict[name] + except KeyError as e: + raise ValueError(f"unknown configuration value: {name!r}") from e + override_value = self._get_override_ini_value(name) + if override_value is None: + try: + value = self.inicfg[name] + except KeyError: + if default is not None: + return default + if type is None: + return "" + return [] + else: + value = override_value + # Coerce the values based on types. + # + # Note: some coercions are only required if we are reading from .ini files, because + # the file format doesn't contain type information, but when reading from toml we will + # get either str or list of str values (see _parse_ini_config_from_pyproject_toml). + # For example: + # + # ini: + # a_line_list = "tests acceptance" + # in this case, we need to split the string to obtain a list of strings. + # + # toml: + # a_line_list = ["tests", "acceptance"] + # in this case, we already have a list ready to use. + # + if type == "paths": + # TODO: This assert is probably not valid in all cases. + assert self.inipath is not None + dp = self.inipath.parent + input_values = shlex.split(value) if isinstance(value, str) else value + return [dp / x for x in input_values] + elif type == "args": + return shlex.split(value) if isinstance(value, str) else value + elif type == "linelist": + if isinstance(value, str): + return [t for t in map(lambda x: x.strip(), value.split("\n")) if t] + else: + return value + elif type == "bool": + return _strtobool(str(value).strip()) + elif type == "string": + return value + elif type is None: + return value + else: + return self._getini_unknown_type(name, type, value) + + def _getconftest_pathlist( + self, name: str, path: Path, rootpath: Path + ) -> Optional[List[Path]]: + try: + mod, relroots = self.pluginmanager._rget_with_confmod( + name, path, self.getoption("importmode"), rootpath + ) + except KeyError: + return None + assert mod.__file__ is not None + modpath = Path(mod.__file__).parent + values: List[Path] = [] + for relroot in relroots: + if isinstance(relroot, os.PathLike): + relroot = Path(relroot) + else: + relroot = relroot.replace("/", os.sep) + relroot = absolutepath(modpath / relroot) + values.append(relroot) + return values + + def _get_override_ini_value(self, name: str) -> Optional[str]: + value = None + # override_ini is a list of "ini=value" options. + # Always use the last item if multiple values are set for same ini-name, + # e.g. -o foo=bar1 -o foo=bar2 will set foo to bar2. + for ini_config in self._override_ini: + try: + key, user_ini_value = ini_config.split("=", 1) + except ValueError as e: + raise UsageError( + "-o/--override-ini expects option=value style (got: {!r}).".format( + ini_config + ) + ) from e + else: + if key == name: + value = user_ini_value + return value + + def getoption(self, name: str, default=notset, skip: bool = False): + """Return command line option value. + + :param name: Name of the option. You may also specify + the literal ``--OPT`` option instead of the "dest" option name. + :param default: Default value if no option of that name exists. + :param skip: If True, raise pytest.skip if option does not exists + or has a None value. + """ + name = self._opt2dest.get(name, name) + try: + val = getattr(self.option, name) + if val is None and skip: + raise AttributeError(name) + return val + except AttributeError as e: + if default is not notset: + return default + if skip: + import pytest + + pytest.skip(f"no {name!r} option found") + raise ValueError(f"no option named {name!r}") from e + + def getvalue(self, name: str, path=None): + """Deprecated, use getoption() instead.""" + return self.getoption(name) + + def getvalueorskip(self, name: str, path=None): + """Deprecated, use getoption(skip=True) instead.""" + return self.getoption(name, skip=True) + + def _warn_about_missing_assertion(self, mode: str) -> None: + if not _assertion_supported(): + if mode == "plain": + warning_text = ( + "ASSERTIONS ARE NOT EXECUTED" + " and FAILING TESTS WILL PASS. Are you" + " using python -O?" + ) + else: + warning_text = ( + "assertions not in test modules or" + " plugins will be ignored" + " because assert statements are not executed " + "by the underlying Python interpreter " + "(are you using python -O?)\n" + ) + self.issue_config_time_warning( + PytestConfigWarning(warning_text), + stacklevel=3, + ) + + def _warn_about_skipped_plugins(self) -> None: + for module_name, msg in self.pluginmanager.skipped_plugins: + self.issue_config_time_warning( + PytestConfigWarning(f"skipped plugin {module_name!r}: {msg}"), + stacklevel=2, + ) + + +def _assertion_supported() -> bool: + try: + assert False + except AssertionError: + return True + else: + return False # type: ignore[unreachable] + + +def create_terminal_writer( + config: Config, file: Optional[TextIO] = None +) -> TerminalWriter: + """Create a TerminalWriter instance configured according to the options + in the config object. + + Every code which requires a TerminalWriter object and has access to a + config object should use this function. + """ + tw = TerminalWriter(file=file) + + if config.option.color == "yes": + tw.hasmarkup = True + elif config.option.color == "no": + tw.hasmarkup = False + + if config.option.code_highlight == "yes": + tw.code_highlight = True + elif config.option.code_highlight == "no": + tw.code_highlight = False + + return tw + + +def _strtobool(val: str) -> bool: + """Convert a string representation of truth to True or False. + + True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values + are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if + 'val' is anything else. + + .. note:: Copied from distutils.util. + """ + val = val.lower() + if val in ("y", "yes", "t", "true", "on", "1"): + return True + elif val in ("n", "no", "f", "false", "off", "0"): + return False + else: + raise ValueError(f"invalid truth value {val!r}") + + +@lru_cache(maxsize=50) +def parse_warning_filter( + arg: str, *, escape: bool +) -> Tuple["warnings._ActionKind", str, Type[Warning], str, int]: + """Parse a warnings filter string. + + This is copied from warnings._setoption with the following changes: + + * Does not apply the filter. + * Escaping is optional. + * Raises UsageError so we get nice error messages on failure. + """ + __tracebackhide__ = True + error_template = dedent( + f"""\ + while parsing the following warning configuration: + + {arg} + + This error occurred: + + {{error}} + """ + ) + + parts = arg.split(":") + if len(parts) > 5: + doc_url = ( + "https://docs.python.org/3/library/warnings.html#describing-warning-filters" + ) + error = dedent( + f"""\ + Too many fields ({len(parts)}), expected at most 5 separated by colons: + + action:message:category:module:line + + For more information please consult: {doc_url} + """ + ) + raise UsageError(error_template.format(error=error)) + + while len(parts) < 5: + parts.append("") + action_, message, category_, module, lineno_ = (s.strip() for s in parts) + try: + action: "warnings._ActionKind" = warnings._getaction(action_) # type: ignore[attr-defined] + except warnings._OptionError as e: + raise UsageError(error_template.format(error=str(e))) + try: + category: Type[Warning] = _resolve_warning_category(category_) + except Exception: + exc_info = ExceptionInfo.from_current() + exception_text = exc_info.getrepr(style="native") + raise UsageError(error_template.format(error=exception_text)) + if message and escape: + message = re.escape(message) + if module and escape: + module = re.escape(module) + r"\Z" + if lineno_: + try: + lineno = int(lineno_) + if lineno < 0: + raise ValueError("number is negative") + except ValueError as e: + raise UsageError( + error_template.format(error=f"invalid lineno {lineno_!r}: {e}") + ) + else: + lineno = 0 + return action, message, category, module, lineno + + +def _resolve_warning_category(category: str) -> Type[Warning]: + """ + Copied from warnings._getcategory, but changed so it lets exceptions (specially ImportErrors) + propagate so we can get access to their tracebacks (#9218). + """ + __tracebackhide__ = True + if not category: + return Warning + + if "." not in category: + import builtins as m + + klass = category + else: + module, _, klass = category.rpartition(".") + m = __import__(module, None, None, [klass]) + cat = getattr(m, klass) + if not issubclass(cat, Warning): + raise UsageError(f"{cat} is not a Warning subclass") + return cast(Type[Warning], cat) + + +def apply_warning_filters( + config_filters: Iterable[str], cmdline_filters: Iterable[str] +) -> None: + """Applies pytest-configured filters to the warnings module""" + # Filters should have this precedence: cmdline options, config. + # Filters should be applied in the inverse order of precedence. + for arg in config_filters: + warnings.filterwarnings(*parse_warning_filter(arg, escape=False)) + + for arg in cmdline_filters: + warnings.filterwarnings(*parse_warning_filter(arg, escape=True)) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/config/argparsing.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/config/argparsing.py new file mode 100644 index 000000000..d3f01916b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/config/argparsing.py @@ -0,0 +1,551 @@ +import argparse +import os +import sys +import warnings +from gettext import gettext +from typing import Any +from typing import Callable +from typing import cast +from typing import Dict +from typing import List +from typing import Mapping +from typing import NoReturn +from typing import Optional +from typing import Sequence +from typing import Tuple +from typing import TYPE_CHECKING +from typing import Union + +import _pytest._io +from _pytest.compat import final +from _pytest.config.exceptions import UsageError +from _pytest.deprecated import ARGUMENT_PERCENT_DEFAULT +from _pytest.deprecated import ARGUMENT_TYPE_STR +from _pytest.deprecated import ARGUMENT_TYPE_STR_CHOICE +from _pytest.deprecated import check_ispytest + +if TYPE_CHECKING: + from typing_extensions import Literal + +FILE_OR_DIR = "file_or_dir" + + +@final +class Parser: + """Parser for command line arguments and ini-file values. + + :ivar extra_info: Dict of generic param -> value to display in case + there's an error processing the command line arguments. + """ + + prog: Optional[str] = None + + def __init__( + self, + usage: Optional[str] = None, + processopt: Optional[Callable[["Argument"], None]] = None, + *, + _ispytest: bool = False, + ) -> None: + check_ispytest(_ispytest) + self._anonymous = OptionGroup("Custom options", parser=self, _ispytest=True) + self._groups: List[OptionGroup] = [] + self._processopt = processopt + self._usage = usage + self._inidict: Dict[str, Tuple[str, Optional[str], Any]] = {} + self._ininames: List[str] = [] + self.extra_info: Dict[str, Any] = {} + + def processoption(self, option: "Argument") -> None: + if self._processopt: + if option.dest: + self._processopt(option) + + def getgroup( + self, name: str, description: str = "", after: Optional[str] = None + ) -> "OptionGroup": + """Get (or create) a named option Group. + + :param name: Name of the option group. + :param description: Long description for --help output. + :param after: Name of another group, used for ordering --help output. + :returns: The option group. + + The returned group object has an ``addoption`` method with the same + signature as :func:`parser.addoption ` but + will be shown in the respective group in the output of + ``pytest --help``. + """ + for group in self._groups: + if group.name == name: + return group + group = OptionGroup(name, description, parser=self, _ispytest=True) + i = 0 + for i, grp in enumerate(self._groups): + if grp.name == after: + break + self._groups.insert(i + 1, group) + return group + + def addoption(self, *opts: str, **attrs: Any) -> None: + """Register a command line option. + + :param opts: + Option names, can be short or long options. + :param attrs: + Same attributes as the argparse library's :py:func:`add_argument() + ` function accepts. + + After command line parsing, options are available on the pytest config + object via ``config.option.NAME`` where ``NAME`` is usually set + by passing a ``dest`` attribute, for example + ``addoption("--long", dest="NAME", ...)``. + """ + self._anonymous.addoption(*opts, **attrs) + + def parse( + self, + args: Sequence[Union[str, "os.PathLike[str]"]], + namespace: Optional[argparse.Namespace] = None, + ) -> argparse.Namespace: + from _pytest._argcomplete import try_argcomplete + + self.optparser = self._getparser() + try_argcomplete(self.optparser) + strargs = [os.fspath(x) for x in args] + return self.optparser.parse_args(strargs, namespace=namespace) + + def _getparser(self) -> "MyOptionParser": + from _pytest._argcomplete import filescompleter + + optparser = MyOptionParser(self, self.extra_info, prog=self.prog) + groups = self._groups + [self._anonymous] + for group in groups: + if group.options: + desc = group.description or group.name + arggroup = optparser.add_argument_group(desc) + for option in group.options: + n = option.names() + a = option.attrs() + arggroup.add_argument(*n, **a) + file_or_dir_arg = optparser.add_argument(FILE_OR_DIR, nargs="*") + # bash like autocompletion for dirs (appending '/') + # Type ignored because typeshed doesn't know about argcomplete. + file_or_dir_arg.completer = filescompleter # type: ignore + return optparser + + def parse_setoption( + self, + args: Sequence[Union[str, "os.PathLike[str]"]], + option: argparse.Namespace, + namespace: Optional[argparse.Namespace] = None, + ) -> List[str]: + parsedoption = self.parse(args, namespace=namespace) + for name, value in parsedoption.__dict__.items(): + setattr(option, name, value) + return cast(List[str], getattr(parsedoption, FILE_OR_DIR)) + + def parse_known_args( + self, + args: Sequence[Union[str, "os.PathLike[str]"]], + namespace: Optional[argparse.Namespace] = None, + ) -> argparse.Namespace: + """Parse the known arguments at this point. + + :returns: An argparse namespace object. + """ + return self.parse_known_and_unknown_args(args, namespace=namespace)[0] + + def parse_known_and_unknown_args( + self, + args: Sequence[Union[str, "os.PathLike[str]"]], + namespace: Optional[argparse.Namespace] = None, + ) -> Tuple[argparse.Namespace, List[str]]: + """Parse the known arguments at this point, and also return the + remaining unknown arguments. + + :returns: + A tuple containing an argparse namespace object for the known + arguments, and a list of the unknown arguments. + """ + optparser = self._getparser() + strargs = [os.fspath(x) for x in args] + return optparser.parse_known_args(strargs, namespace=namespace) + + def addini( + self, + name: str, + help: str, + type: Optional[ + "Literal['string', 'paths', 'pathlist', 'args', 'linelist', 'bool']" + ] = None, + default: Any = None, + ) -> None: + """Register an ini-file option. + + :param name: + Name of the ini-variable. + :param type: + Type of the variable. Can be: + + * ``string``: a string + * ``bool``: a boolean + * ``args``: a list of strings, separated as in a shell + * ``linelist``: a list of strings, separated by line breaks + * ``paths``: a list of :class:`pathlib.Path`, separated as in a shell + * ``pathlist``: a list of ``py.path``, separated as in a shell + + .. versionadded:: 7.0 + The ``paths`` variable type. + + Defaults to ``string`` if ``None`` or not passed. + :param default: + Default value if no ini-file option exists but is queried. + + The value of ini-variables can be retrieved via a call to + :py:func:`config.getini(name) `. + """ + assert type in (None, "string", "paths", "pathlist", "args", "linelist", "bool") + self._inidict[name] = (help, type, default) + self._ininames.append(name) + + +class ArgumentError(Exception): + """Raised if an Argument instance is created with invalid or + inconsistent arguments.""" + + def __init__(self, msg: str, option: Union["Argument", str]) -> None: + self.msg = msg + self.option_id = str(option) + + def __str__(self) -> str: + if self.option_id: + return f"option {self.option_id}: {self.msg}" + else: + return self.msg + + +class Argument: + """Class that mimics the necessary behaviour of optparse.Option. + + It's currently a least effort implementation and ignoring choices + and integer prefixes. + + https://docs.python.org/3/library/optparse.html#optparse-standard-option-types + """ + + _typ_map = {"int": int, "string": str, "float": float, "complex": complex} + + def __init__(self, *names: str, **attrs: Any) -> None: + """Store params in private vars for use in add_argument.""" + self._attrs = attrs + self._short_opts: List[str] = [] + self._long_opts: List[str] = [] + if "%default" in (attrs.get("help") or ""): + warnings.warn(ARGUMENT_PERCENT_DEFAULT, stacklevel=3) + try: + typ = attrs["type"] + except KeyError: + pass + else: + # This might raise a keyerror as well, don't want to catch that. + if isinstance(typ, str): + if typ == "choice": + warnings.warn( + ARGUMENT_TYPE_STR_CHOICE.format(typ=typ, names=names), + stacklevel=4, + ) + # argparse expects a type here take it from + # the type of the first element + attrs["type"] = type(attrs["choices"][0]) + else: + warnings.warn( + ARGUMENT_TYPE_STR.format(typ=typ, names=names), stacklevel=4 + ) + attrs["type"] = Argument._typ_map[typ] + # Used in test_parseopt -> test_parse_defaultgetter. + self.type = attrs["type"] + else: + self.type = typ + try: + # Attribute existence is tested in Config._processopt. + self.default = attrs["default"] + except KeyError: + pass + self._set_opt_strings(names) + dest: Optional[str] = attrs.get("dest") + if dest: + self.dest = dest + elif self._long_opts: + self.dest = self._long_opts[0][2:].replace("-", "_") + else: + try: + self.dest = self._short_opts[0][1:] + except IndexError as e: + self.dest = "???" # Needed for the error repr. + raise ArgumentError("need a long or short option", self) from e + + def names(self) -> List[str]: + return self._short_opts + self._long_opts + + def attrs(self) -> Mapping[str, Any]: + # Update any attributes set by processopt. + attrs = "default dest help".split() + attrs.append(self.dest) + for attr in attrs: + try: + self._attrs[attr] = getattr(self, attr) + except AttributeError: + pass + if self._attrs.get("help"): + a = self._attrs["help"] + a = a.replace("%default", "%(default)s") + # a = a.replace('%prog', '%(prog)s') + self._attrs["help"] = a + return self._attrs + + def _set_opt_strings(self, opts: Sequence[str]) -> None: + """Directly from optparse. + + Might not be necessary as this is passed to argparse later on. + """ + for opt in opts: + if len(opt) < 2: + raise ArgumentError( + "invalid option string %r: " + "must be at least two characters long" % opt, + self, + ) + elif len(opt) == 2: + if not (opt[0] == "-" and opt[1] != "-"): + raise ArgumentError( + "invalid short option string %r: " + "must be of the form -x, (x any non-dash char)" % opt, + self, + ) + self._short_opts.append(opt) + else: + if not (opt[0:2] == "--" and opt[2] != "-"): + raise ArgumentError( + "invalid long option string %r: " + "must start with --, followed by non-dash" % opt, + self, + ) + self._long_opts.append(opt) + + def __repr__(self) -> str: + args: List[str] = [] + if self._short_opts: + args += ["_short_opts: " + repr(self._short_opts)] + if self._long_opts: + args += ["_long_opts: " + repr(self._long_opts)] + args += ["dest: " + repr(self.dest)] + if hasattr(self, "type"): + args += ["type: " + repr(self.type)] + if hasattr(self, "default"): + args += ["default: " + repr(self.default)] + return "Argument({})".format(", ".join(args)) + + +class OptionGroup: + """A group of options shown in its own section.""" + + def __init__( + self, + name: str, + description: str = "", + parser: Optional[Parser] = None, + *, + _ispytest: bool = False, + ) -> None: + check_ispytest(_ispytest) + self.name = name + self.description = description + self.options: List[Argument] = [] + self.parser = parser + + def addoption(self, *opts: str, **attrs: Any) -> None: + """Add an option to this group. + + If a shortened version of a long option is specified, it will + be suppressed in the help. ``addoption('--twowords', '--two-words')`` + results in help showing ``--two-words`` only, but ``--twowords`` gets + accepted **and** the automatic destination is in ``args.twowords``. + + :param opts: + Option names, can be short or long options. + :param attrs: + Same attributes as the argparse library's :py:func:`add_argument() + ` function accepts. + """ + conflict = set(opts).intersection( + name for opt in self.options for name in opt.names() + ) + if conflict: + raise ValueError("option names %s already added" % conflict) + option = Argument(*opts, **attrs) + self._addoption_instance(option, shortupper=False) + + def _addoption(self, *opts: str, **attrs: Any) -> None: + option = Argument(*opts, **attrs) + self._addoption_instance(option, shortupper=True) + + def _addoption_instance(self, option: "Argument", shortupper: bool = False) -> None: + if not shortupper: + for opt in option._short_opts: + if opt[0] == "-" and opt[1].islower(): + raise ValueError("lowercase shortoptions reserved") + if self.parser: + self.parser.processoption(option) + self.options.append(option) + + +class MyOptionParser(argparse.ArgumentParser): + def __init__( + self, + parser: Parser, + extra_info: Optional[Dict[str, Any]] = None, + prog: Optional[str] = None, + ) -> None: + self._parser = parser + super().__init__( + prog=prog, + usage=parser._usage, + add_help=False, + formatter_class=DropShorterLongHelpFormatter, + allow_abbrev=False, + ) + # extra_info is a dict of (param -> value) to display if there's + # an usage error to provide more contextual information to the user. + self.extra_info = extra_info if extra_info else {} + + def error(self, message: str) -> NoReturn: + """Transform argparse error message into UsageError.""" + msg = f"{self.prog}: error: {message}" + + if hasattr(self._parser, "_config_source_hint"): + # Type ignored because the attribute is set dynamically. + msg = f"{msg} ({self._parser._config_source_hint})" # type: ignore + + raise UsageError(self.format_usage() + msg) + + # Type ignored because typeshed has a very complex type in the superclass. + def parse_args( # type: ignore + self, + args: Optional[Sequence[str]] = None, + namespace: Optional[argparse.Namespace] = None, + ) -> argparse.Namespace: + """Allow splitting of positional arguments.""" + parsed, unrecognized = self.parse_known_args(args, namespace) + if unrecognized: + for arg in unrecognized: + if arg and arg[0] == "-": + lines = ["unrecognized arguments: %s" % (" ".join(unrecognized))] + for k, v in sorted(self.extra_info.items()): + lines.append(f" {k}: {v}") + self.error("\n".join(lines)) + getattr(parsed, FILE_OR_DIR).extend(unrecognized) + return parsed + + if sys.version_info[:2] < (3, 9): # pragma: no cover + # Backport of https://github.com/python/cpython/pull/14316 so we can + # disable long --argument abbreviations without breaking short flags. + def _parse_optional( + self, arg_string: str + ) -> Optional[Tuple[Optional[argparse.Action], str, Optional[str]]]: + if not arg_string: + return None + if not arg_string[0] in self.prefix_chars: + return None + if arg_string in self._option_string_actions: + action = self._option_string_actions[arg_string] + return action, arg_string, None + if len(arg_string) == 1: + return None + if "=" in arg_string: + option_string, explicit_arg = arg_string.split("=", 1) + if option_string in self._option_string_actions: + action = self._option_string_actions[option_string] + return action, option_string, explicit_arg + if self.allow_abbrev or not arg_string.startswith("--"): + option_tuples = self._get_option_tuples(arg_string) + if len(option_tuples) > 1: + msg = gettext( + "ambiguous option: %(option)s could match %(matches)s" + ) + options = ", ".join(option for _, option, _ in option_tuples) + self.error(msg % {"option": arg_string, "matches": options}) + elif len(option_tuples) == 1: + (option_tuple,) = option_tuples + return option_tuple + if self._negative_number_matcher.match(arg_string): + if not self._has_negative_number_optionals: + return None + if " " in arg_string: + return None + return None, arg_string, None + + +class DropShorterLongHelpFormatter(argparse.HelpFormatter): + """Shorten help for long options that differ only in extra hyphens. + + - Collapse **long** options that are the same except for extra hyphens. + - Shortcut if there are only two options and one of them is a short one. + - Cache result on the action object as this is called at least 2 times. + """ + + def __init__(self, *args: Any, **kwargs: Any) -> None: + # Use more accurate terminal width. + if "width" not in kwargs: + kwargs["width"] = _pytest._io.get_terminal_width() + super().__init__(*args, **kwargs) + + def _format_action_invocation(self, action: argparse.Action) -> str: + orgstr = super()._format_action_invocation(action) + if orgstr and orgstr[0] != "-": # only optional arguments + return orgstr + res: Optional[str] = getattr(action, "_formatted_action_invocation", None) + if res: + return res + options = orgstr.split(", ") + if len(options) == 2 and (len(options[0]) == 2 or len(options[1]) == 2): + # a shortcut for '-h, --help' or '--abc', '-a' + action._formatted_action_invocation = orgstr # type: ignore + return orgstr + return_list = [] + short_long: Dict[str, str] = {} + for option in options: + if len(option) == 2 or option[2] == " ": + continue + if not option.startswith("--"): + raise ArgumentError( + 'long optional argument without "--": [%s]' % (option), option + ) + xxoption = option[2:] + shortened = xxoption.replace("-", "") + if shortened not in short_long or len(short_long[shortened]) < len( + xxoption + ): + short_long[shortened] = xxoption + # now short_long has been filled out to the longest with dashes + # **and** we keep the right option ordering from add_argument + for option in options: + if len(option) == 2 or option[2] == " ": + return_list.append(option) + if option[2:] == short_long.get(option.replace("-", "")): + return_list.append(option.replace(" ", "=", 1)) + formatted_action_invocation = ", ".join(return_list) + action._formatted_action_invocation = formatted_action_invocation # type: ignore + return formatted_action_invocation + + def _split_lines(self, text, width): + """Wrap lines after splitting on original newlines. + + This allows to have explicit line breaks in the help text. + """ + import textwrap + + lines = [] + for line in text.splitlines(): + lines.extend(textwrap.wrap(line.strip(), width)) + return lines diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/config/compat.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/config/compat.py new file mode 100644 index 000000000..5bd922a4a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/config/compat.py @@ -0,0 +1,70 @@ +import functools +import warnings +from pathlib import Path +from typing import Optional + +from ..compat import LEGACY_PATH +from ..compat import legacy_path +from ..deprecated import HOOK_LEGACY_PATH_ARG +from _pytest.nodes import _check_path + +# hookname: (Path, LEGACY_PATH) +imply_paths_hooks = { + "pytest_ignore_collect": ("collection_path", "path"), + "pytest_collect_file": ("file_path", "path"), + "pytest_pycollect_makemodule": ("module_path", "path"), + "pytest_report_header": ("start_path", "startdir"), + "pytest_report_collectionfinish": ("start_path", "startdir"), +} + + +class PathAwareHookProxy: + """ + this helper wraps around hook callers + until pluggy supports fixingcalls, this one will do + + it currently doesn't return full hook caller proxies for fixed hooks, + this may have to be changed later depending on bugs + """ + + def __init__(self, hook_caller): + self.__hook_caller = hook_caller + + def __dir__(self): + return dir(self.__hook_caller) + + def __getattr__(self, key, _wraps=functools.wraps): + hook = getattr(self.__hook_caller, key) + if key not in imply_paths_hooks: + self.__dict__[key] = hook + return hook + else: + path_var, fspath_var = imply_paths_hooks[key] + + @_wraps(hook) + def fixed_hook(**kw): + path_value: Optional[Path] = kw.pop(path_var, None) + fspath_value: Optional[LEGACY_PATH] = kw.pop(fspath_var, None) + if fspath_value is not None: + warnings.warn( + HOOK_LEGACY_PATH_ARG.format( + pylib_path_arg=fspath_var, pathlib_path_arg=path_var + ), + stacklevel=2, + ) + if path_value is not None: + if fspath_value is not None: + _check_path(path_value, fspath_value) + else: + fspath_value = legacy_path(path_value) + else: + assert fspath_value is not None + path_value = Path(fspath_value) + + kw[path_var] = path_value + kw[fspath_var] = fspath_value + return hook(**kw) + + fixed_hook.__name__ = key + self.__dict__[key] = fixed_hook + return fixed_hook diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/config/exceptions.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/config/exceptions.py new file mode 100644 index 000000000..4f1320e75 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/config/exceptions.py @@ -0,0 +1,11 @@ +from _pytest.compat import final + + +@final +class UsageError(Exception): + """Error in pytest usage or invocation.""" + + +class PrintHelp(Exception): + """Raised when pytest should print its help to skip the rest of the + argument parsing and validation.""" diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/config/findpaths.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/config/findpaths.py new file mode 100644 index 000000000..02674ffae --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/config/findpaths.py @@ -0,0 +1,218 @@ +import os +import sys +from pathlib import Path +from typing import Dict +from typing import Iterable +from typing import List +from typing import Optional +from typing import Sequence +from typing import Tuple +from typing import TYPE_CHECKING +from typing import Union + +import iniconfig + +from .exceptions import UsageError +from _pytest.outcomes import fail +from _pytest.pathlib import absolutepath +from _pytest.pathlib import commonpath +from _pytest.pathlib import safe_exists + +if TYPE_CHECKING: + from . import Config + + +def _parse_ini_config(path: Path) -> iniconfig.IniConfig: + """Parse the given generic '.ini' file using legacy IniConfig parser, returning + the parsed object. + + Raise UsageError if the file cannot be parsed. + """ + try: + return iniconfig.IniConfig(str(path)) + except iniconfig.ParseError as exc: + raise UsageError(str(exc)) from exc + + +def load_config_dict_from_file( + filepath: Path, +) -> Optional[Dict[str, Union[str, List[str]]]]: + """Load pytest configuration from the given file path, if supported. + + Return None if the file does not contain valid pytest configuration. + """ + + # Configuration from ini files are obtained from the [pytest] section, if present. + if filepath.suffix == ".ini": + iniconfig = _parse_ini_config(filepath) + + if "pytest" in iniconfig: + return dict(iniconfig["pytest"].items()) + else: + # "pytest.ini" files are always the source of configuration, even if empty. + if filepath.name == "pytest.ini": + return {} + + # '.cfg' files are considered if they contain a "[tool:pytest]" section. + elif filepath.suffix == ".cfg": + iniconfig = _parse_ini_config(filepath) + + if "tool:pytest" in iniconfig.sections: + return dict(iniconfig["tool:pytest"].items()) + elif "pytest" in iniconfig.sections: + # If a setup.cfg contains a "[pytest]" section, we raise a failure to indicate users that + # plain "[pytest]" sections in setup.cfg files is no longer supported (#3086). + fail(CFG_PYTEST_SECTION.format(filename="setup.cfg"), pytrace=False) + + # '.toml' files are considered if they contain a [tool.pytest.ini_options] table. + elif filepath.suffix == ".toml": + if sys.version_info >= (3, 11): + import tomllib + else: + import tomli as tomllib + + toml_text = filepath.read_text(encoding="utf-8") + try: + config = tomllib.loads(toml_text) + except tomllib.TOMLDecodeError as exc: + raise UsageError(f"{filepath}: {exc}") from exc + + result = config.get("tool", {}).get("pytest", {}).get("ini_options", None) + if result is not None: + # TOML supports richer data types than ini files (strings, arrays, floats, ints, etc), + # however we need to convert all scalar values to str for compatibility with the rest + # of the configuration system, which expects strings only. + def make_scalar(v: object) -> Union[str, List[str]]: + return v if isinstance(v, list) else str(v) + + return {k: make_scalar(v) for k, v in result.items()} + + return None + + +def locate_config( + args: Iterable[Path], +) -> Tuple[Optional[Path], Optional[Path], Dict[str, Union[str, List[str]]]]: + """Search in the list of arguments for a valid ini-file for pytest, + and return a tuple of (rootdir, inifile, cfg-dict).""" + config_names = [ + "pytest.ini", + ".pytest.ini", + "pyproject.toml", + "tox.ini", + "setup.cfg", + ] + args = [x for x in args if not str(x).startswith("-")] + if not args: + args = [Path.cwd()] + for arg in args: + argpath = absolutepath(arg) + for base in (argpath, *argpath.parents): + for config_name in config_names: + p = base / config_name + if p.is_file(): + ini_config = load_config_dict_from_file(p) + if ini_config is not None: + return base, p, ini_config + return None, None, {} + + +def get_common_ancestor(paths: Iterable[Path]) -> Path: + common_ancestor: Optional[Path] = None + for path in paths: + if not path.exists(): + continue + if common_ancestor is None: + common_ancestor = path + else: + if common_ancestor in path.parents or path == common_ancestor: + continue + elif path in common_ancestor.parents: + common_ancestor = path + else: + shared = commonpath(path, common_ancestor) + if shared is not None: + common_ancestor = shared + if common_ancestor is None: + common_ancestor = Path.cwd() + elif common_ancestor.is_file(): + common_ancestor = common_ancestor.parent + return common_ancestor + + +def get_dirs_from_args(args: Iterable[str]) -> List[Path]: + def is_option(x: str) -> bool: + return x.startswith("-") + + def get_file_part_from_node_id(x: str) -> str: + return x.split("::")[0] + + def get_dir_from_path(path: Path) -> Path: + if path.is_dir(): + return path + return path.parent + + # These look like paths but may not exist + possible_paths = ( + absolutepath(get_file_part_from_node_id(arg)) + for arg in args + if not is_option(arg) + ) + + return [get_dir_from_path(path) for path in possible_paths if safe_exists(path)] + + +CFG_PYTEST_SECTION = "[pytest] section in {filename} files is no longer supported, change to [tool:pytest] instead." + + +def determine_setup( + inifile: Optional[str], + args: Sequence[str], + rootdir_cmd_arg: Optional[str] = None, + config: Optional["Config"] = None, +) -> Tuple[Path, Optional[Path], Dict[str, Union[str, List[str]]]]: + rootdir = None + dirs = get_dirs_from_args(args) + if inifile: + inipath_ = absolutepath(inifile) + inipath: Optional[Path] = inipath_ + inicfg = load_config_dict_from_file(inipath_) or {} + if rootdir_cmd_arg is None: + rootdir = inipath_.parent + else: + ancestor = get_common_ancestor(dirs) + rootdir, inipath, inicfg = locate_config([ancestor]) + if rootdir is None and rootdir_cmd_arg is None: + for possible_rootdir in (ancestor, *ancestor.parents): + if (possible_rootdir / "setup.py").is_file(): + rootdir = possible_rootdir + break + else: + if dirs != [ancestor]: + rootdir, inipath, inicfg = locate_config(dirs) + if rootdir is None: + if config is not None: + cwd = config.invocation_params.dir + else: + cwd = Path.cwd() + rootdir = get_common_ancestor([cwd, ancestor]) + if is_fs_root(rootdir): + rootdir = ancestor + if rootdir_cmd_arg: + rootdir = absolutepath(os.path.expandvars(rootdir_cmd_arg)) + if not rootdir.is_dir(): + raise UsageError( + "Directory '{}' not found. Check your '--rootdir' option.".format( + rootdir + ) + ) + assert rootdir is not None + return rootdir, inipath, inicfg or {} + + +def is_fs_root(p: Path) -> bool: + r""" + Return True if the given path is pointing to the root of the + file system ("/" on Unix and "C:\\" on Windows for example). + """ + return os.path.splitdrive(str(p))[1] == os.sep diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/debugging.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/debugging.py new file mode 100644 index 000000000..a3f80802c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/debugging.py @@ -0,0 +1,391 @@ +"""Interactive debugging with PDB, the Python Debugger.""" +import argparse +import functools +import sys +import types +import unittest +from typing import Any +from typing import Callable +from typing import Generator +from typing import List +from typing import Optional +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import Union + +from _pytest import outcomes +from _pytest._code import ExceptionInfo +from _pytest.config import Config +from _pytest.config import ConftestImportFailure +from _pytest.config import hookimpl +from _pytest.config import PytestPluginManager +from _pytest.config.argparsing import Parser +from _pytest.config.exceptions import UsageError +from _pytest.nodes import Node +from _pytest.reports import BaseReport + +if TYPE_CHECKING: + from _pytest.capture import CaptureManager + from _pytest.runner import CallInfo + + +def _validate_usepdb_cls(value: str) -> Tuple[str, str]: + """Validate syntax of --pdbcls option.""" + try: + modname, classname = value.split(":") + except ValueError as e: + raise argparse.ArgumentTypeError( + f"{value!r} is not in the format 'modname:classname'" + ) from e + return (modname, classname) + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("general") + group._addoption( + "--pdb", + dest="usepdb", + action="store_true", + help="Start the interactive Python debugger on errors or KeyboardInterrupt", + ) + group._addoption( + "--pdbcls", + dest="usepdb_cls", + metavar="modulename:classname", + type=_validate_usepdb_cls, + help="Specify a custom interactive Python debugger for use with --pdb." + "For example: --pdbcls=IPython.terminal.debugger:TerminalPdb", + ) + group._addoption( + "--trace", + dest="trace", + action="store_true", + help="Immediately break when running each test", + ) + + +def pytest_configure(config: Config) -> None: + import pdb + + if config.getvalue("trace"): + config.pluginmanager.register(PdbTrace(), "pdbtrace") + if config.getvalue("usepdb"): + config.pluginmanager.register(PdbInvoke(), "pdbinvoke") + + pytestPDB._saved.append( + (pdb.set_trace, pytestPDB._pluginmanager, pytestPDB._config) + ) + pdb.set_trace = pytestPDB.set_trace + pytestPDB._pluginmanager = config.pluginmanager + pytestPDB._config = config + + # NOTE: not using pytest_unconfigure, since it might get called although + # pytest_configure was not (if another plugin raises UsageError). + def fin() -> None: + ( + pdb.set_trace, + pytestPDB._pluginmanager, + pytestPDB._config, + ) = pytestPDB._saved.pop() + + config.add_cleanup(fin) + + +class pytestPDB: + """Pseudo PDB that defers to the real pdb.""" + + _pluginmanager: Optional[PytestPluginManager] = None + _config: Optional[Config] = None + _saved: List[ + Tuple[Callable[..., None], Optional[PytestPluginManager], Optional[Config]] + ] = [] + _recursive_debug = 0 + _wrapped_pdb_cls: Optional[Tuple[Type[Any], Type[Any]]] = None + + @classmethod + def _is_capturing(cls, capman: Optional["CaptureManager"]) -> Union[str, bool]: + if capman: + return capman.is_capturing() + return False + + @classmethod + def _import_pdb_cls(cls, capman: Optional["CaptureManager"]): + if not cls._config: + import pdb + + # Happens when using pytest.set_trace outside of a test. + return pdb.Pdb + + usepdb_cls = cls._config.getvalue("usepdb_cls") + + if cls._wrapped_pdb_cls and cls._wrapped_pdb_cls[0] == usepdb_cls: + return cls._wrapped_pdb_cls[1] + + if usepdb_cls: + modname, classname = usepdb_cls + + try: + __import__(modname) + mod = sys.modules[modname] + + # Handle --pdbcls=pdb:pdb.Pdb (useful e.g. with pdbpp). + parts = classname.split(".") + pdb_cls = getattr(mod, parts[0]) + for part in parts[1:]: + pdb_cls = getattr(pdb_cls, part) + except Exception as exc: + value = ":".join((modname, classname)) + raise UsageError( + f"--pdbcls: could not import {value!r}: {exc}" + ) from exc + else: + import pdb + + pdb_cls = pdb.Pdb + + wrapped_cls = cls._get_pdb_wrapper_class(pdb_cls, capman) + cls._wrapped_pdb_cls = (usepdb_cls, wrapped_cls) + return wrapped_cls + + @classmethod + def _get_pdb_wrapper_class(cls, pdb_cls, capman: Optional["CaptureManager"]): + import _pytest.config + + # Type ignored because mypy doesn't support "dynamic" + # inheritance like this. + class PytestPdbWrapper(pdb_cls): # type: ignore[valid-type,misc] + _pytest_capman = capman + _continued = False + + def do_debug(self, arg): + cls._recursive_debug += 1 + ret = super().do_debug(arg) + cls._recursive_debug -= 1 + return ret + + def do_continue(self, arg): + ret = super().do_continue(arg) + if cls._recursive_debug == 0: + assert cls._config is not None + tw = _pytest.config.create_terminal_writer(cls._config) + tw.line() + + capman = self._pytest_capman + capturing = pytestPDB._is_capturing(capman) + if capturing: + if capturing == "global": + tw.sep(">", "PDB continue (IO-capturing resumed)") + else: + tw.sep( + ">", + "PDB continue (IO-capturing resumed for %s)" + % capturing, + ) + assert capman is not None + capman.resume() + else: + tw.sep(">", "PDB continue") + assert cls._pluginmanager is not None + cls._pluginmanager.hook.pytest_leave_pdb(config=cls._config, pdb=self) + self._continued = True + return ret + + do_c = do_cont = do_continue + + def do_quit(self, arg): + """Raise Exit outcome when quit command is used in pdb. + + This is a bit of a hack - it would be better if BdbQuit + could be handled, but this would require to wrap the + whole pytest run, and adjust the report etc. + """ + ret = super().do_quit(arg) + + if cls._recursive_debug == 0: + outcomes.exit("Quitting debugger") + + return ret + + do_q = do_quit + do_exit = do_quit + + def setup(self, f, tb): + """Suspend on setup(). + + Needed after do_continue resumed, and entering another + breakpoint again. + """ + ret = super().setup(f, tb) + if not ret and self._continued: + # pdb.setup() returns True if the command wants to exit + # from the interaction: do not suspend capturing then. + if self._pytest_capman: + self._pytest_capman.suspend_global_capture(in_=True) + return ret + + def get_stack(self, f, t): + stack, i = super().get_stack(f, t) + if f is None: + # Find last non-hidden frame. + i = max(0, len(stack) - 1) + while i and stack[i][0].f_locals.get("__tracebackhide__", False): + i -= 1 + return stack, i + + return PytestPdbWrapper + + @classmethod + def _init_pdb(cls, method, *args, **kwargs): + """Initialize PDB debugging, dropping any IO capturing.""" + import _pytest.config + + if cls._pluginmanager is None: + capman: Optional[CaptureManager] = None + else: + capman = cls._pluginmanager.getplugin("capturemanager") + if capman: + capman.suspend(in_=True) + + if cls._config: + tw = _pytest.config.create_terminal_writer(cls._config) + tw.line() + + if cls._recursive_debug == 0: + # Handle header similar to pdb.set_trace in py37+. + header = kwargs.pop("header", None) + if header is not None: + tw.sep(">", header) + else: + capturing = cls._is_capturing(capman) + if capturing == "global": + tw.sep(">", f"PDB {method} (IO-capturing turned off)") + elif capturing: + tw.sep( + ">", + "PDB %s (IO-capturing turned off for %s)" + % (method, capturing), + ) + else: + tw.sep(">", f"PDB {method}") + + _pdb = cls._import_pdb_cls(capman)(**kwargs) + + if cls._pluginmanager: + cls._pluginmanager.hook.pytest_enter_pdb(config=cls._config, pdb=_pdb) + return _pdb + + @classmethod + def set_trace(cls, *args, **kwargs) -> None: + """Invoke debugging via ``Pdb.set_trace``, dropping any IO capturing.""" + frame = sys._getframe().f_back + _pdb = cls._init_pdb("set_trace", *args, **kwargs) + _pdb.set_trace(frame) + + +class PdbInvoke: + def pytest_exception_interact( + self, node: Node, call: "CallInfo[Any]", report: BaseReport + ) -> None: + capman = node.config.pluginmanager.getplugin("capturemanager") + if capman: + capman.suspend_global_capture(in_=True) + out, err = capman.read_global_capture() + sys.stdout.write(out) + sys.stdout.write(err) + assert call.excinfo is not None + + if not isinstance(call.excinfo.value, unittest.SkipTest): + _enter_pdb(node, call.excinfo, report) + + def pytest_internalerror(self, excinfo: ExceptionInfo[BaseException]) -> None: + tb = _postmortem_traceback(excinfo) + post_mortem(tb) + + +class PdbTrace: + @hookimpl(hookwrapper=True) + def pytest_pyfunc_call(self, pyfuncitem) -> Generator[None, None, None]: + wrap_pytest_function_for_tracing(pyfuncitem) + yield + + +def wrap_pytest_function_for_tracing(pyfuncitem): + """Change the Python function object of the given Function item by a + wrapper which actually enters pdb before calling the python function + itself, effectively leaving the user in the pdb prompt in the first + statement of the function.""" + _pdb = pytestPDB._init_pdb("runcall") + testfunction = pyfuncitem.obj + + # we can't just return `partial(pdb.runcall, testfunction)` because (on + # python < 3.7.4) runcall's first param is `func`, which means we'd get + # an exception if one of the kwargs to testfunction was called `func`. + @functools.wraps(testfunction) + def wrapper(*args, **kwargs): + func = functools.partial(testfunction, *args, **kwargs) + _pdb.runcall(func) + + pyfuncitem.obj = wrapper + + +def maybe_wrap_pytest_function_for_tracing(pyfuncitem): + """Wrap the given pytestfunct item for tracing support if --trace was given in + the command line.""" + if pyfuncitem.config.getvalue("trace"): + wrap_pytest_function_for_tracing(pyfuncitem) + + +def _enter_pdb( + node: Node, excinfo: ExceptionInfo[BaseException], rep: BaseReport +) -> BaseReport: + # XXX we re-use the TerminalReporter's terminalwriter + # because this seems to avoid some encoding related troubles + # for not completely clear reasons. + tw = node.config.pluginmanager.getplugin("terminalreporter")._tw + tw.line() + + showcapture = node.config.option.showcapture + + for sectionname, content in ( + ("stdout", rep.capstdout), + ("stderr", rep.capstderr), + ("log", rep.caplog), + ): + if showcapture in (sectionname, "all") and content: + tw.sep(">", "captured " + sectionname) + if content[-1:] == "\n": + content = content[:-1] + tw.line(content) + + tw.sep(">", "traceback") + rep.toterminal(tw) + tw.sep(">", "entering PDB") + tb = _postmortem_traceback(excinfo) + rep._pdbshown = True # type: ignore[attr-defined] + post_mortem(tb) + return rep + + +def _postmortem_traceback(excinfo: ExceptionInfo[BaseException]) -> types.TracebackType: + from doctest import UnexpectedException + + if isinstance(excinfo.value, UnexpectedException): + # A doctest.UnexpectedException is not useful for post_mortem. + # Use the underlying exception instead: + return excinfo.value.exc_info[2] + elif isinstance(excinfo.value, ConftestImportFailure): + # A config.ConftestImportFailure is not useful for post_mortem. + # Use the underlying exception instead: + return excinfo.value.excinfo[2] + else: + assert excinfo._excinfo is not None + return excinfo._excinfo[2] + + +def post_mortem(t: types.TracebackType) -> None: + p = pytestPDB._init_pdb("post_mortem") + p.reset() + p.interaction(None, t) + if p.quitting: + outcomes.exit("Quitting debugger") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/deprecated.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/deprecated.py new file mode 100644 index 000000000..b9c10df7a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/deprecated.py @@ -0,0 +1,146 @@ +"""Deprecation messages and bits of code used elsewhere in the codebase that +is planned to be removed in the next pytest release. + +Keeping it in a central location makes it easy to track what is deprecated and should +be removed when the time comes. + +All constants defined in this module should be either instances of +:class:`PytestWarning`, or :class:`UnformattedWarning` +in case of warnings which need to format their messages. +""" +from warnings import warn + +from _pytest.warning_types import PytestDeprecationWarning +from _pytest.warning_types import PytestRemovedIn8Warning +from _pytest.warning_types import UnformattedWarning + +# set of plugins which have been integrated into the core; we use this list to ignore +# them during registration to avoid conflicts +DEPRECATED_EXTERNAL_PLUGINS = { + "pytest_catchlog", + "pytest_capturelog", + "pytest_faulthandler", +} + +NOSE_SUPPORT = UnformattedWarning( + PytestRemovedIn8Warning, + "Support for nose tests is deprecated and will be removed in a future release.\n" + "{nodeid} is using nose method: `{method}` ({stage})\n" + "See docs: https://docs.pytest.org/en/stable/deprecations.html#support-for-tests-written-for-nose", +) + +NOSE_SUPPORT_METHOD = UnformattedWarning( + PytestRemovedIn8Warning, + "Support for nose tests is deprecated and will be removed in a future release.\n" + "{nodeid} is using nose-specific method: `{method}(self)`\n" + "To remove this warning, rename it to `{method}_method(self)`\n" + "See docs: https://docs.pytest.org/en/stable/deprecations.html#support-for-tests-written-for-nose", +) + + +# This can be* removed pytest 8, but it's harmless and common, so no rush to remove. +# * If you're in the future: "could have been". +YIELD_FIXTURE = PytestDeprecationWarning( + "@pytest.yield_fixture is deprecated.\n" + "Use @pytest.fixture instead; they are the same." +) + +WARNING_CMDLINE_PREPARSE_HOOK = PytestRemovedIn8Warning( + "The pytest_cmdline_preparse hook is deprecated and will be removed in a future release. \n" + "Please use pytest_load_initial_conftests hook instead." +) + +FSCOLLECTOR_GETHOOKPROXY_ISINITPATH = PytestRemovedIn8Warning( + "The gethookproxy() and isinitpath() methods of FSCollector and Package are deprecated; " + "use self.session.gethookproxy() and self.session.isinitpath() instead. " +) + +STRICT_OPTION = PytestRemovedIn8Warning( + "The --strict option is deprecated, use --strict-markers instead." +) + +# This deprecation is never really meant to be removed. +PRIVATE = PytestDeprecationWarning("A private pytest class or function was used.") + +ARGUMENT_PERCENT_DEFAULT = PytestRemovedIn8Warning( + 'pytest now uses argparse. "%default" should be changed to "%(default)s"', +) + +ARGUMENT_TYPE_STR_CHOICE = UnformattedWarning( + PytestRemovedIn8Warning, + "`type` argument to addoption() is the string {typ!r}." + " For choices this is optional and can be omitted, " + " but when supplied should be a type (for example `str` or `int`)." + " (options: {names})", +) + +ARGUMENT_TYPE_STR = UnformattedWarning( + PytestRemovedIn8Warning, + "`type` argument to addoption() is the string {typ!r}, " + " but when supplied should be a type (for example `str` or `int`)." + " (options: {names})", +) + + +HOOK_LEGACY_PATH_ARG = UnformattedWarning( + PytestRemovedIn8Warning, + "The ({pylib_path_arg}: py.path.local) argument is deprecated, please use ({pathlib_path_arg}: pathlib.Path)\n" + "see https://docs.pytest.org/en/latest/deprecations.html" + "#py-path-local-arguments-for-hooks-replaced-with-pathlib-path", +) + +NODE_CTOR_FSPATH_ARG = UnformattedWarning( + PytestRemovedIn8Warning, + "The (fspath: py.path.local) argument to {node_type_name} is deprecated. " + "Please use the (path: pathlib.Path) argument instead.\n" + "See https://docs.pytest.org/en/latest/deprecations.html" + "#fspath-argument-for-node-constructors-replaced-with-pathlib-path", +) + +WARNS_NONE_ARG = PytestRemovedIn8Warning( + "Passing None has been deprecated.\n" + "See https://docs.pytest.org/en/latest/how-to/capture-warnings.html" + "#additional-use-cases-of-warnings-in-tests" + " for alternatives in common use cases." +) + +KEYWORD_MSG_ARG = UnformattedWarning( + PytestRemovedIn8Warning, + "pytest.{func}(msg=...) is now deprecated, use pytest.{func}(reason=...) instead", +) + +INSTANCE_COLLECTOR = PytestRemovedIn8Warning( + "The pytest.Instance collector type is deprecated and is no longer used. " + "See https://docs.pytest.org/en/latest/deprecations.html#the-pytest-instance-collector", +) +HOOK_LEGACY_MARKING = UnformattedWarning( + PytestDeprecationWarning, + "The hook{type} {fullname} uses old-style configuration options (marks or attributes).\n" + "Please use the pytest.hook{type}({hook_opts}) decorator instead\n" + " to configure the hooks.\n" + " See https://docs.pytest.org/en/latest/deprecations.html" + "#configuring-hook-specs-impls-using-markers", +) + +# You want to make some `__init__` or function "private". +# +# def my_private_function(some, args): +# ... +# +# Do this: +# +# def my_private_function(some, args, *, _ispytest: bool = False): +# check_ispytest(_ispytest) +# ... +# +# Change all internal/allowed calls to +# +# my_private_function(some, args, _ispytest=True) +# +# All other calls will get the default _ispytest=False and trigger +# the warning (possibly error in the future). + + +def check_ispytest(ispytest: bool) -> None: + if not ispytest: + warn(PRIVATE, stacklevel=3) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/doctest.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/doctest.py new file mode 100644 index 000000000..ca41a98ea --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/doctest.py @@ -0,0 +1,771 @@ +"""Discover and run doctests in modules and test files.""" +import bdb +import functools +import inspect +import os +import platform +import sys +import traceback +import types +import warnings +from contextlib import contextmanager +from pathlib import Path +from typing import Any +from typing import Callable +from typing import Dict +from typing import Generator +from typing import Iterable +from typing import List +from typing import Optional +from typing import Pattern +from typing import Sequence +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import Union + +from _pytest import outcomes +from _pytest._code.code import ExceptionInfo +from _pytest._code.code import ReprFileLocation +from _pytest._code.code import TerminalRepr +from _pytest._io import TerminalWriter +from _pytest.compat import safe_getattr +from _pytest.config import Config +from _pytest.config.argparsing import Parser +from _pytest.fixtures import fixture +from _pytest.fixtures import FixtureRequest +from _pytest.nodes import Collector +from _pytest.nodes import Item +from _pytest.outcomes import OutcomeException +from _pytest.outcomes import skip +from _pytest.pathlib import fnmatch_ex +from _pytest.pathlib import import_path +from _pytest.python import Module +from _pytest.python_api import approx +from _pytest.warning_types import PytestWarning + +if TYPE_CHECKING: + import doctest + +DOCTEST_REPORT_CHOICE_NONE = "none" +DOCTEST_REPORT_CHOICE_CDIFF = "cdiff" +DOCTEST_REPORT_CHOICE_NDIFF = "ndiff" +DOCTEST_REPORT_CHOICE_UDIFF = "udiff" +DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE = "only_first_failure" + +DOCTEST_REPORT_CHOICES = ( + DOCTEST_REPORT_CHOICE_NONE, + DOCTEST_REPORT_CHOICE_CDIFF, + DOCTEST_REPORT_CHOICE_NDIFF, + DOCTEST_REPORT_CHOICE_UDIFF, + DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE, +) + +# Lazy definition of runner class +RUNNER_CLASS = None +# Lazy definition of output checker class +CHECKER_CLASS: Optional[Type["doctest.OutputChecker"]] = None + + +def pytest_addoption(parser: Parser) -> None: + parser.addini( + "doctest_optionflags", + "Option flags for doctests", + type="args", + default=["ELLIPSIS"], + ) + parser.addini( + "doctest_encoding", "Encoding used for doctest files", default="utf-8" + ) + group = parser.getgroup("collect") + group.addoption( + "--doctest-modules", + action="store_true", + default=False, + help="Run doctests in all .py modules", + dest="doctestmodules", + ) + group.addoption( + "--doctest-report", + type=str.lower, + default="udiff", + help="Choose another output format for diffs on doctest failure", + choices=DOCTEST_REPORT_CHOICES, + dest="doctestreport", + ) + group.addoption( + "--doctest-glob", + action="append", + default=[], + metavar="pat", + help="Doctests file matching pattern, default: test*.txt", + dest="doctestglob", + ) + group.addoption( + "--doctest-ignore-import-errors", + action="store_true", + default=False, + help="Ignore doctest ImportErrors", + dest="doctest_ignore_import_errors", + ) + group.addoption( + "--doctest-continue-on-failure", + action="store_true", + default=False, + help="For a given doctest, continue to run after the first failure", + dest="doctest_continue_on_failure", + ) + + +def pytest_unconfigure() -> None: + global RUNNER_CLASS + + RUNNER_CLASS = None + + +def pytest_collect_file( + file_path: Path, + parent: Collector, +) -> Optional[Union["DoctestModule", "DoctestTextfile"]]: + config = parent.config + if file_path.suffix == ".py": + if config.option.doctestmodules and not any( + (_is_setup_py(file_path), _is_main_py(file_path)) + ): + mod: DoctestModule = DoctestModule.from_parent(parent, path=file_path) + return mod + elif _is_doctest(config, file_path, parent): + txt: DoctestTextfile = DoctestTextfile.from_parent(parent, path=file_path) + return txt + return None + + +def _is_setup_py(path: Path) -> bool: + if path.name != "setup.py": + return False + contents = path.read_bytes() + return b"setuptools" in contents or b"distutils" in contents + + +def _is_doctest(config: Config, path: Path, parent: Collector) -> bool: + if path.suffix in (".txt", ".rst") and parent.session.isinitpath(path): + return True + globs = config.getoption("doctestglob") or ["test*.txt"] + return any(fnmatch_ex(glob, path) for glob in globs) + + +def _is_main_py(path: Path) -> bool: + return path.name == "__main__.py" + + +class ReprFailDoctest(TerminalRepr): + def __init__( + self, reprlocation_lines: Sequence[Tuple[ReprFileLocation, Sequence[str]]] + ) -> None: + self.reprlocation_lines = reprlocation_lines + + def toterminal(self, tw: TerminalWriter) -> None: + for reprlocation, lines in self.reprlocation_lines: + for line in lines: + tw.line(line) + reprlocation.toterminal(tw) + + +class MultipleDoctestFailures(Exception): + def __init__(self, failures: Sequence["doctest.DocTestFailure"]) -> None: + super().__init__() + self.failures = failures + + +def _init_runner_class() -> Type["doctest.DocTestRunner"]: + import doctest + + class PytestDoctestRunner(doctest.DebugRunner): + """Runner to collect failures. + + Note that the out variable in this case is a list instead of a + stdout-like object. + """ + + def __init__( + self, + checker: Optional["doctest.OutputChecker"] = None, + verbose: Optional[bool] = None, + optionflags: int = 0, + continue_on_failure: bool = True, + ) -> None: + super().__init__(checker=checker, verbose=verbose, optionflags=optionflags) + self.continue_on_failure = continue_on_failure + + def report_failure( + self, + out, + test: "doctest.DocTest", + example: "doctest.Example", + got: str, + ) -> None: + failure = doctest.DocTestFailure(test, example, got) + if self.continue_on_failure: + out.append(failure) + else: + raise failure + + def report_unexpected_exception( + self, + out, + test: "doctest.DocTest", + example: "doctest.Example", + exc_info: Tuple[Type[BaseException], BaseException, types.TracebackType], + ) -> None: + if isinstance(exc_info[1], OutcomeException): + raise exc_info[1] + if isinstance(exc_info[1], bdb.BdbQuit): + outcomes.exit("Quitting debugger") + failure = doctest.UnexpectedException(test, example, exc_info) + if self.continue_on_failure: + out.append(failure) + else: + raise failure + + return PytestDoctestRunner + + +def _get_runner( + checker: Optional["doctest.OutputChecker"] = None, + verbose: Optional[bool] = None, + optionflags: int = 0, + continue_on_failure: bool = True, +) -> "doctest.DocTestRunner": + # We need this in order to do a lazy import on doctest + global RUNNER_CLASS + if RUNNER_CLASS is None: + RUNNER_CLASS = _init_runner_class() + # Type ignored because the continue_on_failure argument is only defined on + # PytestDoctestRunner, which is lazily defined so can't be used as a type. + return RUNNER_CLASS( # type: ignore + checker=checker, + verbose=verbose, + optionflags=optionflags, + continue_on_failure=continue_on_failure, + ) + + +class DoctestItem(Item): + def __init__( + self, + name: str, + parent: "Union[DoctestTextfile, DoctestModule]", + runner: Optional["doctest.DocTestRunner"] = None, + dtest: Optional["doctest.DocTest"] = None, + ) -> None: + super().__init__(name, parent) + self.runner = runner + self.dtest = dtest + self.obj = None + self.fixture_request: Optional[FixtureRequest] = None + + @classmethod + def from_parent( # type: ignore + cls, + parent: "Union[DoctestTextfile, DoctestModule]", + *, + name: str, + runner: "doctest.DocTestRunner", + dtest: "doctest.DocTest", + ): + # incompatible signature due to imposed limits on subclass + """The public named constructor.""" + return super().from_parent(name=name, parent=parent, runner=runner, dtest=dtest) + + def setup(self) -> None: + if self.dtest is not None: + self.fixture_request = _setup_fixtures(self) + globs = dict(getfixture=self.fixture_request.getfixturevalue) + for name, value in self.fixture_request.getfixturevalue( + "doctest_namespace" + ).items(): + globs[name] = value + self.dtest.globs.update(globs) + + def runtest(self) -> None: + assert self.dtest is not None + assert self.runner is not None + _check_all_skipped(self.dtest) + self._disable_output_capturing_for_darwin() + failures: List["doctest.DocTestFailure"] = [] + # Type ignored because we change the type of `out` from what + # doctest expects. + self.runner.run(self.dtest, out=failures) # type: ignore[arg-type] + if failures: + raise MultipleDoctestFailures(failures) + + def _disable_output_capturing_for_darwin(self) -> None: + """Disable output capturing. Otherwise, stdout is lost to doctest (#985).""" + if platform.system() != "Darwin": + return + capman = self.config.pluginmanager.getplugin("capturemanager") + if capman: + capman.suspend_global_capture(in_=True) + out, err = capman.read_global_capture() + sys.stdout.write(out) + sys.stderr.write(err) + + # TODO: Type ignored -- breaks Liskov Substitution. + def repr_failure( # type: ignore[override] + self, + excinfo: ExceptionInfo[BaseException], + ) -> Union[str, TerminalRepr]: + import doctest + + failures: Optional[ + Sequence[Union[doctest.DocTestFailure, doctest.UnexpectedException]] + ] = None + if isinstance( + excinfo.value, (doctest.DocTestFailure, doctest.UnexpectedException) + ): + failures = [excinfo.value] + elif isinstance(excinfo.value, MultipleDoctestFailures): + failures = excinfo.value.failures + + if failures is None: + return super().repr_failure(excinfo) + + reprlocation_lines = [] + for failure in failures: + example = failure.example + test = failure.test + filename = test.filename + if test.lineno is None: + lineno = None + else: + lineno = test.lineno + example.lineno + 1 + message = type(failure).__name__ + # TODO: ReprFileLocation doesn't expect a None lineno. + reprlocation = ReprFileLocation(filename, lineno, message) # type: ignore[arg-type] + checker = _get_checker() + report_choice = _get_report_choice(self.config.getoption("doctestreport")) + if lineno is not None: + assert failure.test.docstring is not None + lines = failure.test.docstring.splitlines(False) + # add line numbers to the left of the error message + assert test.lineno is not None + lines = [ + "%03d %s" % (i + test.lineno + 1, x) for (i, x) in enumerate(lines) + ] + # trim docstring error lines to 10 + lines = lines[max(example.lineno - 9, 0) : example.lineno + 1] + else: + lines = [ + "EXAMPLE LOCATION UNKNOWN, not showing all tests of that example" + ] + indent = ">>>" + for line in example.source.splitlines(): + lines.append(f"??? {indent} {line}") + indent = "..." + if isinstance(failure, doctest.DocTestFailure): + lines += checker.output_difference( + example, failure.got, report_choice + ).split("\n") + else: + inner_excinfo = ExceptionInfo.from_exc_info(failure.exc_info) + lines += ["UNEXPECTED EXCEPTION: %s" % repr(inner_excinfo.value)] + lines += [ + x.strip("\n") for x in traceback.format_exception(*failure.exc_info) + ] + reprlocation_lines.append((reprlocation, lines)) + return ReprFailDoctest(reprlocation_lines) + + def reportinfo(self) -> Tuple[Union["os.PathLike[str]", str], Optional[int], str]: + assert self.dtest is not None + return self.path, self.dtest.lineno, "[doctest] %s" % self.name + + +def _get_flag_lookup() -> Dict[str, int]: + import doctest + + return dict( + DONT_ACCEPT_TRUE_FOR_1=doctest.DONT_ACCEPT_TRUE_FOR_1, + DONT_ACCEPT_BLANKLINE=doctest.DONT_ACCEPT_BLANKLINE, + NORMALIZE_WHITESPACE=doctest.NORMALIZE_WHITESPACE, + ELLIPSIS=doctest.ELLIPSIS, + IGNORE_EXCEPTION_DETAIL=doctest.IGNORE_EXCEPTION_DETAIL, + COMPARISON_FLAGS=doctest.COMPARISON_FLAGS, + ALLOW_UNICODE=_get_allow_unicode_flag(), + ALLOW_BYTES=_get_allow_bytes_flag(), + NUMBER=_get_number_flag(), + ) + + +def get_optionflags(parent): + optionflags_str = parent.config.getini("doctest_optionflags") + flag_lookup_table = _get_flag_lookup() + flag_acc = 0 + for flag in optionflags_str: + flag_acc |= flag_lookup_table[flag] + return flag_acc + + +def _get_continue_on_failure(config): + continue_on_failure = config.getvalue("doctest_continue_on_failure") + if continue_on_failure: + # We need to turn off this if we use pdb since we should stop at + # the first failure. + if config.getvalue("usepdb"): + continue_on_failure = False + return continue_on_failure + + +class DoctestTextfile(Module): + obj = None + + def collect(self) -> Iterable[DoctestItem]: + import doctest + + # Inspired by doctest.testfile; ideally we would use it directly, + # but it doesn't support passing a custom checker. + encoding = self.config.getini("doctest_encoding") + text = self.path.read_text(encoding) + filename = str(self.path) + name = self.path.name + globs = {"__name__": "__main__"} + + optionflags = get_optionflags(self) + + runner = _get_runner( + verbose=False, + optionflags=optionflags, + checker=_get_checker(), + continue_on_failure=_get_continue_on_failure(self.config), + ) + + parser = doctest.DocTestParser() + test = parser.get_doctest(text, globs, name, filename, 0) + if test.examples: + yield DoctestItem.from_parent( + self, name=test.name, runner=runner, dtest=test + ) + + +def _check_all_skipped(test: "doctest.DocTest") -> None: + """Raise pytest.skip() if all examples in the given DocTest have the SKIP + option set.""" + import doctest + + all_skipped = all(x.options.get(doctest.SKIP, False) for x in test.examples) + if all_skipped: + skip("all tests skipped by +SKIP option") + + +def _is_mocked(obj: object) -> bool: + """Return if an object is possibly a mock object by checking the + existence of a highly improbable attribute.""" + return ( + safe_getattr(obj, "pytest_mock_example_attribute_that_shouldnt_exist", None) + is not None + ) + + +@contextmanager +def _patch_unwrap_mock_aware() -> Generator[None, None, None]: + """Context manager which replaces ``inspect.unwrap`` with a version + that's aware of mock objects and doesn't recurse into them.""" + real_unwrap = inspect.unwrap + + def _mock_aware_unwrap( + func: Callable[..., Any], *, stop: Optional[Callable[[Any], Any]] = None + ) -> Any: + try: + if stop is None or stop is _is_mocked: + return real_unwrap(func, stop=_is_mocked) + _stop = stop + return real_unwrap(func, stop=lambda obj: _is_mocked(obj) or _stop(func)) + except Exception as e: + warnings.warn( + "Got %r when unwrapping %r. This is usually caused " + "by a violation of Python's object protocol; see e.g. " + "https://github.com/pytest-dev/pytest/issues/5080" % (e, func), + PytestWarning, + ) + raise + + inspect.unwrap = _mock_aware_unwrap + try: + yield + finally: + inspect.unwrap = real_unwrap + + +class DoctestModule(Module): + def collect(self) -> Iterable[DoctestItem]: + import doctest + + class MockAwareDocTestFinder(doctest.DocTestFinder): + """A hackish doctest finder that overrides stdlib internals to fix a stdlib bug. + + https://github.com/pytest-dev/pytest/issues/3456 + https://bugs.python.org/issue25532 + """ + + def _find_lineno(self, obj, source_lines): + """Doctest code does not take into account `@property`, this + is a hackish way to fix it. https://bugs.python.org/issue17446 + + Wrapped Doctests will need to be unwrapped so the correct + line number is returned. This will be reported upstream. #8796 + """ + if isinstance(obj, property): + obj = getattr(obj, "fget", obj) + + if hasattr(obj, "__wrapped__"): + # Get the main obj in case of it being wrapped + obj = inspect.unwrap(obj) + + # Type ignored because this is a private function. + return super()._find_lineno( # type:ignore[misc] + obj, + source_lines, + ) + + def _find( + self, tests, obj, name, module, source_lines, globs, seen + ) -> None: + if _is_mocked(obj): + return + with _patch_unwrap_mock_aware(): + # Type ignored because this is a private function. + super()._find( # type:ignore[misc] + tests, obj, name, module, source_lines, globs, seen + ) + + if sys.version_info < (3, 13): + + def _from_module(self, module, object): + """`cached_property` objects are never considered a part + of the 'current module'. As such they are skipped by doctest. + Here we override `_from_module` to check the underlying + function instead. https://github.com/python/cpython/issues/107995 + """ + if hasattr(functools, "cached_property") and isinstance( + object, functools.cached_property + ): + object = object.func + + # Type ignored because this is a private function. + return super()._from_module(module, object) # type: ignore[misc] + + else: # pragma: no cover + pass + + if self.path.name == "conftest.py": + module = self.config.pluginmanager._importconftest( + self.path, + self.config.getoption("importmode"), + rootpath=self.config.rootpath, + ) + else: + try: + module = import_path( + self.path, + root=self.config.rootpath, + mode=self.config.getoption("importmode"), + ) + except ImportError: + if self.config.getvalue("doctest_ignore_import_errors"): + skip("unable to import module %r" % self.path) + else: + raise + # Uses internal doctest module parsing mechanism. + finder = MockAwareDocTestFinder() + optionflags = get_optionflags(self) + runner = _get_runner( + verbose=False, + optionflags=optionflags, + checker=_get_checker(), + continue_on_failure=_get_continue_on_failure(self.config), + ) + + for test in finder.find(module, module.__name__): + if test.examples: # skip empty doctests + yield DoctestItem.from_parent( + self, name=test.name, runner=runner, dtest=test + ) + + +def _setup_fixtures(doctest_item: DoctestItem) -> FixtureRequest: + """Used by DoctestTextfile and DoctestItem to setup fixture information.""" + + def func() -> None: + pass + + doctest_item.funcargs = {} # type: ignore[attr-defined] + fm = doctest_item.session._fixturemanager + doctest_item._fixtureinfo = fm.getfixtureinfo( # type: ignore[attr-defined] + node=doctest_item, func=func, cls=None, funcargs=False + ) + fixture_request = FixtureRequest(doctest_item, _ispytest=True) + fixture_request._fillfixtures() + return fixture_request + + +def _init_checker_class() -> Type["doctest.OutputChecker"]: + import doctest + import re + + class LiteralsOutputChecker(doctest.OutputChecker): + # Based on doctest_nose_plugin.py from the nltk project + # (https://github.com/nltk/nltk) and on the "numtest" doctest extension + # by Sebastien Boisgerault (https://github.com/boisgera/numtest). + + _unicode_literal_re = re.compile(r"(\W|^)[uU]([rR]?[\'\"])", re.UNICODE) + _bytes_literal_re = re.compile(r"(\W|^)[bB]([rR]?[\'\"])", re.UNICODE) + _number_re = re.compile( + r""" + (?P + (?P + (?P [+-]?\d*)\.(?P\d+) + | + (?P [+-]?\d+)\. + ) + (?: + [Ee] + (?P [+-]?\d+) + )? + | + (?P [+-]?\d+) + (?: + [Ee] + (?P [+-]?\d+) + ) + ) + """, + re.VERBOSE, + ) + + def check_output(self, want: str, got: str, optionflags: int) -> bool: + if super().check_output(want, got, optionflags): + return True + + allow_unicode = optionflags & _get_allow_unicode_flag() + allow_bytes = optionflags & _get_allow_bytes_flag() + allow_number = optionflags & _get_number_flag() + + if not allow_unicode and not allow_bytes and not allow_number: + return False + + def remove_prefixes(regex: Pattern[str], txt: str) -> str: + return re.sub(regex, r"\1\2", txt) + + if allow_unicode: + want = remove_prefixes(self._unicode_literal_re, want) + got = remove_prefixes(self._unicode_literal_re, got) + + if allow_bytes: + want = remove_prefixes(self._bytes_literal_re, want) + got = remove_prefixes(self._bytes_literal_re, got) + + if allow_number: + got = self._remove_unwanted_precision(want, got) + + return super().check_output(want, got, optionflags) + + def _remove_unwanted_precision(self, want: str, got: str) -> str: + wants = list(self._number_re.finditer(want)) + gots = list(self._number_re.finditer(got)) + if len(wants) != len(gots): + return got + offset = 0 + for w, g in zip(wants, gots): + fraction: Optional[str] = w.group("fraction") + exponent: Optional[str] = w.group("exponent1") + if exponent is None: + exponent = w.group("exponent2") + precision = 0 if fraction is None else len(fraction) + if exponent is not None: + precision -= int(exponent) + if float(w.group()) == approx(float(g.group()), abs=10**-precision): + # They're close enough. Replace the text we actually + # got with the text we want, so that it will match when we + # check the string literally. + got = ( + got[: g.start() + offset] + w.group() + got[g.end() + offset :] + ) + offset += w.end() - w.start() - (g.end() - g.start()) + return got + + return LiteralsOutputChecker + + +def _get_checker() -> "doctest.OutputChecker": + """Return a doctest.OutputChecker subclass that supports some + additional options: + + * ALLOW_UNICODE and ALLOW_BYTES options to ignore u'' and b'' + prefixes (respectively) in string literals. Useful when the same + doctest should run in Python 2 and Python 3. + + * NUMBER to ignore floating-point differences smaller than the + precision of the literal number in the doctest. + + An inner class is used to avoid importing "doctest" at the module + level. + """ + global CHECKER_CLASS + if CHECKER_CLASS is None: + CHECKER_CLASS = _init_checker_class() + return CHECKER_CLASS() + + +def _get_allow_unicode_flag() -> int: + """Register and return the ALLOW_UNICODE flag.""" + import doctest + + return doctest.register_optionflag("ALLOW_UNICODE") + + +def _get_allow_bytes_flag() -> int: + """Register and return the ALLOW_BYTES flag.""" + import doctest + + return doctest.register_optionflag("ALLOW_BYTES") + + +def _get_number_flag() -> int: + """Register and return the NUMBER flag.""" + import doctest + + return doctest.register_optionflag("NUMBER") + + +def _get_report_choice(key: str) -> int: + """Return the actual `doctest` module flag value. + + We want to do it as late as possible to avoid importing `doctest` and all + its dependencies when parsing options, as it adds overhead and breaks tests. + """ + import doctest + + return { + DOCTEST_REPORT_CHOICE_UDIFF: doctest.REPORT_UDIFF, + DOCTEST_REPORT_CHOICE_CDIFF: doctest.REPORT_CDIFF, + DOCTEST_REPORT_CHOICE_NDIFF: doctest.REPORT_NDIFF, + DOCTEST_REPORT_CHOICE_ONLY_FIRST_FAILURE: doctest.REPORT_ONLY_FIRST_FAILURE, + DOCTEST_REPORT_CHOICE_NONE: 0, + }[key] + + +@fixture(scope="session") +def doctest_namespace() -> Dict[str, Any]: + """Fixture that returns a :py:class:`dict` that will be injected into the + namespace of doctests. + + Usually this fixture is used in conjunction with another ``autouse`` fixture: + + .. code-block:: python + + @pytest.fixture(autouse=True) + def add_np(doctest_namespace): + doctest_namespace["np"] = numpy + + For more details: :ref:`doctest_namespace`. + """ + return dict() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/faulthandler.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/faulthandler.py new file mode 100644 index 000000000..36040bfff --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/faulthandler.py @@ -0,0 +1,94 @@ +import os +import sys +from typing import Generator + +import pytest +from _pytest.config import Config +from _pytest.config.argparsing import Parser +from _pytest.nodes import Item +from _pytest.stash import StashKey + + +fault_handler_stderr_fd_key = StashKey[int]() +fault_handler_originally_enabled_key = StashKey[bool]() + + +def pytest_addoption(parser: Parser) -> None: + help = ( + "Dump the traceback of all threads if a test takes " + "more than TIMEOUT seconds to finish" + ) + parser.addini("faulthandler_timeout", help, default=0.0) + + +def pytest_configure(config: Config) -> None: + import faulthandler + + config.stash[fault_handler_stderr_fd_key] = os.dup(get_stderr_fileno()) + config.stash[fault_handler_originally_enabled_key] = faulthandler.is_enabled() + faulthandler.enable(file=config.stash[fault_handler_stderr_fd_key]) + + +def pytest_unconfigure(config: Config) -> None: + import faulthandler + + faulthandler.disable() + # Close the dup file installed during pytest_configure. + if fault_handler_stderr_fd_key in config.stash: + os.close(config.stash[fault_handler_stderr_fd_key]) + del config.stash[fault_handler_stderr_fd_key] + if config.stash.get(fault_handler_originally_enabled_key, False): + # Re-enable the faulthandler if it was originally enabled. + faulthandler.enable(file=get_stderr_fileno()) + + +def get_stderr_fileno() -> int: + try: + fileno = sys.stderr.fileno() + # The Twisted Logger will return an invalid file descriptor since it is not backed + # by an FD. So, let's also forward this to the same code path as with pytest-xdist. + if fileno == -1: + raise AttributeError() + return fileno + except (AttributeError, ValueError): + # pytest-xdist monkeypatches sys.stderr with an object that is not an actual file. + # https://docs.python.org/3/library/faulthandler.html#issue-with-file-descriptors + # This is potentially dangerous, but the best we can do. + return sys.__stderr__.fileno() + + +def get_timeout_config_value(config: Config) -> float: + return float(config.getini("faulthandler_timeout") or 0.0) + + +@pytest.hookimpl(hookwrapper=True, trylast=True) +def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]: + timeout = get_timeout_config_value(item.config) + if timeout > 0: + import faulthandler + + stderr = item.config.stash[fault_handler_stderr_fd_key] + faulthandler.dump_traceback_later(timeout, file=stderr) + try: + yield + finally: + faulthandler.cancel_dump_traceback_later() + else: + yield + + +@pytest.hookimpl(tryfirst=True) +def pytest_enter_pdb() -> None: + """Cancel any traceback dumping due to timeout before entering pdb.""" + import faulthandler + + faulthandler.cancel_dump_traceback_later() + + +@pytest.hookimpl(tryfirst=True) +def pytest_exception_interact() -> None: + """Cancel any traceback dumping due to an interactive exception being + raised.""" + import faulthandler + + faulthandler.cancel_dump_traceback_later() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/fixtures.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/fixtures.py new file mode 100644 index 000000000..0462504ef --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/fixtures.py @@ -0,0 +1,1713 @@ +import dataclasses +import functools +import inspect +import os +import sys +import warnings +from collections import defaultdict +from collections import deque +from contextlib import suppress +from pathlib import Path +from types import TracebackType +from typing import Any +from typing import Callable +from typing import cast +from typing import Dict +from typing import Generator +from typing import Generic +from typing import Iterable +from typing import Iterator +from typing import List +from typing import MutableMapping +from typing import NoReturn +from typing import Optional +from typing import Sequence +from typing import Set +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import TypeVar +from typing import Union + +import _pytest +from _pytest import nodes +from _pytest._code import getfslineno +from _pytest._code.code import FormattedExcinfo +from _pytest._code.code import TerminalRepr +from _pytest._io import TerminalWriter +from _pytest.compat import _format_args +from _pytest.compat import _PytestWrapper +from _pytest.compat import assert_never +from _pytest.compat import final +from _pytest.compat import get_real_func +from _pytest.compat import get_real_method +from _pytest.compat import getfuncargnames +from _pytest.compat import getimfunc +from _pytest.compat import getlocation +from _pytest.compat import is_generator +from _pytest.compat import NOTSET +from _pytest.compat import NotSetType +from _pytest.compat import overload +from _pytest.compat import safe_getattr +from _pytest.config import _PluggyPlugin +from _pytest.config import Config +from _pytest.config.argparsing import Parser +from _pytest.deprecated import check_ispytest +from _pytest.deprecated import YIELD_FIXTURE +from _pytest.mark import Mark +from _pytest.mark import ParameterSet +from _pytest.mark.structures import MarkDecorator +from _pytest.outcomes import fail +from _pytest.outcomes import skip +from _pytest.outcomes import TEST_OUTCOME +from _pytest.pathlib import absolutepath +from _pytest.pathlib import bestrelpath +from _pytest.scope import HIGH_SCOPES +from _pytest.scope import Scope +from _pytest.stash import StashKey + + +if TYPE_CHECKING: + from typing import Deque + + from _pytest.scope import _ScopeName + from _pytest.main import Session + from _pytest.python import CallSpec2 + from _pytest.python import Metafunc + + +# The value of the fixture -- return/yield of the fixture function (type variable). +FixtureValue = TypeVar("FixtureValue") +# The type of the fixture function (type variable). +FixtureFunction = TypeVar("FixtureFunction", bound=Callable[..., object]) +# The type of a fixture function (type alias generic in fixture value). +_FixtureFunc = Union[ + Callable[..., FixtureValue], Callable[..., Generator[FixtureValue, None, None]] +] +# The type of FixtureDef.cached_result (type alias generic in fixture value). +_FixtureCachedResult = Union[ + Tuple[ + # The result. + FixtureValue, + # Cache key. + object, + None, + ], + Tuple[ + None, + # Cache key. + object, + # Exc info if raised. + Tuple[Type[BaseException], BaseException, TracebackType], + ], +] + + +@dataclasses.dataclass(frozen=True) +class PseudoFixtureDef(Generic[FixtureValue]): + cached_result: "_FixtureCachedResult[FixtureValue]" + _scope: Scope + + +def pytest_sessionstart(session: "Session") -> None: + session._fixturemanager = FixtureManager(session) + + +def get_scope_package( + node: nodes.Item, + fixturedef: "FixtureDef[object]", +) -> Optional[Union[nodes.Item, nodes.Collector]]: + from _pytest.python import Package + + current: Optional[Union[nodes.Item, nodes.Collector]] = node + fixture_package_name = "{}/{}".format(fixturedef.baseid, "__init__.py") + while current and ( + not isinstance(current, Package) or fixture_package_name != current.nodeid + ): + current = current.parent # type: ignore[assignment] + if current is None: + return node.session + return current + + +def get_scope_node( + node: nodes.Node, scope: Scope +) -> Optional[Union[nodes.Item, nodes.Collector]]: + import _pytest.python + + if scope is Scope.Function: + return node.getparent(nodes.Item) + elif scope is Scope.Class: + return node.getparent(_pytest.python.Class) + elif scope is Scope.Module: + return node.getparent(_pytest.python.Module) + elif scope is Scope.Package: + return node.getparent(_pytest.python.Package) + elif scope is Scope.Session: + return node.getparent(_pytest.main.Session) + else: + assert_never(scope) + + +# Used for storing artificial fixturedefs for direct parametrization. +name2pseudofixturedef_key = StashKey[Dict[str, "FixtureDef[Any]"]]() + + +def add_funcarg_pseudo_fixture_def( + collector: nodes.Collector, metafunc: "Metafunc", fixturemanager: "FixtureManager" +) -> None: + # This function will transform all collected calls to functions + # if they use direct funcargs (i.e. direct parametrization) + # because we want later test execution to be able to rely on + # an existing FixtureDef structure for all arguments. + # XXX we can probably avoid this algorithm if we modify CallSpec2 + # to directly care for creating the fixturedefs within its methods. + if not metafunc._calls[0].funcargs: + # This function call does not have direct parametrization. + return + # Collect funcargs of all callspecs into a list of values. + arg2params: Dict[str, List[object]] = {} + arg2scope: Dict[str, Scope] = {} + for callspec in metafunc._calls: + for argname, argvalue in callspec.funcargs.items(): + assert argname not in callspec.params + callspec.params[argname] = argvalue + arg2params_list = arg2params.setdefault(argname, []) + callspec.indices[argname] = len(arg2params_list) + arg2params_list.append(argvalue) + if argname not in arg2scope: + scope = callspec._arg2scope.get(argname, Scope.Function) + arg2scope[argname] = scope + callspec.funcargs.clear() + + # Register artificial FixtureDef's so that later at test execution + # time we can rely on a proper FixtureDef to exist for fixture setup. + arg2fixturedefs = metafunc._arg2fixturedefs + for argname, valuelist in arg2params.items(): + # If we have a scope that is higher than function, we need + # to make sure we only ever create an according fixturedef on + # a per-scope basis. We thus store and cache the fixturedef on the + # node related to the scope. + scope = arg2scope[argname] + node = None + if scope is not Scope.Function: + node = get_scope_node(collector, scope) + if node is None: + assert scope is Scope.Class and isinstance( + collector, _pytest.python.Module + ) + # Use module-level collector for class-scope (for now). + node = collector + if node is None: + name2pseudofixturedef = None + else: + default: Dict[str, FixtureDef[Any]] = {} + name2pseudofixturedef = node.stash.setdefault( + name2pseudofixturedef_key, default + ) + if name2pseudofixturedef is not None and argname in name2pseudofixturedef: + arg2fixturedefs[argname] = [name2pseudofixturedef[argname]] + else: + fixturedef = FixtureDef( + fixturemanager=fixturemanager, + baseid="", + argname=argname, + func=get_direct_param_fixture_func, + scope=arg2scope[argname], + params=valuelist, + unittest=False, + ids=None, + ) + arg2fixturedefs[argname] = [fixturedef] + if name2pseudofixturedef is not None: + name2pseudofixturedef[argname] = fixturedef + + +def getfixturemarker(obj: object) -> Optional["FixtureFunctionMarker"]: + """Return fixturemarker or None if it doesn't exist or raised + exceptions.""" + return cast( + Optional[FixtureFunctionMarker], + safe_getattr(obj, "_pytestfixturefunction", None), + ) + + +# Parametrized fixture key, helper alias for code below. +_Key = Tuple[object, ...] + + +def get_parametrized_fixture_keys(item: nodes.Item, scope: Scope) -> Iterator[_Key]: + """Return list of keys for all parametrized arguments which match + the specified scope.""" + assert scope is not Scope.Function + try: + callspec = item.callspec # type: ignore[attr-defined] + except AttributeError: + pass + else: + cs: CallSpec2 = callspec + # cs.indices.items() is random order of argnames. Need to + # sort this so that different calls to + # get_parametrized_fixture_keys will be deterministic. + for argname, param_index in sorted(cs.indices.items()): + if cs._arg2scope[argname] != scope: + continue + if scope is Scope.Session: + key: _Key = (argname, param_index) + elif scope is Scope.Package: + key = (argname, param_index, item.path.parent) + elif scope is Scope.Module: + key = (argname, param_index, item.path) + elif scope is Scope.Class: + item_cls = item.cls # type: ignore[attr-defined] + key = (argname, param_index, item.path, item_cls) + else: + assert_never(scope) + yield key + + +# Algorithm for sorting on a per-parametrized resource setup basis. +# It is called for Session scope first and performs sorting +# down to the lower scopes such as to minimize number of "high scope" +# setups and teardowns. + + +def reorder_items(items: Sequence[nodes.Item]) -> List[nodes.Item]: + argkeys_cache: Dict[Scope, Dict[nodes.Item, Dict[_Key, None]]] = {} + items_by_argkey: Dict[Scope, Dict[_Key, Deque[nodes.Item]]] = {} + for scope in HIGH_SCOPES: + d: Dict[nodes.Item, Dict[_Key, None]] = {} + argkeys_cache[scope] = d + item_d: Dict[_Key, Deque[nodes.Item]] = defaultdict(deque) + items_by_argkey[scope] = item_d + for item in items: + keys = dict.fromkeys(get_parametrized_fixture_keys(item, scope), None) + if keys: + d[item] = keys + for key in keys: + item_d[key].append(item) + items_dict = dict.fromkeys(items, None) + return list( + reorder_items_atscope(items_dict, argkeys_cache, items_by_argkey, Scope.Session) + ) + + +def fix_cache_order( + item: nodes.Item, + argkeys_cache: Dict[Scope, Dict[nodes.Item, Dict[_Key, None]]], + items_by_argkey: Dict[Scope, Dict[_Key, "Deque[nodes.Item]"]], +) -> None: + for scope in HIGH_SCOPES: + for key in argkeys_cache[scope].get(item, []): + items_by_argkey[scope][key].appendleft(item) + + +def reorder_items_atscope( + items: Dict[nodes.Item, None], + argkeys_cache: Dict[Scope, Dict[nodes.Item, Dict[_Key, None]]], + items_by_argkey: Dict[Scope, Dict[_Key, "Deque[nodes.Item]"]], + scope: Scope, +) -> Dict[nodes.Item, None]: + if scope is Scope.Function or len(items) < 3: + return items + ignore: Set[Optional[_Key]] = set() + items_deque = deque(items) + items_done: Dict[nodes.Item, None] = {} + scoped_items_by_argkey = items_by_argkey[scope] + scoped_argkeys_cache = argkeys_cache[scope] + while items_deque: + no_argkey_group: Dict[nodes.Item, None] = {} + slicing_argkey = None + while items_deque: + item = items_deque.popleft() + if item in items_done or item in no_argkey_group: + continue + argkeys = dict.fromkeys( + (k for k in scoped_argkeys_cache.get(item, []) if k not in ignore), None + ) + if not argkeys: + no_argkey_group[item] = None + else: + slicing_argkey, _ = argkeys.popitem() + # We don't have to remove relevant items from later in the + # deque because they'll just be ignored. + matching_items = [ + i for i in scoped_items_by_argkey[slicing_argkey] if i in items + ] + for i in reversed(matching_items): + fix_cache_order(i, argkeys_cache, items_by_argkey) + items_deque.appendleft(i) + break + if no_argkey_group: + no_argkey_group = reorder_items_atscope( + no_argkey_group, argkeys_cache, items_by_argkey, scope.next_lower() + ) + for item in no_argkey_group: + items_done[item] = None + ignore.add(slicing_argkey) + return items_done + + +def get_direct_param_fixture_func(request: "FixtureRequest") -> Any: + return request.param + + +@dataclasses.dataclass +class FuncFixtureInfo: + __slots__ = ("argnames", "initialnames", "names_closure", "name2fixturedefs") + + # Original function argument names. + argnames: Tuple[str, ...] + # Argnames that function immediately requires. These include argnames + + # fixture names specified via usefixtures and via autouse=True in fixture + # definitions. + initialnames: Tuple[str, ...] + names_closure: List[str] + name2fixturedefs: Dict[str, Sequence["FixtureDef[Any]"]] + + def prune_dependency_tree(self) -> None: + """Recompute names_closure from initialnames and name2fixturedefs. + + Can only reduce names_closure, which means that the new closure will + always be a subset of the old one. The order is preserved. + + This method is needed because direct parametrization may shadow some + of the fixtures that were included in the originally built dependency + tree. In this way the dependency tree can get pruned, and the closure + of argnames may get reduced. + """ + closure: Set[str] = set() + working_set = set(self.initialnames) + while working_set: + argname = working_set.pop() + # Argname may be smth not included in the original names_closure, + # in which case we ignore it. This currently happens with pseudo + # FixtureDefs which wrap 'get_direct_param_fixture_func(request)'. + # So they introduce the new dependency 'request' which might have + # been missing in the original tree (closure). + if argname not in closure and argname in self.names_closure: + closure.add(argname) + if argname in self.name2fixturedefs: + working_set.update(self.name2fixturedefs[argname][-1].argnames) + + self.names_closure[:] = sorted(closure, key=self.names_closure.index) + + +class FixtureRequest: + """A request for a fixture from a test or fixture function. + + A request object gives access to the requesting test context and has + an optional ``param`` attribute in case the fixture is parametrized + indirectly. + """ + + def __init__(self, pyfuncitem, *, _ispytest: bool = False) -> None: + check_ispytest(_ispytest) + self._pyfuncitem = pyfuncitem + #: Fixture for which this request is being performed. + self.fixturename: Optional[str] = None + self._scope = Scope.Function + self._fixture_defs: Dict[str, FixtureDef[Any]] = {} + fixtureinfo: FuncFixtureInfo = pyfuncitem._fixtureinfo + self._arg2fixturedefs = fixtureinfo.name2fixturedefs.copy() + self._arg2index: Dict[str, int] = {} + self._fixturemanager: FixtureManager = pyfuncitem.session._fixturemanager + # Notes on the type of `param`: + # -`request.param` is only defined in parametrized fixtures, and will raise + # AttributeError otherwise. Python typing has no notion of "undefined", so + # this cannot be reflected in the type. + # - Technically `param` is only (possibly) defined on SubRequest, not + # FixtureRequest, but the typing of that is still in flux so this cheats. + # - In the future we might consider using a generic for the param type, but + # for now just using Any. + self.param: Any + + @property + def scope(self) -> "_ScopeName": + """Scope string, one of "function", "class", "module", "package", "session".""" + return self._scope.value + + @property + def fixturenames(self) -> List[str]: + """Names of all active fixtures in this request.""" + result = list(self._pyfuncitem._fixtureinfo.names_closure) + result.extend(set(self._fixture_defs).difference(result)) + return result + + @property + def node(self): + """Underlying collection node (depends on current request scope).""" + scope = self._scope + if scope is Scope.Function: + # This might also be a non-function Item despite its attribute name. + node: Optional[Union[nodes.Item, nodes.Collector]] = self._pyfuncitem + elif scope is Scope.Package: + # FIXME: _fixturedef is not defined on FixtureRequest (this class), + # but on FixtureRequest (a subclass). + node = get_scope_package(self._pyfuncitem, self._fixturedef) # type: ignore[attr-defined] + else: + node = get_scope_node(self._pyfuncitem, scope) + if node is None and scope is Scope.Class: + # Fallback to function item itself. + node = self._pyfuncitem + assert node, 'Could not obtain a node for scope "{}" for function {!r}'.format( + scope, self._pyfuncitem + ) + return node + + def _getnextfixturedef(self, argname: str) -> "FixtureDef[Any]": + fixturedefs = self._arg2fixturedefs.get(argname, None) + if fixturedefs is None: + # We arrive here because of a dynamic call to + # getfixturevalue(argname) usage which was naturally + # not known at parsing/collection time. + assert self._pyfuncitem.parent is not None + parentid = self._pyfuncitem.parent.nodeid + fixturedefs = self._fixturemanager.getfixturedefs(argname, parentid) + # TODO: Fix this type ignore. Either add assert or adjust types. + # Can this be None here? + self._arg2fixturedefs[argname] = fixturedefs # type: ignore[assignment] + # fixturedefs list is immutable so we maintain a decreasing index. + index = self._arg2index.get(argname, 0) - 1 + if fixturedefs is None or (-index > len(fixturedefs)): + raise FixtureLookupError(argname, self) + self._arg2index[argname] = index + return fixturedefs[index] + + @property + def config(self) -> Config: + """The pytest config object associated with this request.""" + return self._pyfuncitem.config # type: ignore[no-any-return] + + @property + def function(self): + """Test function object if the request has a per-function scope.""" + if self.scope != "function": + raise AttributeError( + f"function not available in {self.scope}-scoped context" + ) + return self._pyfuncitem.obj + + @property + def cls(self): + """Class (can be None) where the test function was collected.""" + if self.scope not in ("class", "function"): + raise AttributeError(f"cls not available in {self.scope}-scoped context") + clscol = self._pyfuncitem.getparent(_pytest.python.Class) + if clscol: + return clscol.obj + + @property + def instance(self): + """Instance (can be None) on which test function was collected.""" + # unittest support hack, see _pytest.unittest.TestCaseFunction. + try: + return self._pyfuncitem._testcase + except AttributeError: + function = getattr(self, "function", None) + return getattr(function, "__self__", None) + + @property + def module(self): + """Python module object where the test function was collected.""" + if self.scope not in ("function", "class", "module"): + raise AttributeError(f"module not available in {self.scope}-scoped context") + return self._pyfuncitem.getparent(_pytest.python.Module).obj + + @property + def path(self) -> Path: + """Path where the test function was collected.""" + if self.scope not in ("function", "class", "module", "package"): + raise AttributeError(f"path not available in {self.scope}-scoped context") + # TODO: Remove ignore once _pyfuncitem is properly typed. + return self._pyfuncitem.path # type: ignore + + @property + def keywords(self) -> MutableMapping[str, Any]: + """Keywords/markers dictionary for the underlying node.""" + node: nodes.Node = self.node + return node.keywords + + @property + def session(self) -> "Session": + """Pytest session object.""" + return self._pyfuncitem.session # type: ignore[no-any-return] + + def addfinalizer(self, finalizer: Callable[[], object]) -> None: + """Add finalizer/teardown function to be called without arguments after + the last test within the requesting test context finished execution.""" + # XXX usually this method is shadowed by fixturedef specific ones. + self.node.addfinalizer(finalizer) + + def applymarker(self, marker: Union[str, MarkDecorator]) -> None: + """Apply a marker to a single test function invocation. + + This method is useful if you don't want to have a keyword/marker + on all function invocations. + + :param marker: + An object created by a call to ``pytest.mark.NAME(...)``. + """ + self.node.add_marker(marker) + + def raiseerror(self, msg: Optional[str]) -> NoReturn: + """Raise a FixtureLookupError exception. + + :param msg: + An optional custom error message. + """ + raise self._fixturemanager.FixtureLookupError(None, self, msg) + + def _fillfixtures(self) -> None: + item = self._pyfuncitem + fixturenames = getattr(item, "fixturenames", self.fixturenames) + for argname in fixturenames: + if argname not in item.funcargs: + item.funcargs[argname] = self.getfixturevalue(argname) + + def getfixturevalue(self, argname: str) -> Any: + """Dynamically run a named fixture function. + + Declaring fixtures via function argument is recommended where possible. + But if you can only decide whether to use another fixture at test + setup time, you may use this function to retrieve it inside a fixture + or test function body. + + This method can be used during the test setup phase or the test run + phase, but during the test teardown phase a fixture's value may not + be available. + + :param argname: + The fixture name. + :raises pytest.FixtureLookupError: + If the given fixture could not be found. + """ + fixturedef = self._get_active_fixturedef(argname) + assert fixturedef.cached_result is not None, ( + f'The fixture value for "{argname}" is not available. ' + "This can happen when the fixture has already been torn down." + ) + return fixturedef.cached_result[0] + + def _get_active_fixturedef( + self, argname: str + ) -> Union["FixtureDef[object]", PseudoFixtureDef[object]]: + try: + return self._fixture_defs[argname] + except KeyError: + try: + fixturedef = self._getnextfixturedef(argname) + except FixtureLookupError: + if argname == "request": + cached_result = (self, [0], None) + return PseudoFixtureDef(cached_result, Scope.Function) + raise + # Remove indent to prevent the python3 exception + # from leaking into the call. + self._compute_fixture_value(fixturedef) + self._fixture_defs[argname] = fixturedef + return fixturedef + + def _get_fixturestack(self) -> List["FixtureDef[Any]"]: + current = self + values: List[FixtureDef[Any]] = [] + while isinstance(current, SubRequest): + values.append(current._fixturedef) # type: ignore[has-type] + current = current._parent_request + values.reverse() + return values + + def _compute_fixture_value(self, fixturedef: "FixtureDef[object]") -> None: + """Create a SubRequest based on "self" and call the execute method + of the given FixtureDef object. + + This will force the FixtureDef object to throw away any previous + results and compute a new fixture value, which will be stored into + the FixtureDef object itself. + """ + # prepare a subrequest object before calling fixture function + # (latter managed by fixturedef) + argname = fixturedef.argname + funcitem = self._pyfuncitem + scope = fixturedef._scope + try: + callspec = funcitem.callspec + except AttributeError: + callspec = None + if callspec is not None and argname in callspec.params: + param = callspec.params[argname] + param_index = callspec.indices[argname] + # If a parametrize invocation set a scope it will override + # the static scope defined with the fixture function. + with suppress(KeyError): + scope = callspec._arg2scope[argname] + else: + param = NOTSET + param_index = 0 + has_params = fixturedef.params is not None + fixtures_not_supported = getattr(funcitem, "nofuncargs", False) + if has_params and fixtures_not_supported: + msg = ( + "{name} does not support fixtures, maybe unittest.TestCase subclass?\n" + "Node id: {nodeid}\n" + "Function type: {typename}" + ).format( + name=funcitem.name, + nodeid=funcitem.nodeid, + typename=type(funcitem).__name__, + ) + fail(msg, pytrace=False) + if has_params: + frame = inspect.stack()[3] + frameinfo = inspect.getframeinfo(frame[0]) + source_path = absolutepath(frameinfo.filename) + source_lineno = frameinfo.lineno + try: + source_path_str = str( + source_path.relative_to(funcitem.config.rootpath) + ) + except ValueError: + source_path_str = str(source_path) + msg = ( + "The requested fixture has no parameter defined for test:\n" + " {}\n\n" + "Requested fixture '{}' defined in:\n{}" + "\n\nRequested here:\n{}:{}".format( + funcitem.nodeid, + fixturedef.argname, + getlocation(fixturedef.func, funcitem.config.rootpath), + source_path_str, + source_lineno, + ) + ) + fail(msg, pytrace=False) + + subrequest = SubRequest( + self, scope, param, param_index, fixturedef, _ispytest=True + ) + + # Check if a higher-level scoped fixture accesses a lower level one. + subrequest._check_scope(argname, self._scope, scope) + try: + # Call the fixture function. + fixturedef.execute(request=subrequest) + finally: + self._schedule_finalizers(fixturedef, subrequest) + + def _schedule_finalizers( + self, fixturedef: "FixtureDef[object]", subrequest: "SubRequest" + ) -> None: + # If fixture function failed it might have registered finalizers. + subrequest.node.addfinalizer(lambda: fixturedef.finish(request=subrequest)) + + def _check_scope( + self, + argname: str, + invoking_scope: Scope, + requested_scope: Scope, + ) -> None: + if argname == "request": + return + if invoking_scope > requested_scope: + # Try to report something helpful. + text = "\n".join(self._factorytraceback()) + fail( + f"ScopeMismatch: You tried to access the {requested_scope.value} scoped " + f"fixture {argname} with a {invoking_scope.value} scoped request object, " + f"involved factories:\n{text}", + pytrace=False, + ) + + def _factorytraceback(self) -> List[str]: + lines = [] + for fixturedef in self._get_fixturestack(): + factory = fixturedef.func + fs, lineno = getfslineno(factory) + if isinstance(fs, Path): + session: Session = self._pyfuncitem.session + p = bestrelpath(session.path, fs) + else: + p = fs + args = _format_args(factory) + lines.append("%s:%d: def %s%s" % (p, lineno + 1, factory.__name__, args)) + return lines + + def __repr__(self) -> str: + return "" % (self.node) + + +@final +class SubRequest(FixtureRequest): + """A sub request for handling getting a fixture from a test function/fixture.""" + + def __init__( + self, + request: "FixtureRequest", + scope: Scope, + param: Any, + param_index: int, + fixturedef: "FixtureDef[object]", + *, + _ispytest: bool = False, + ) -> None: + check_ispytest(_ispytest) + self._parent_request = request + self.fixturename = fixturedef.argname + if param is not NOTSET: + self.param = param + self.param_index = param_index + self._scope = scope + self._fixturedef = fixturedef + self._pyfuncitem = request._pyfuncitem + self._fixture_defs = request._fixture_defs + self._arg2fixturedefs = request._arg2fixturedefs + self._arg2index = request._arg2index + self._fixturemanager = request._fixturemanager + + def __repr__(self) -> str: + return f"" + + def addfinalizer(self, finalizer: Callable[[], object]) -> None: + """Add finalizer/teardown function to be called without arguments after + the last test within the requesting test context finished execution.""" + self._fixturedef.addfinalizer(finalizer) + + def _schedule_finalizers( + self, fixturedef: "FixtureDef[object]", subrequest: "SubRequest" + ) -> None: + # If the executing fixturedef was not explicitly requested in the argument list (via + # getfixturevalue inside the fixture call) then ensure this fixture def will be finished + # first. + if fixturedef.argname not in self.fixturenames: + fixturedef.addfinalizer( + functools.partial(self._fixturedef.finish, request=self) + ) + super()._schedule_finalizers(fixturedef, subrequest) + + +@final +class FixtureLookupError(LookupError): + """Could not return a requested fixture (missing or invalid).""" + + def __init__( + self, argname: Optional[str], request: FixtureRequest, msg: Optional[str] = None + ) -> None: + self.argname = argname + self.request = request + self.fixturestack = request._get_fixturestack() + self.msg = msg + + def formatrepr(self) -> "FixtureLookupErrorRepr": + tblines: List[str] = [] + addline = tblines.append + stack = [self.request._pyfuncitem.obj] + stack.extend(map(lambda x: x.func, self.fixturestack)) + msg = self.msg + if msg is not None: + # The last fixture raise an error, let's present + # it at the requesting side. + stack = stack[:-1] + for function in stack: + fspath, lineno = getfslineno(function) + try: + lines, _ = inspect.getsourcelines(get_real_func(function)) + except (OSError, IndexError, TypeError): + error_msg = "file %s, line %s: source code not available" + addline(error_msg % (fspath, lineno + 1)) + else: + addline(f"file {fspath}, line {lineno + 1}") + for i, line in enumerate(lines): + line = line.rstrip() + addline(" " + line) + if line.lstrip().startswith("def"): + break + + if msg is None: + fm = self.request._fixturemanager + available = set() + parentid = self.request._pyfuncitem.parent.nodeid + for name, fixturedefs in fm._arg2fixturedefs.items(): + faclist = list(fm._matchfactories(fixturedefs, parentid)) + if faclist: + available.add(name) + if self.argname in available: + msg = " recursive dependency involving fixture '{}' detected".format( + self.argname + ) + else: + msg = f"fixture '{self.argname}' not found" + msg += "\n available fixtures: {}".format(", ".join(sorted(available))) + msg += "\n use 'pytest --fixtures [testpath]' for help on them." + + return FixtureLookupErrorRepr(fspath, lineno, tblines, msg, self.argname) + + +class FixtureLookupErrorRepr(TerminalRepr): + def __init__( + self, + filename: Union[str, "os.PathLike[str]"], + firstlineno: int, + tblines: Sequence[str], + errorstring: str, + argname: Optional[str], + ) -> None: + self.tblines = tblines + self.errorstring = errorstring + self.filename = filename + self.firstlineno = firstlineno + self.argname = argname + + def toterminal(self, tw: TerminalWriter) -> None: + # tw.line("FixtureLookupError: %s" %(self.argname), red=True) + for tbline in self.tblines: + tw.line(tbline.rstrip()) + lines = self.errorstring.split("\n") + if lines: + tw.line( + f"{FormattedExcinfo.fail_marker} {lines[0].strip()}", + red=True, + ) + for line in lines[1:]: + tw.line( + f"{FormattedExcinfo.flow_marker} {line.strip()}", + red=True, + ) + tw.line() + tw.line("%s:%d" % (os.fspath(self.filename), self.firstlineno + 1)) + + +def fail_fixturefunc(fixturefunc, msg: str) -> NoReturn: + fs, lineno = getfslineno(fixturefunc) + location = f"{fs}:{lineno + 1}" + source = _pytest._code.Source(fixturefunc) + fail(msg + ":\n\n" + str(source.indent()) + "\n" + location, pytrace=False) + + +def call_fixture_func( + fixturefunc: "_FixtureFunc[FixtureValue]", request: FixtureRequest, kwargs +) -> FixtureValue: + if is_generator(fixturefunc): + fixturefunc = cast( + Callable[..., Generator[FixtureValue, None, None]], fixturefunc + ) + generator = fixturefunc(**kwargs) + try: + fixture_result = next(generator) + except StopIteration: + raise ValueError(f"{request.fixturename} did not yield a value") from None + finalizer = functools.partial(_teardown_yield_fixture, fixturefunc, generator) + request.addfinalizer(finalizer) + else: + fixturefunc = cast(Callable[..., FixtureValue], fixturefunc) + fixture_result = fixturefunc(**kwargs) + return fixture_result + + +def _teardown_yield_fixture(fixturefunc, it) -> None: + """Execute the teardown of a fixture function by advancing the iterator + after the yield and ensure the iteration ends (if not it means there is + more than one yield in the function).""" + try: + next(it) + except StopIteration: + pass + else: + fail_fixturefunc(fixturefunc, "fixture function has more than one 'yield'") + + +def _eval_scope_callable( + scope_callable: "Callable[[str, Config], _ScopeName]", + fixture_name: str, + config: Config, +) -> "_ScopeName": + try: + # Type ignored because there is no typing mechanism to specify + # keyword arguments, currently. + result = scope_callable(fixture_name=fixture_name, config=config) # type: ignore[call-arg] + except Exception as e: + raise TypeError( + "Error evaluating {} while defining fixture '{}'.\n" + "Expected a function with the signature (*, fixture_name, config)".format( + scope_callable, fixture_name + ) + ) from e + if not isinstance(result, str): + fail( + "Expected {} to return a 'str' while defining fixture '{}', but it returned:\n" + "{!r}".format(scope_callable, fixture_name, result), + pytrace=False, + ) + return result + + +@final +class FixtureDef(Generic[FixtureValue]): + """A container for a fixture definition.""" + + def __init__( + self, + fixturemanager: "FixtureManager", + baseid: Optional[str], + argname: str, + func: "_FixtureFunc[FixtureValue]", + scope: Union[Scope, "_ScopeName", Callable[[str, Config], "_ScopeName"], None], + params: Optional[Sequence[object]], + unittest: bool = False, + ids: Optional[ + Union[Tuple[Optional[object], ...], Callable[[Any], Optional[object]]] + ] = None, + ) -> None: + self._fixturemanager = fixturemanager + # The "base" node ID for the fixture. + # + # This is a node ID prefix. A fixture is only available to a node (e.g. + # a `Function` item) if the fixture's baseid is a parent of the node's + # nodeid (see the `iterparentnodeids` function for what constitutes a + # "parent" and a "prefix" in this context). + # + # For a fixture found in a Collector's object (e.g. a `Module`s module, + # a `Class`'s class), the baseid is the Collector's nodeid. + # + # For a fixture found in a conftest plugin, the baseid is the conftest's + # directory path relative to the rootdir. + # + # For other plugins, the baseid is the empty string (always matches). + self.baseid = baseid or "" + # Whether the fixture was found from a node or a conftest in the + # collection tree. Will be false for fixtures defined in non-conftest + # plugins. + self.has_location = baseid is not None + # The fixture factory function. + self.func = func + # The name by which the fixture may be requested. + self.argname = argname + if scope is None: + scope = Scope.Function + elif callable(scope): + scope = _eval_scope_callable(scope, argname, fixturemanager.config) + if isinstance(scope, str): + scope = Scope.from_user( + scope, descr=f"Fixture '{func.__name__}'", where=baseid + ) + self._scope = scope + # If the fixture is directly parametrized, the parameter values. + self.params: Optional[Sequence[object]] = params + # If the fixture is directly parametrized, a tuple of explicit IDs to + # assign to the parameter values, or a callable to generate an ID given + # a parameter value. + self.ids = ids + # The names requested by the fixtures. + self.argnames = getfuncargnames(func, name=argname, is_method=unittest) + # Whether the fixture was collected from a unittest TestCase class. + # Note that it really only makes sense to define autouse fixtures in + # unittest TestCases. + self.unittest = unittest + # If the fixture was executed, the current value of the fixture. + # Can change if the fixture is executed with different parameters. + self.cached_result: Optional[_FixtureCachedResult[FixtureValue]] = None + self._finalizers: List[Callable[[], object]] = [] + + @property + def scope(self) -> "_ScopeName": + """Scope string, one of "function", "class", "module", "package", "session".""" + return self._scope.value + + def addfinalizer(self, finalizer: Callable[[], object]) -> None: + self._finalizers.append(finalizer) + + def finish(self, request: SubRequest) -> None: + exc = None + try: + while self._finalizers: + try: + func = self._finalizers.pop() + func() + except BaseException as e: + # XXX Only first exception will be seen by user, + # ideally all should be reported. + if exc is None: + exc = e + if exc: + raise exc + finally: + ihook = request.node.ihook + ihook.pytest_fixture_post_finalizer(fixturedef=self, request=request) + # Even if finalization fails, we invalidate the cached fixture + # value and remove all finalizers because they may be bound methods + # which will keep instances alive. + self.cached_result = None + self._finalizers = [] + + def execute(self, request: SubRequest) -> FixtureValue: + # Get required arguments and register our own finish() + # with their finalization. + for argname in self.argnames: + fixturedef = request._get_active_fixturedef(argname) + if argname != "request": + # PseudoFixtureDef is only for "request". + assert isinstance(fixturedef, FixtureDef) + fixturedef.addfinalizer(functools.partial(self.finish, request=request)) + + my_cache_key = self.cache_key(request) + if self.cached_result is not None: + # note: comparison with `==` can fail (or be expensive) for e.g. + # numpy arrays (#6497). + cache_key = self.cached_result[1] + if my_cache_key is cache_key: + if self.cached_result[2] is not None: + _, val, tb = self.cached_result[2] + raise val.with_traceback(tb) + else: + result = self.cached_result[0] + return result + # We have a previous but differently parametrized fixture instance + # so we need to tear it down before creating a new one. + self.finish(request) + assert self.cached_result is None + + ihook = request.node.ihook + result = ihook.pytest_fixture_setup(fixturedef=self, request=request) + return result + + def cache_key(self, request: SubRequest) -> object: + return request.param_index if not hasattr(request, "param") else request.param + + def __repr__(self) -> str: + return "".format( + self.argname, self.scope, self.baseid + ) + + +def resolve_fixture_function( + fixturedef: FixtureDef[FixtureValue], request: FixtureRequest +) -> "_FixtureFunc[FixtureValue]": + """Get the actual callable that can be called to obtain the fixture + value, dealing with unittest-specific instances and bound methods.""" + fixturefunc = fixturedef.func + if fixturedef.unittest: + if request.instance is not None: + # Bind the unbound method to the TestCase instance. + fixturefunc = fixturedef.func.__get__(request.instance) # type: ignore[union-attr] + else: + # The fixture function needs to be bound to the actual + # request.instance so that code working with "fixturedef" behaves + # as expected. + if request.instance is not None: + # Handle the case where fixture is defined not in a test class, but some other class + # (for example a plugin class with a fixture), see #2270. + if hasattr(fixturefunc, "__self__") and not isinstance( + request.instance, fixturefunc.__self__.__class__ # type: ignore[union-attr] + ): + return fixturefunc + fixturefunc = getimfunc(fixturedef.func) + if fixturefunc != fixturedef.func: + fixturefunc = fixturefunc.__get__(request.instance) # type: ignore[union-attr] + return fixturefunc + + +def pytest_fixture_setup( + fixturedef: FixtureDef[FixtureValue], request: SubRequest +) -> FixtureValue: + """Execution of fixture setup.""" + kwargs = {} + for argname in fixturedef.argnames: + fixdef = request._get_active_fixturedef(argname) + assert fixdef.cached_result is not None + result, arg_cache_key, exc = fixdef.cached_result + request._check_scope(argname, request._scope, fixdef._scope) + kwargs[argname] = result + + fixturefunc = resolve_fixture_function(fixturedef, request) + my_cache_key = fixturedef.cache_key(request) + try: + result = call_fixture_func(fixturefunc, request, kwargs) + except TEST_OUTCOME: + exc_info = sys.exc_info() + assert exc_info[0] is not None + if isinstance( + exc_info[1], skip.Exception + ) and not fixturefunc.__name__.startswith("xunit_setup"): + exc_info[1]._use_item_location = True # type: ignore[attr-defined] + fixturedef.cached_result = (None, my_cache_key, exc_info) + raise + fixturedef.cached_result = (result, my_cache_key, None) + return result + + +def _ensure_immutable_ids( + ids: Optional[Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]]] +) -> Optional[Union[Tuple[Optional[object], ...], Callable[[Any], Optional[object]]]]: + if ids is None: + return None + if callable(ids): + return ids + return tuple(ids) + + +def _params_converter( + params: Optional[Iterable[object]], +) -> Optional[Tuple[object, ...]]: + return tuple(params) if params is not None else None + + +def wrap_function_to_error_out_if_called_directly( + function: FixtureFunction, + fixture_marker: "FixtureFunctionMarker", +) -> FixtureFunction: + """Wrap the given fixture function so we can raise an error about it being called directly, + instead of used as an argument in a test function.""" + message = ( + 'Fixture "{name}" called directly. Fixtures are not meant to be called directly,\n' + "but are created automatically when test functions request them as parameters.\n" + "See https://docs.pytest.org/en/stable/explanation/fixtures.html for more information about fixtures, and\n" + "https://docs.pytest.org/en/stable/deprecations.html#calling-fixtures-directly about how to update your code." + ).format(name=fixture_marker.name or function.__name__) + + @functools.wraps(function) + def result(*args, **kwargs): + fail(message, pytrace=False) + + # Keep reference to the original function in our own custom attribute so we don't unwrap + # further than this point and lose useful wrappings like @mock.patch (#3774). + result.__pytest_wrapped__ = _PytestWrapper(function) # type: ignore[attr-defined] + + return cast(FixtureFunction, result) + + +@final +@dataclasses.dataclass(frozen=True) +class FixtureFunctionMarker: + scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" + params: Optional[Tuple[object, ...]] + autouse: bool = False + ids: Optional[ + Union[Tuple[Optional[object], ...], Callable[[Any], Optional[object]]] + ] = None + name: Optional[str] = None + + _ispytest: dataclasses.InitVar[bool] = False + + def __post_init__(self, _ispytest: bool) -> None: + check_ispytest(_ispytest) + + def __call__(self, function: FixtureFunction) -> FixtureFunction: + if inspect.isclass(function): + raise ValueError("class fixtures not supported (maybe in the future)") + + if getattr(function, "_pytestfixturefunction", False): + raise ValueError( + "fixture is being applied more than once to the same function" + ) + + function = wrap_function_to_error_out_if_called_directly(function, self) + + name = self.name or function.__name__ + if name == "request": + location = getlocation(function) + fail( + "'request' is a reserved word for fixtures, use another name:\n {}".format( + location + ), + pytrace=False, + ) + + # Type ignored because https://github.com/python/mypy/issues/2087. + function._pytestfixturefunction = self # type: ignore[attr-defined] + return function + + +@overload +def fixture( + fixture_function: FixtureFunction, + *, + scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = ..., + params: Optional[Iterable[object]] = ..., + autouse: bool = ..., + ids: Optional[ + Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]] + ] = ..., + name: Optional[str] = ..., +) -> FixtureFunction: + ... + + +@overload +def fixture( # noqa: F811 + fixture_function: None = ..., + *, + scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = ..., + params: Optional[Iterable[object]] = ..., + autouse: bool = ..., + ids: Optional[ + Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]] + ] = ..., + name: Optional[str] = None, +) -> FixtureFunctionMarker: + ... + + +def fixture( # noqa: F811 + fixture_function: Optional[FixtureFunction] = None, + *, + scope: "Union[_ScopeName, Callable[[str, Config], _ScopeName]]" = "function", + params: Optional[Iterable[object]] = None, + autouse: bool = False, + ids: Optional[ + Union[Sequence[Optional[object]], Callable[[Any], Optional[object]]] + ] = None, + name: Optional[str] = None, +) -> Union[FixtureFunctionMarker, FixtureFunction]: + """Decorator to mark a fixture factory function. + + This decorator can be used, with or without parameters, to define a + fixture function. + + The name of the fixture function can later be referenced to cause its + invocation ahead of running tests: test modules or classes can use the + ``pytest.mark.usefixtures(fixturename)`` marker. + + Test functions can directly use fixture names as input arguments in which + case the fixture instance returned from the fixture function will be + injected. + + Fixtures can provide their values to test functions using ``return`` or + ``yield`` statements. When using ``yield`` the code block after the + ``yield`` statement is executed as teardown code regardless of the test + outcome, and must yield exactly once. + + :param scope: + The scope for which this fixture is shared; one of ``"function"`` + (default), ``"class"``, ``"module"``, ``"package"`` or ``"session"``. + + This parameter may also be a callable which receives ``(fixture_name, config)`` + as parameters, and must return a ``str`` with one of the values mentioned above. + + See :ref:`dynamic scope` in the docs for more information. + + :param params: + An optional list of parameters which will cause multiple invocations + of the fixture function and all of the tests using it. The current + parameter is available in ``request.param``. + + :param autouse: + If True, the fixture func is activated for all tests that can see it. + If False (the default), an explicit reference is needed to activate + the fixture. + + :param ids: + Sequence of ids each corresponding to the params so that they are + part of the test id. If no ids are provided they will be generated + automatically from the params. + + :param name: + The name of the fixture. This defaults to the name of the decorated + function. If a fixture is used in the same module in which it is + defined, the function name of the fixture will be shadowed by the + function arg that requests the fixture; one way to resolve this is to + name the decorated function ``fixture_`` and then use + ``@pytest.fixture(name='')``. + """ + fixture_marker = FixtureFunctionMarker( + scope=scope, + params=tuple(params) if params is not None else None, + autouse=autouse, + ids=None if ids is None else ids if callable(ids) else tuple(ids), + name=name, + _ispytest=True, + ) + + # Direct decoration. + if fixture_function: + return fixture_marker(fixture_function) + + return fixture_marker + + +def yield_fixture( + fixture_function=None, + *args, + scope="function", + params=None, + autouse=False, + ids=None, + name=None, +): + """(Return a) decorator to mark a yield-fixture factory function. + + .. deprecated:: 3.0 + Use :py:func:`pytest.fixture` directly instead. + """ + warnings.warn(YIELD_FIXTURE, stacklevel=2) + return fixture( + fixture_function, + *args, + scope=scope, + params=params, + autouse=autouse, + ids=ids, + name=name, + ) + + +@fixture(scope="session") +def pytestconfig(request: FixtureRequest) -> Config: + """Session-scoped fixture that returns the session's :class:`pytest.Config` + object. + + Example:: + + def test_foo(pytestconfig): + if pytestconfig.getoption("verbose") > 0: + ... + + """ + return request.config + + +def pytest_addoption(parser: Parser) -> None: + parser.addini( + "usefixtures", + type="args", + default=[], + help="List of default fixtures to be used with this project", + ) + + +class FixtureManager: + """pytest fixture definitions and information is stored and managed + from this class. + + During collection fm.parsefactories() is called multiple times to parse + fixture function definitions into FixtureDef objects and internal + data structures. + + During collection of test functions, metafunc-mechanics instantiate + a FuncFixtureInfo object which is cached per node/func-name. + This FuncFixtureInfo object is later retrieved by Function nodes + which themselves offer a fixturenames attribute. + + The FuncFixtureInfo object holds information about fixtures and FixtureDefs + relevant for a particular function. An initial list of fixtures is + assembled like this: + + - ini-defined usefixtures + - autouse-marked fixtures along the collection chain up from the function + - usefixtures markers at module/class/function level + - test function funcargs + + Subsequently the funcfixtureinfo.fixturenames attribute is computed + as the closure of the fixtures needed to setup the initial fixtures, + i.e. fixtures needed by fixture functions themselves are appended + to the fixturenames list. + + Upon the test-setup phases all fixturenames are instantiated, retrieved + by a lookup of their FuncFixtureInfo. + """ + + FixtureLookupError = FixtureLookupError + FixtureLookupErrorRepr = FixtureLookupErrorRepr + + def __init__(self, session: "Session") -> None: + self.session = session + self.config: Config = session.config + self._arg2fixturedefs: Dict[str, List[FixtureDef[Any]]] = {} + self._holderobjseen: Set[object] = set() + # A mapping from a nodeid to a list of autouse fixtures it defines. + self._nodeid_autousenames: Dict[str, List[str]] = { + "": self.config.getini("usefixtures"), + } + session.config.pluginmanager.register(self, "funcmanage") + + def _get_direct_parametrize_args(self, node: nodes.Node) -> List[str]: + """Return all direct parametrization arguments of a node, so we don't + mistake them for fixtures. + + Check https://github.com/pytest-dev/pytest/issues/5036. + + These things are done later as well when dealing with parametrization + so this could be improved. + """ + parametrize_argnames: List[str] = [] + for marker in node.iter_markers(name="parametrize"): + if not marker.kwargs.get("indirect", False): + p_argnames, _ = ParameterSet._parse_parametrize_args( + *marker.args, **marker.kwargs + ) + parametrize_argnames.extend(p_argnames) + + return parametrize_argnames + + def getfixtureinfo( + self, node: nodes.Node, func, cls, funcargs: bool = True + ) -> FuncFixtureInfo: + if funcargs and not getattr(node, "nofuncargs", False): + argnames = getfuncargnames(func, name=node.name, cls=cls) + else: + argnames = () + + usefixtures = tuple( + arg for mark in node.iter_markers(name="usefixtures") for arg in mark.args + ) + initialnames = usefixtures + argnames + fm = node.session._fixturemanager + initialnames, names_closure, arg2fixturedefs = fm.getfixtureclosure( + initialnames, node, ignore_args=self._get_direct_parametrize_args(node) + ) + return FuncFixtureInfo(argnames, initialnames, names_closure, arg2fixturedefs) + + def pytest_plugin_registered(self, plugin: _PluggyPlugin) -> None: + nodeid = None + try: + p = absolutepath(plugin.__file__) # type: ignore[attr-defined] + except AttributeError: + pass + else: + # Construct the base nodeid which is later used to check + # what fixtures are visible for particular tests (as denoted + # by their test id). + if p.name.startswith("conftest.py"): + try: + nodeid = str(p.parent.relative_to(self.config.rootpath)) + except ValueError: + nodeid = "" + if nodeid == ".": + nodeid = "" + if os.sep != nodes.SEP: + nodeid = nodeid.replace(os.sep, nodes.SEP) + + self.parsefactories(plugin, nodeid) + + def _getautousenames(self, nodeid: str) -> Iterator[str]: + """Return the names of autouse fixtures applicable to nodeid.""" + for parentnodeid in nodes.iterparentnodeids(nodeid): + basenames = self._nodeid_autousenames.get(parentnodeid) + if basenames: + yield from basenames + + def getfixtureclosure( + self, + fixturenames: Tuple[str, ...], + parentnode: nodes.Node, + ignore_args: Sequence[str] = (), + ) -> Tuple[Tuple[str, ...], List[str], Dict[str, Sequence[FixtureDef[Any]]]]: + # Collect the closure of all fixtures, starting with the given + # fixturenames as the initial set. As we have to visit all + # factory definitions anyway, we also return an arg2fixturedefs + # mapping so that the caller can reuse it and does not have + # to re-discover fixturedefs again for each fixturename + # (discovering matching fixtures for a given name/node is expensive). + + parentid = parentnode.nodeid + fixturenames_closure = list(self._getautousenames(parentid)) + + def merge(otherlist: Iterable[str]) -> None: + for arg in otherlist: + if arg not in fixturenames_closure: + fixturenames_closure.append(arg) + + merge(fixturenames) + + # At this point, fixturenames_closure contains what we call "initialnames", + # which is a set of fixturenames the function immediately requests. We + # need to return it as well, so save this. + initialnames = tuple(fixturenames_closure) + + arg2fixturedefs: Dict[str, Sequence[FixtureDef[Any]]] = {} + lastlen = -1 + while lastlen != len(fixturenames_closure): + lastlen = len(fixturenames_closure) + for argname in fixturenames_closure: + if argname in ignore_args: + continue + if argname in arg2fixturedefs: + continue + fixturedefs = self.getfixturedefs(argname, parentid) + if fixturedefs: + arg2fixturedefs[argname] = fixturedefs + merge(fixturedefs[-1].argnames) + + def sort_by_scope(arg_name: str) -> Scope: + try: + fixturedefs = arg2fixturedefs[arg_name] + except KeyError: + return Scope.Function + else: + return fixturedefs[-1]._scope + + fixturenames_closure.sort(key=sort_by_scope, reverse=True) + return initialnames, fixturenames_closure, arg2fixturedefs + + def pytest_generate_tests(self, metafunc: "Metafunc") -> None: + """Generate new tests based on parametrized fixtures used by the given metafunc""" + + def get_parametrize_mark_argnames(mark: Mark) -> Sequence[str]: + args, _ = ParameterSet._parse_parametrize_args(*mark.args, **mark.kwargs) + return args + + for argname in metafunc.fixturenames: + # Get the FixtureDefs for the argname. + fixture_defs = metafunc._arg2fixturedefs.get(argname) + if not fixture_defs: + # Will raise FixtureLookupError at setup time if not parametrized somewhere + # else (e.g @pytest.mark.parametrize) + continue + + # If the test itself parametrizes using this argname, give it + # precedence. + if any( + argname in get_parametrize_mark_argnames(mark) + for mark in metafunc.definition.iter_markers("parametrize") + ): + continue + + # In the common case we only look at the fixture def with the + # closest scope (last in the list). But if the fixture overrides + # another fixture, while requesting the super fixture, keep going + # in case the super fixture is parametrized (#1953). + for fixturedef in reversed(fixture_defs): + # Fixture is parametrized, apply it and stop. + if fixturedef.params is not None: + metafunc.parametrize( + argname, + fixturedef.params, + indirect=True, + scope=fixturedef.scope, + ids=fixturedef.ids, + ) + break + + # Not requesting the overridden super fixture, stop. + if argname not in fixturedef.argnames: + break + + # Try next super fixture, if any. + + def pytest_collection_modifyitems(self, items: List[nodes.Item]) -> None: + # Separate parametrized setups. + items[:] = reorder_items(items) + + @overload + def parsefactories( + self, + node_or_obj: nodes.Node, + *, + unittest: bool = ..., + ) -> None: + raise NotImplementedError() + + @overload + def parsefactories( # noqa: F811 + self, + node_or_obj: object, + nodeid: Optional[str], + *, + unittest: bool = ..., + ) -> None: + raise NotImplementedError() + + def parsefactories( # noqa: F811 + self, + node_or_obj: Union[nodes.Node, object], + nodeid: Union[str, NotSetType, None] = NOTSET, + *, + unittest: bool = False, + ) -> None: + """Collect fixtures from a collection node or object. + + Found fixtures are parsed into `FixtureDef`s and saved. + + If `node_or_object` is a collection node (with an underlying Python + object), the node's object is traversed and the node's nodeid is used to + determine the fixtures' visibilty. `nodeid` must not be specified in + this case. + + If `node_or_object` is an object (e.g. a plugin), the object is + traversed and the given `nodeid` is used to determine the fixtures' + visibility. `nodeid` must be specified in this case; None and "" mean + total visibility. + """ + if nodeid is not NOTSET: + holderobj = node_or_obj + else: + assert isinstance(node_or_obj, nodes.Node) + holderobj = cast(object, node_or_obj.obj) # type: ignore[attr-defined] + assert isinstance(node_or_obj.nodeid, str) + nodeid = node_or_obj.nodeid + if holderobj in self._holderobjseen: + return + + self._holderobjseen.add(holderobj) + autousenames = [] + for name in dir(holderobj): + # ugly workaround for one of the fspath deprecated property of node + # todo: safely generalize + if isinstance(holderobj, nodes.Node) and name == "fspath": + continue + + # The attribute can be an arbitrary descriptor, so the attribute + # access below can raise. safe_getatt() ignores such exceptions. + obj = safe_getattr(holderobj, name, None) + marker = getfixturemarker(obj) + if not isinstance(marker, FixtureFunctionMarker): + # Magic globals with __getattr__ might have got us a wrong + # fixture attribute. + continue + + if marker.name: + name = marker.name + + # During fixture definition we wrap the original fixture function + # to issue a warning if called directly, so here we unwrap it in + # order to not emit the warning when pytest itself calls the + # fixture function. + obj = get_real_method(obj, holderobj) + + fixture_def = FixtureDef( + fixturemanager=self, + baseid=nodeid, + argname=name, + func=obj, + scope=marker.scope, + params=marker.params, + unittest=unittest, + ids=marker.ids, + ) + + faclist = self._arg2fixturedefs.setdefault(name, []) + if fixture_def.has_location: + faclist.append(fixture_def) + else: + # fixturedefs with no location are at the front + # so this inserts the current fixturedef after the + # existing fixturedefs from external plugins but + # before the fixturedefs provided in conftests. + i = len([f for f in faclist if not f.has_location]) + faclist.insert(i, fixture_def) + if marker.autouse: + autousenames.append(name) + + if autousenames: + self._nodeid_autousenames.setdefault(nodeid or "", []).extend(autousenames) + + def getfixturedefs( + self, argname: str, nodeid: str + ) -> Optional[Sequence[FixtureDef[Any]]]: + """Get a list of fixtures which are applicable to the given node id. + + :param str argname: Name of the fixture to search for. + :param str nodeid: Full node id of the requesting test. + :rtype: Sequence[FixtureDef] + """ + try: + fixturedefs = self._arg2fixturedefs[argname] + except KeyError: + return None + return tuple(self._matchfactories(fixturedefs, nodeid)) + + def _matchfactories( + self, fixturedefs: Iterable[FixtureDef[Any]], nodeid: str + ) -> Iterator[FixtureDef[Any]]: + parentnodeids = set(nodes.iterparentnodeids(nodeid)) + for fixturedef in fixturedefs: + if fixturedef.baseid in parentnodeids: + yield fixturedef diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/freeze_support.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/freeze_support.py new file mode 100644 index 000000000..9f8ea231f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/freeze_support.py @@ -0,0 +1,44 @@ +"""Provides a function to report all internal modules for using freezing +tools.""" +import types +from typing import Iterator +from typing import List +from typing import Union + + +def freeze_includes() -> List[str]: + """Return a list of module names used by pytest that should be + included by cx_freeze.""" + import _pytest + + result = list(_iter_all_modules(_pytest)) + return result + + +def _iter_all_modules( + package: Union[str, types.ModuleType], + prefix: str = "", +) -> Iterator[str]: + """Iterate over the names of all modules that can be found in the given + package, recursively. + + >>> import _pytest + >>> list(_iter_all_modules(_pytest)) + ['_pytest._argcomplete', '_pytest._code.code', ...] + """ + import os + import pkgutil + + if isinstance(package, str): + path = package + else: + # Type ignored because typeshed doesn't define ModuleType.__path__ + # (only defined on packages). + package_path = package.__path__ # type: ignore[attr-defined] + path, prefix = package_path[0], package.__name__ + "." + for _, name, is_package in pkgutil.iter_modules([path]): + if is_package: + for m in _iter_all_modules(os.path.join(path, name), prefix=name + "."): + yield prefix + m + else: + yield prefix + name diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/helpconfig.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/helpconfig.py new file mode 100644 index 000000000..ea16c4388 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/helpconfig.py @@ -0,0 +1,270 @@ +"""Version info, help messages, tracing configuration.""" +import os +import sys +from argparse import Action +from typing import List +from typing import Optional +from typing import Union + +import pytest +from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config import PrintHelp +from _pytest.config.argparsing import Parser +from _pytest.terminal import TerminalReporter + + +class HelpAction(Action): + """An argparse Action that will raise an exception in order to skip the + rest of the argument parsing when --help is passed. + + This prevents argparse from quitting due to missing required arguments + when any are defined, for example by ``pytest_addoption``. + This is similar to the way that the builtin argparse --help option is + implemented by raising SystemExit. + """ + + def __init__(self, option_strings, dest=None, default=False, help=None): + super().__init__( + option_strings=option_strings, + dest=dest, + const=True, + default=default, + nargs=0, + help=help, + ) + + def __call__(self, parser, namespace, values, option_string=None): + setattr(namespace, self.dest, self.const) + + # We should only skip the rest of the parsing after preparse is done. + if getattr(parser._parser, "after_preparse", False): + raise PrintHelp + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("debugconfig") + group.addoption( + "--version", + "-V", + action="count", + default=0, + dest="version", + help="Display pytest version and information about plugins. " + "When given twice, also display information about plugins.", + ) + group._addoption( + "-h", + "--help", + action=HelpAction, + dest="help", + help="Show help message and configuration info", + ) + group._addoption( + "-p", + action="append", + dest="plugins", + default=[], + metavar="name", + help="Early-load given plugin module name or entry point (multi-allowed). " + "To avoid loading of plugins, use the `no:` prefix, e.g. " + "`no:doctest`.", + ) + group.addoption( + "--traceconfig", + "--trace-config", + action="store_true", + default=False, + help="Trace considerations of conftest.py files", + ) + group.addoption( + "--debug", + action="store", + nargs="?", + const="pytestdebug.log", + dest="debug", + metavar="DEBUG_FILE_NAME", + help="Store internal tracing debug information in this log file. " + "This file is opened with 'w' and truncated as a result, care advised. " + "Default: pytestdebug.log.", + ) + group._addoption( + "-o", + "--override-ini", + dest="override_ini", + action="append", + help='Override ini option with "option=value" style, ' + "e.g. `-o xfail_strict=True -o cache_dir=cache`.", + ) + + +@pytest.hookimpl(hookwrapper=True) +def pytest_cmdline_parse(): + outcome = yield + config: Config = outcome.get_result() + + if config.option.debug: + # --debug | --debug was provided. + path = config.option.debug + debugfile = open(path, "w", encoding="utf-8") + debugfile.write( + "versions pytest-%s, " + "python-%s\ncwd=%s\nargs=%s\n\n" + % ( + pytest.__version__, + ".".join(map(str, sys.version_info)), + os.getcwd(), + config.invocation_params.args, + ) + ) + config.trace.root.setwriter(debugfile.write) + undo_tracing = config.pluginmanager.enable_tracing() + sys.stderr.write("writing pytest debug information to %s\n" % path) + + def unset_tracing() -> None: + debugfile.close() + sys.stderr.write("wrote pytest debug information to %s\n" % debugfile.name) + config.trace.root.setwriter(None) + undo_tracing() + + config.add_cleanup(unset_tracing) + + +def showversion(config: Config) -> None: + if config.option.version > 1: + sys.stdout.write( + "This is pytest version {}, imported from {}\n".format( + pytest.__version__, pytest.__file__ + ) + ) + plugininfo = getpluginversioninfo(config) + if plugininfo: + for line in plugininfo: + sys.stdout.write(line + "\n") + else: + sys.stdout.write(f"pytest {pytest.__version__}\n") + + +def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]: + if config.option.version > 0: + showversion(config) + return 0 + elif config.option.help: + config._do_configure() + showhelp(config) + config._ensure_unconfigure() + return 0 + return None + + +def showhelp(config: Config) -> None: + import textwrap + + reporter: Optional[TerminalReporter] = config.pluginmanager.get_plugin( + "terminalreporter" + ) + assert reporter is not None + tw = reporter._tw + tw.write(config._parser.optparser.format_help()) + tw.line() + tw.line( + "[pytest] ini-options in the first " + "pytest.ini|tox.ini|setup.cfg|pyproject.toml file found:" + ) + tw.line() + + columns = tw.fullwidth # costly call + indent_len = 24 # based on argparse's max_help_position=24 + indent = " " * indent_len + for name in config._parser._ininames: + help, type, default = config._parser._inidict[name] + if type is None: + type = "string" + if help is None: + raise TypeError(f"help argument cannot be None for {name}") + spec = f"{name} ({type}):" + tw.write(" %s" % spec) + spec_len = len(spec) + if spec_len > (indent_len - 3): + # Display help starting at a new line. + tw.line() + helplines = textwrap.wrap( + help, + columns, + initial_indent=indent, + subsequent_indent=indent, + break_on_hyphens=False, + ) + + for line in helplines: + tw.line(line) + else: + # Display help starting after the spec, following lines indented. + tw.write(" " * (indent_len - spec_len - 2)) + wrapped = textwrap.wrap(help, columns - indent_len, break_on_hyphens=False) + + if wrapped: + tw.line(wrapped[0]) + for line in wrapped[1:]: + tw.line(indent + line) + + tw.line() + tw.line("Environment variables:") + vars = [ + ("PYTEST_ADDOPTS", "Extra command line options"), + ("PYTEST_PLUGINS", "Comma-separated plugins to load during startup"), + ("PYTEST_DISABLE_PLUGIN_AUTOLOAD", "Set to disable plugin auto-loading"), + ("PYTEST_DEBUG", "Set to enable debug tracing of pytest's internals"), + ] + for name, help in vars: + tw.line(f" {name:<24} {help}") + tw.line() + tw.line() + + tw.line("to see available markers type: pytest --markers") + tw.line("to see available fixtures type: pytest --fixtures") + tw.line( + "(shown according to specified file_or_dir or current dir " + "if not specified; fixtures with leading '_' are only shown " + "with the '-v' option" + ) + + for warningreport in reporter.stats.get("warnings", []): + tw.line("warning : " + warningreport.message, red=True) + return + + +conftest_options = [("pytest_plugins", "list of plugin names to load")] + + +def getpluginversioninfo(config: Config) -> List[str]: + lines = [] + plugininfo = config.pluginmanager.list_plugin_distinfo() + if plugininfo: + lines.append("setuptools registered plugins:") + for plugin, dist in plugininfo: + loc = getattr(plugin, "__file__", repr(plugin)) + content = f"{dist.project_name}-{dist.version} at {loc}" + lines.append(" " + content) + return lines + + +def pytest_report_header(config: Config) -> List[str]: + lines = [] + if config.option.debug or config.option.traceconfig: + lines.append(f"using: pytest-{pytest.__version__}") + + verinfo = getpluginversioninfo(config) + if verinfo: + lines.extend(verinfo) + + if config.option.traceconfig: + lines.append("active plugins:") + items = config.pluginmanager.list_name_plugin() + for name, plugin in items: + if hasattr(plugin, "__file__"): + r = plugin.__file__ + else: + r = repr(plugin) + lines.append(f" {name:<20}: {r}") + return lines diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/hookspec.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/hookspec.py new file mode 100644 index 000000000..1f7c368f7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/hookspec.py @@ -0,0 +1,979 @@ +"""Hook specifications for pytest plugins which are invoked by pytest itself +and by builtin plugins.""" +from pathlib import Path +from typing import Any +from typing import Dict +from typing import List +from typing import Mapping +from typing import Optional +from typing import Sequence +from typing import Tuple +from typing import TYPE_CHECKING +from typing import Union + +from pluggy import HookspecMarker + +from _pytest.deprecated import WARNING_CMDLINE_PREPARSE_HOOK + +if TYPE_CHECKING: + import pdb + import warnings + from typing_extensions import Literal + + from _pytest._code.code import ExceptionRepr + from _pytest._code.code import ExceptionInfo + from _pytest.config import Config + from _pytest.config import ExitCode + from _pytest.config import PytestPluginManager + from _pytest.config import _PluggyPlugin + from _pytest.config.argparsing import Parser + from _pytest.fixtures import FixtureDef + from _pytest.fixtures import SubRequest + from _pytest.main import Session + from _pytest.nodes import Collector + from _pytest.nodes import Item + from _pytest.outcomes import Exit + from _pytest.python import Class + from _pytest.python import Function + from _pytest.python import Metafunc + from _pytest.python import Module + from _pytest.reports import CollectReport + from _pytest.reports import TestReport + from _pytest.runner import CallInfo + from _pytest.terminal import TerminalReporter + from _pytest.terminal import TestShortLogReport + from _pytest.compat import LEGACY_PATH + + +hookspec = HookspecMarker("pytest") + +# ------------------------------------------------------------------------- +# Initialization hooks called for every plugin +# ------------------------------------------------------------------------- + + +@hookspec(historic=True) +def pytest_addhooks(pluginmanager: "PytestPluginManager") -> None: + """Called at plugin registration time to allow adding new hooks via a call to + ``pluginmanager.add_hookspecs(module_or_class, prefix)``. + + :param pytest.PytestPluginManager pluginmanager: The pytest plugin manager. + + .. note:: + This hook is incompatible with ``hookwrapper=True``. + """ + + +@hookspec(historic=True) +def pytest_plugin_registered( + plugin: "_PluggyPlugin", manager: "PytestPluginManager" +) -> None: + """A new pytest plugin got registered. + + :param plugin: The plugin module or instance. + :param pytest.PytestPluginManager manager: pytest plugin manager. + + .. note:: + This hook is incompatible with ``hookwrapper=True``. + """ + + +@hookspec(historic=True) +def pytest_addoption(parser: "Parser", pluginmanager: "PytestPluginManager") -> None: + """Register argparse-style options and ini-style config values, + called once at the beginning of a test run. + + .. note:: + + This function should be implemented only in plugins or ``conftest.py`` + files situated at the tests root directory due to how pytest + :ref:`discovers plugins during startup `. + + :param pytest.Parser parser: + To add command line options, call + :py:func:`parser.addoption(...) `. + To add ini-file values call :py:func:`parser.addini(...) + `. + + :param pytest.PytestPluginManager pluginmanager: + The pytest plugin manager, which can be used to install :py:func:`hookspec`'s + or :py:func:`hookimpl`'s and allow one plugin to call another plugin's hooks + to change how command line options are added. + + Options can later be accessed through the + :py:class:`config ` object, respectively: + + - :py:func:`config.getoption(name) ` to + retrieve the value of a command line option. + + - :py:func:`config.getini(name) ` to retrieve + a value read from an ini-style file. + + The config object is passed around on many internal objects via the ``.config`` + attribute or can be retrieved as the ``pytestconfig`` fixture. + + .. note:: + This hook is incompatible with ``hookwrapper=True``. + """ + + +@hookspec(historic=True) +def pytest_configure(config: "Config") -> None: + """Allow plugins and conftest files to perform initial configuration. + + This hook is called for every plugin and initial conftest file + after command line options have been parsed. + + After that, the hook is called for other conftest files as they are + imported. + + .. note:: + This hook is incompatible with ``hookwrapper=True``. + + :param pytest.Config config: The pytest config object. + """ + + +# ------------------------------------------------------------------------- +# Bootstrapping hooks called for plugins registered early enough: +# internal and 3rd party plugins. +# ------------------------------------------------------------------------- + + +@hookspec(firstresult=True) +def pytest_cmdline_parse( + pluginmanager: "PytestPluginManager", args: List[str] +) -> Optional["Config"]: + """Return an initialized :class:`~pytest.Config`, parsing the specified args. + + Stops at first non-None result, see :ref:`firstresult`. + + .. note:: + This hook will only be called for plugin classes passed to the + ``plugins`` arg when using `pytest.main`_ to perform an in-process + test run. + + :param pluginmanager: The pytest plugin manager. + :param args: List of arguments passed on the command line. + :returns: A pytest config object. + """ + + +@hookspec(warn_on_impl=WARNING_CMDLINE_PREPARSE_HOOK) +def pytest_cmdline_preparse(config: "Config", args: List[str]) -> None: + """(**Deprecated**) modify command line arguments before option parsing. + + This hook is considered deprecated and will be removed in a future pytest version. Consider + using :hook:`pytest_load_initial_conftests` instead. + + .. note:: + This hook will not be called for ``conftest.py`` files, only for setuptools plugins. + + :param config: The pytest config object. + :param args: Arguments passed on the command line. + """ + + +@hookspec(firstresult=True) +def pytest_cmdline_main(config: "Config") -> Optional[Union["ExitCode", int]]: + """Called for performing the main command line action. The default + implementation will invoke the configure hooks and runtest_mainloop. + + Stops at first non-None result, see :ref:`firstresult`. + + :param config: The pytest config object. + :returns: The exit code. + """ + + +def pytest_load_initial_conftests( + early_config: "Config", parser: "Parser", args: List[str] +) -> None: + """Called to implement the loading of initial conftest files ahead + of command line option parsing. + + .. note:: + This hook will not be called for ``conftest.py`` files, only for setuptools plugins. + + :param early_config: The pytest config object. + :param args: Arguments passed on the command line. + :param parser: To add command line options. + """ + + +# ------------------------------------------------------------------------- +# collection hooks +# ------------------------------------------------------------------------- + + +@hookspec(firstresult=True) +def pytest_collection(session: "Session") -> Optional[object]: + """Perform the collection phase for the given session. + + Stops at first non-None result, see :ref:`firstresult`. + The return value is not used, but only stops further processing. + + The default collection phase is this (see individual hooks for full details): + + 1. Starting from ``session`` as the initial collector: + + 1. ``pytest_collectstart(collector)`` + 2. ``report = pytest_make_collect_report(collector)`` + 3. ``pytest_exception_interact(collector, call, report)`` if an interactive exception occurred + 4. For each collected node: + + 1. If an item, ``pytest_itemcollected(item)`` + 2. If a collector, recurse into it. + + 5. ``pytest_collectreport(report)`` + + 2. ``pytest_collection_modifyitems(session, config, items)`` + + 1. ``pytest_deselected(items)`` for any deselected items (may be called multiple times) + + 3. ``pytest_collection_finish(session)`` + 4. Set ``session.items`` to the list of collected items + 5. Set ``session.testscollected`` to the number of collected items + + You can implement this hook to only perform some action before collection, + for example the terminal plugin uses it to start displaying the collection + counter (and returns `None`). + + :param session: The pytest session object. + """ + + +def pytest_collection_modifyitems( + session: "Session", config: "Config", items: List["Item"] +) -> None: + """Called after collection has been performed. May filter or re-order + the items in-place. + + :param session: The pytest session object. + :param config: The pytest config object. + :param items: List of item objects. + """ + + +def pytest_collection_finish(session: "Session") -> None: + """Called after collection has been performed and modified. + + :param session: The pytest session object. + """ + + +@hookspec(firstresult=True) +def pytest_ignore_collect( + collection_path: Path, path: "LEGACY_PATH", config: "Config" +) -> Optional[bool]: + """Return True to prevent considering this path for collection. + + This hook is consulted for all files and directories prior to calling + more specific hooks. + + Stops at first non-None result, see :ref:`firstresult`. + + :param collection_path: The path to analyze. + :param path: The path to analyze (deprecated). + :param config: The pytest config object. + + .. versionchanged:: 7.0.0 + The ``collection_path`` parameter was added as a :class:`pathlib.Path` + equivalent of the ``path`` parameter. The ``path`` parameter + has been deprecated. + """ + + +def pytest_collect_file( + file_path: Path, path: "LEGACY_PATH", parent: "Collector" +) -> "Optional[Collector]": + """Create a :class:`~pytest.Collector` for the given path, or None if not relevant. + + The new node needs to have the specified ``parent`` as a parent. + + :param file_path: The path to analyze. + :param path: The path to collect (deprecated). + + .. versionchanged:: 7.0.0 + The ``file_path`` parameter was added as a :class:`pathlib.Path` + equivalent of the ``path`` parameter. The ``path`` parameter + has been deprecated. + """ + + +# logging hooks for collection + + +def pytest_collectstart(collector: "Collector") -> None: + """Collector starts collecting. + + :param collector: + The collector. + """ + + +def pytest_itemcollected(item: "Item") -> None: + """We just collected a test item. + + :param item: + The item. + """ + + +def pytest_collectreport(report: "CollectReport") -> None: + """Collector finished collecting. + + :param report: + The collect report. + """ + + +def pytest_deselected(items: Sequence["Item"]) -> None: + """Called for deselected test items, e.g. by keyword. + + May be called multiple times. + + :param items: + The items. + """ + + +@hookspec(firstresult=True) +def pytest_make_collect_report(collector: "Collector") -> "Optional[CollectReport]": + """Perform :func:`collector.collect() ` and return + a :class:`~pytest.CollectReport`. + + Stops at first non-None result, see :ref:`firstresult`. + + :param collector: + The collector. + """ + + +# ------------------------------------------------------------------------- +# Python test function related hooks +# ------------------------------------------------------------------------- + + +@hookspec(firstresult=True) +def pytest_pycollect_makemodule( + module_path: Path, path: "LEGACY_PATH", parent +) -> Optional["Module"]: + """Return a :class:`pytest.Module` collector or None for the given path. + + This hook will be called for each matching test module path. + The :hook:`pytest_collect_file` hook needs to be used if you want to + create test modules for files that do not match as a test module. + + Stops at first non-None result, see :ref:`firstresult`. + + :param module_path: The path of the module to collect. + :param path: The path of the module to collect (deprecated). + + .. versionchanged:: 7.0.0 + The ``module_path`` parameter was added as a :class:`pathlib.Path` + equivalent of the ``path`` parameter. + + The ``path`` parameter has been deprecated in favor of ``fspath``. + """ + + +@hookspec(firstresult=True) +def pytest_pycollect_makeitem( + collector: Union["Module", "Class"], name: str, obj: object +) -> Union[None, "Item", "Collector", List[Union["Item", "Collector"]]]: + """Return a custom item/collector for a Python object in a module, or None. + + Stops at first non-None result, see :ref:`firstresult`. + + :param collector: + The module/class collector. + :param name: + The name of the object in the module/class. + :param obj: + The object. + :returns: + The created items/collectors. + """ + + +@hookspec(firstresult=True) +def pytest_pyfunc_call(pyfuncitem: "Function") -> Optional[object]: + """Call underlying test function. + + Stops at first non-None result, see :ref:`firstresult`. + + :param pyfuncitem: + The function item. + """ + + +def pytest_generate_tests(metafunc: "Metafunc") -> None: + """Generate (multiple) parametrized calls to a test function. + + :param metafunc: + The :class:`~pytest.Metafunc` helper for the test function. + """ + + +@hookspec(firstresult=True) +def pytest_make_parametrize_id( + config: "Config", val: object, argname: str +) -> Optional[str]: + """Return a user-friendly string representation of the given ``val`` + that will be used by @pytest.mark.parametrize calls, or None if the hook + doesn't know about ``val``. + + The parameter name is available as ``argname``, if required. + + Stops at first non-None result, see :ref:`firstresult`. + + :param config: The pytest config object. + :param val: The parametrized value. + :param str argname: The automatic parameter name produced by pytest. + """ + + +# ------------------------------------------------------------------------- +# runtest related hooks +# ------------------------------------------------------------------------- + + +@hookspec(firstresult=True) +def pytest_runtestloop(session: "Session") -> Optional[object]: + """Perform the main runtest loop (after collection finished). + + The default hook implementation performs the runtest protocol for all items + collected in the session (``session.items``), unless the collection failed + or the ``collectonly`` pytest option is set. + + If at any point :py:func:`pytest.exit` is called, the loop is + terminated immediately. + + If at any point ``session.shouldfail`` or ``session.shouldstop`` are set, the + loop is terminated after the runtest protocol for the current item is finished. + + :param session: The pytest session object. + + Stops at first non-None result, see :ref:`firstresult`. + The return value is not used, but only stops further processing. + """ + + +@hookspec(firstresult=True) +def pytest_runtest_protocol( + item: "Item", nextitem: "Optional[Item]" +) -> Optional[object]: + """Perform the runtest protocol for a single test item. + + The default runtest protocol is this (see individual hooks for full details): + + - ``pytest_runtest_logstart(nodeid, location)`` + + - Setup phase: + - ``call = pytest_runtest_setup(item)`` (wrapped in ``CallInfo(when="setup")``) + - ``report = pytest_runtest_makereport(item, call)`` + - ``pytest_runtest_logreport(report)`` + - ``pytest_exception_interact(call, report)`` if an interactive exception occurred + + - Call phase, if the the setup passed and the ``setuponly`` pytest option is not set: + - ``call = pytest_runtest_call(item)`` (wrapped in ``CallInfo(when="call")``) + - ``report = pytest_runtest_makereport(item, call)`` + - ``pytest_runtest_logreport(report)`` + - ``pytest_exception_interact(call, report)`` if an interactive exception occurred + + - Teardown phase: + - ``call = pytest_runtest_teardown(item, nextitem)`` (wrapped in ``CallInfo(when="teardown")``) + - ``report = pytest_runtest_makereport(item, call)`` + - ``pytest_runtest_logreport(report)`` + - ``pytest_exception_interact(call, report)`` if an interactive exception occurred + + - ``pytest_runtest_logfinish(nodeid, location)`` + + :param item: Test item for which the runtest protocol is performed. + :param nextitem: The scheduled-to-be-next test item (or None if this is the end my friend). + + Stops at first non-None result, see :ref:`firstresult`. + The return value is not used, but only stops further processing. + """ + + +def pytest_runtest_logstart( + nodeid: str, location: Tuple[str, Optional[int], str] +) -> None: + """Called at the start of running the runtest protocol for a single item. + + See :hook:`pytest_runtest_protocol` for a description of the runtest protocol. + + :param nodeid: Full node ID of the item. + :param location: A tuple of ``(filename, lineno, testname)`` + where ``filename`` is a file path relative to ``config.rootpath`` + and ``lineno`` is 0-based. + """ + + +def pytest_runtest_logfinish( + nodeid: str, location: Tuple[str, Optional[int], str] +) -> None: + """Called at the end of running the runtest protocol for a single item. + + See :hook:`pytest_runtest_protocol` for a description of the runtest protocol. + + :param nodeid: Full node ID of the item. + :param location: A tuple of ``(filename, lineno, testname)`` + where ``filename`` is a file path relative to ``config.rootpath`` + and ``lineno`` is 0-based. + """ + + +def pytest_runtest_setup(item: "Item") -> None: + """Called to perform the setup phase for a test item. + + The default implementation runs ``setup()`` on ``item`` and all of its + parents (which haven't been setup yet). This includes obtaining the + values of fixtures required by the item (which haven't been obtained + yet). + + :param item: + The item. + """ + + +def pytest_runtest_call(item: "Item") -> None: + """Called to run the test for test item (the call phase). + + The default implementation calls ``item.runtest()``. + + :param item: + The item. + """ + + +def pytest_runtest_teardown(item: "Item", nextitem: Optional["Item"]) -> None: + """Called to perform the teardown phase for a test item. + + The default implementation runs the finalizers and calls ``teardown()`` + on ``item`` and all of its parents (which need to be torn down). This + includes running the teardown phase of fixtures required by the item (if + they go out of scope). + + :param item: + The item. + :param nextitem: + The scheduled-to-be-next test item (None if no further test item is + scheduled). This argument is used to perform exact teardowns, i.e. + calling just enough finalizers so that nextitem only needs to call + setup functions. + """ + + +@hookspec(firstresult=True) +def pytest_runtest_makereport( + item: "Item", call: "CallInfo[None]" +) -> Optional["TestReport"]: + """Called to create a :class:`~pytest.TestReport` for each of + the setup, call and teardown runtest phases of a test item. + + See :hook:`pytest_runtest_protocol` for a description of the runtest protocol. + + :param item: The item. + :param call: The :class:`~pytest.CallInfo` for the phase. + + Stops at first non-None result, see :ref:`firstresult`. + """ + + +def pytest_runtest_logreport(report: "TestReport") -> None: + """Process the :class:`~pytest.TestReport` produced for each + of the setup, call and teardown runtest phases of an item. + + See :hook:`pytest_runtest_protocol` for a description of the runtest protocol. + """ + + +@hookspec(firstresult=True) +def pytest_report_to_serializable( + config: "Config", + report: Union["CollectReport", "TestReport"], +) -> Optional[Dict[str, Any]]: + """Serialize the given report object into a data structure suitable for + sending over the wire, e.g. converted to JSON. + + :param config: The pytest config object. + :param report: The report. + """ + + +@hookspec(firstresult=True) +def pytest_report_from_serializable( + config: "Config", + data: Dict[str, Any], +) -> Optional[Union["CollectReport", "TestReport"]]: + """Restore a report object previously serialized with + :hook:`pytest_report_to_serializable`. + + :param config: The pytest config object. + """ + + +# ------------------------------------------------------------------------- +# Fixture related hooks +# ------------------------------------------------------------------------- + + +@hookspec(firstresult=True) +def pytest_fixture_setup( + fixturedef: "FixtureDef[Any]", request: "SubRequest" +) -> Optional[object]: + """Perform fixture setup execution. + + :param fixturdef: + The fixture definition object. + :param request: + The fixture request object. + :returns: + The return value of the call to the fixture function. + + Stops at first non-None result, see :ref:`firstresult`. + + .. note:: + If the fixture function returns None, other implementations of + this hook function will continue to be called, according to the + behavior of the :ref:`firstresult` option. + """ + + +def pytest_fixture_post_finalizer( + fixturedef: "FixtureDef[Any]", request: "SubRequest" +) -> None: + """Called after fixture teardown, but before the cache is cleared, so + the fixture result ``fixturedef.cached_result`` is still available (not + ``None``). + + :param fixturdef: + The fixture definition object. + :param request: + The fixture request object. + """ + + +# ------------------------------------------------------------------------- +# test session related hooks +# ------------------------------------------------------------------------- + + +def pytest_sessionstart(session: "Session") -> None: + """Called after the ``Session`` object has been created and before performing collection + and entering the run test loop. + + :param session: The pytest session object. + """ + + +def pytest_sessionfinish( + session: "Session", + exitstatus: Union[int, "ExitCode"], +) -> None: + """Called after whole test run finished, right before returning the exit status to the system. + + :param session: The pytest session object. + :param exitstatus: The status which pytest will return to the system. + """ + + +def pytest_unconfigure(config: "Config") -> None: + """Called before test process is exited. + + :param config: The pytest config object. + """ + + +# ------------------------------------------------------------------------- +# hooks for customizing the assert methods +# ------------------------------------------------------------------------- + + +def pytest_assertrepr_compare( + config: "Config", op: str, left: object, right: object +) -> Optional[List[str]]: + """Return explanation for comparisons in failing assert expressions. + + Return None for no custom explanation, otherwise return a list + of strings. The strings will be joined by newlines but any newlines + *in* a string will be escaped. Note that all but the first line will + be indented slightly, the intention is for the first line to be a summary. + + :param config: The pytest config object. + :param op: The operator, e.g. `"=="`, `"!="`, `"not in"`. + :param left: The left operand. + :param right: The right operand. + """ + + +def pytest_assertion_pass(item: "Item", lineno: int, orig: str, expl: str) -> None: + """Called whenever an assertion passes. + + .. versionadded:: 5.0 + + Use this hook to do some processing after a passing assertion. + The original assertion information is available in the `orig` string + and the pytest introspected assertion information is available in the + `expl` string. + + This hook must be explicitly enabled by the ``enable_assertion_pass_hook`` + ini-file option: + + .. code-block:: ini + + [pytest] + enable_assertion_pass_hook=true + + You need to **clean the .pyc** files in your project directory and interpreter libraries + when enabling this option, as assertions will require to be re-written. + + :param item: pytest item object of current test. + :param lineno: Line number of the assert statement. + :param orig: String with the original assertion. + :param expl: String with the assert explanation. + """ + + +# ------------------------------------------------------------------------- +# Hooks for influencing reporting (invoked from _pytest_terminal). +# ------------------------------------------------------------------------- + + +def pytest_report_header( # type:ignore[empty-body] + config: "Config", start_path: Path, startdir: "LEGACY_PATH" +) -> Union[str, List[str]]: + """Return a string or list of strings to be displayed as header info for terminal reporting. + + :param config: The pytest config object. + :param start_path: The starting dir. + :param startdir: The starting dir (deprecated). + + .. note:: + + Lines returned by a plugin are displayed before those of plugins which + ran before it. + If you want to have your line(s) displayed first, use + :ref:`trylast=True `. + + .. note:: + + This function should be implemented only in plugins or ``conftest.py`` + files situated at the tests root directory due to how pytest + :ref:`discovers plugins during startup `. + + .. versionchanged:: 7.0.0 + The ``start_path`` parameter was added as a :class:`pathlib.Path` + equivalent of the ``startdir`` parameter. The ``startdir`` parameter + has been deprecated. + """ + + +def pytest_report_collectionfinish( # type:ignore[empty-body] + config: "Config", + start_path: Path, + startdir: "LEGACY_PATH", + items: Sequence["Item"], +) -> Union[str, List[str]]: + """Return a string or list of strings to be displayed after collection + has finished successfully. + + These strings will be displayed after the standard "collected X items" message. + + .. versionadded:: 3.2 + + :param config: The pytest config object. + :param start_path: The starting dir. + :param startdir: The starting dir (deprecated). + :param items: List of pytest items that are going to be executed; this list should not be modified. + + .. note:: + + Lines returned by a plugin are displayed before those of plugins which + ran before it. + If you want to have your line(s) displayed first, use + :ref:`trylast=True `. + + .. versionchanged:: 7.0.0 + The ``start_path`` parameter was added as a :class:`pathlib.Path` + equivalent of the ``startdir`` parameter. The ``startdir`` parameter + has been deprecated. + """ + + +@hookspec(firstresult=True) +def pytest_report_teststatus( # type:ignore[empty-body] + report: Union["CollectReport", "TestReport"], config: "Config" +) -> "TestShortLogReport | Tuple[str, str, Union[str, Tuple[str, Mapping[str, bool]]]]": + """Return result-category, shortletter and verbose word for status + reporting. + + The result-category is a category in which to count the result, for + example "passed", "skipped", "error" or the empty string. + + The shortletter is shown as testing progresses, for example ".", "s", + "E" or the empty string. + + The verbose word is shown as testing progresses in verbose mode, for + example "PASSED", "SKIPPED", "ERROR" or the empty string. + + pytest may style these implicitly according to the report outcome. + To provide explicit styling, return a tuple for the verbose word, + for example ``"rerun", "R", ("RERUN", {"yellow": True})``. + + :param report: The report object whose status is to be returned. + :param config: The pytest config object. + :returns: The test status. + + Stops at first non-None result, see :ref:`firstresult`. + """ + + +def pytest_terminal_summary( + terminalreporter: "TerminalReporter", + exitstatus: "ExitCode", + config: "Config", +) -> None: + """Add a section to terminal summary reporting. + + :param terminalreporter: The internal terminal reporter object. + :param exitstatus: The exit status that will be reported back to the OS. + :param config: The pytest config object. + + .. versionadded:: 4.2 + The ``config`` parameter. + """ + + +@hookspec(historic=True) +def pytest_warning_recorded( + warning_message: "warnings.WarningMessage", + when: "Literal['config', 'collect', 'runtest']", + nodeid: str, + location: Optional[Tuple[str, int, str]], +) -> None: + """Process a warning captured by the internal pytest warnings plugin. + + :param warning_message: + The captured warning. This is the same object produced by :py:func:`warnings.catch_warnings`, and contains + the same attributes as the parameters of :py:func:`warnings.showwarning`. + + :param when: + Indicates when the warning was captured. Possible values: + + * ``"config"``: during pytest configuration/initialization stage. + * ``"collect"``: during test collection. + * ``"runtest"``: during test execution. + + :param nodeid: + Full id of the item. + + :param location: + When available, holds information about the execution context of the captured + warning (filename, linenumber, function). ``function`` evaluates to + when the execution context is at the module level. + + .. versionadded:: 6.0 + """ + + +# ------------------------------------------------------------------------- +# Hooks for influencing skipping +# ------------------------------------------------------------------------- + + +def pytest_markeval_namespace( # type:ignore[empty-body] + config: "Config", +) -> Dict[str, Any]: + """Called when constructing the globals dictionary used for + evaluating string conditions in xfail/skipif markers. + + This is useful when the condition for a marker requires + objects that are expensive or impossible to obtain during + collection time, which is required by normal boolean + conditions. + + .. versionadded:: 6.2 + + :param config: The pytest config object. + :returns: A dictionary of additional globals to add. + """ + + +# ------------------------------------------------------------------------- +# error handling and internal debugging hooks +# ------------------------------------------------------------------------- + + +def pytest_internalerror( + excrepr: "ExceptionRepr", + excinfo: "ExceptionInfo[BaseException]", +) -> Optional[bool]: + """Called for internal errors. + + Return True to suppress the fallback handling of printing an + INTERNALERROR message directly to sys.stderr. + + :param excrepr: The exception repr object. + :param excinfo: The exception info. + """ + + +def pytest_keyboard_interrupt( + excinfo: "ExceptionInfo[Union[KeyboardInterrupt, Exit]]", +) -> None: + """Called for keyboard interrupt. + + :param excinfo: The exception info. + """ + + +def pytest_exception_interact( + node: Union["Item", "Collector"], + call: "CallInfo[Any]", + report: Union["CollectReport", "TestReport"], +) -> None: + """Called when an exception was raised which can potentially be + interactively handled. + + May be called during collection (see :hook:`pytest_make_collect_report`), + in which case ``report`` is a :class:`CollectReport`. + + May be called during runtest of an item (see :hook:`pytest_runtest_protocol`), + in which case ``report`` is a :class:`TestReport`. + + This hook is not called if the exception that was raised is an internal + exception like ``skip.Exception``. + + :param node: + The item or collector. + :param call: + The call information. Contains the exception. + :param report: + The collection or test report. + """ + + +def pytest_enter_pdb(config: "Config", pdb: "pdb.Pdb") -> None: + """Called upon pdb.set_trace(). + + Can be used by plugins to take special action just before the python + debugger enters interactive mode. + + :param config: The pytest config object. + :param pdb: The Pdb instance. + """ + + +def pytest_leave_pdb(config: "Config", pdb: "pdb.Pdb") -> None: + """Called when leaving pdb (e.g. with continue after pdb.set_trace()). + + Can be used by plugins to take special action just after the python + debugger leaves interactive mode. + + :param config: The pytest config object. + :param pdb: The Pdb instance. + """ diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/junitxml.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/junitxml.py new file mode 100644 index 000000000..ed259e4c4 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/junitxml.py @@ -0,0 +1,700 @@ +"""Report test results in JUnit-XML format, for use with Jenkins and build +integration servers. + +Based on initial code from Ross Lawley. + +Output conforms to +https://github.com/jenkinsci/xunit-plugin/blob/master/src/main/resources/org/jenkinsci/plugins/xunit/types/model/xsd/junit-10.xsd +""" +import functools +import os +import platform +import re +import xml.etree.ElementTree as ET +from datetime import datetime +from typing import Callable +from typing import Dict +from typing import List +from typing import Match +from typing import Optional +from typing import Tuple +from typing import Union + +import pytest +from _pytest import nodes +from _pytest import timing +from _pytest._code.code import ExceptionRepr +from _pytest._code.code import ReprFileLocation +from _pytest.config import Config +from _pytest.config import filename_arg +from _pytest.config.argparsing import Parser +from _pytest.fixtures import FixtureRequest +from _pytest.reports import TestReport +from _pytest.stash import StashKey +from _pytest.terminal import TerminalReporter + + +xml_key = StashKey["LogXML"]() + + +def bin_xml_escape(arg: object) -> str: + r"""Visually escape invalid XML characters. + + For example, transforms + 'hello\aworld\b' + into + 'hello#x07world#x08' + Note that the #xABs are *not* XML escapes - missing the ampersand «. + The idea is to escape visually for the user rather than for XML itself. + """ + + def repl(matchobj: Match[str]) -> str: + i = ord(matchobj.group()) + if i <= 0xFF: + return "#x%02X" % i + else: + return "#x%04X" % i + + # The spec range of valid chars is: + # Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] + # For an unknown(?) reason, we disallow #x7F (DEL) as well. + illegal_xml_re = ( + "[^\u0009\u000A\u000D\u0020-\u007E\u0080-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]" + ) + return re.sub(illegal_xml_re, repl, str(arg)) + + +def merge_family(left, right) -> None: + result = {} + for kl, vl in left.items(): + for kr, vr in right.items(): + if not isinstance(vl, list): + raise TypeError(type(vl)) + result[kl] = vl + vr + left.update(result) + + +families = {} +families["_base"] = {"testcase": ["classname", "name"]} +families["_base_legacy"] = {"testcase": ["file", "line", "url"]} + +# xUnit 1.x inherits legacy attributes. +families["xunit1"] = families["_base"].copy() +merge_family(families["xunit1"], families["_base_legacy"]) + +# xUnit 2.x uses strict base attributes. +families["xunit2"] = families["_base"] + + +class _NodeReporter: + def __init__(self, nodeid: Union[str, TestReport], xml: "LogXML") -> None: + self.id = nodeid + self.xml = xml + self.add_stats = self.xml.add_stats + self.family = self.xml.family + self.duration = 0.0 + self.properties: List[Tuple[str, str]] = [] + self.nodes: List[ET.Element] = [] + self.attrs: Dict[str, str] = {} + + def append(self, node: ET.Element) -> None: + self.xml.add_stats(node.tag) + self.nodes.append(node) + + def add_property(self, name: str, value: object) -> None: + self.properties.append((str(name), bin_xml_escape(value))) + + def add_attribute(self, name: str, value: object) -> None: + self.attrs[str(name)] = bin_xml_escape(value) + + def make_properties_node(self) -> Optional[ET.Element]: + """Return a Junit node containing custom properties, if any.""" + if self.properties: + properties = ET.Element("properties") + for name, value in self.properties: + properties.append(ET.Element("property", name=name, value=value)) + return properties + return None + + def record_testreport(self, testreport: TestReport) -> None: + names = mangle_test_address(testreport.nodeid) + existing_attrs = self.attrs + classnames = names[:-1] + if self.xml.prefix: + classnames.insert(0, self.xml.prefix) + attrs: Dict[str, str] = { + "classname": ".".join(classnames), + "name": bin_xml_escape(names[-1]), + "file": testreport.location[0], + } + if testreport.location[1] is not None: + attrs["line"] = str(testreport.location[1]) + if hasattr(testreport, "url"): + attrs["url"] = testreport.url + self.attrs = attrs + self.attrs.update(existing_attrs) # Restore any user-defined attributes. + + # Preserve legacy testcase behavior. + if self.family == "xunit1": + return + + # Filter out attributes not permitted by this test family. + # Including custom attributes because they are not valid here. + temp_attrs = {} + for key in self.attrs.keys(): + if key in families[self.family]["testcase"]: + temp_attrs[key] = self.attrs[key] + self.attrs = temp_attrs + + def to_xml(self) -> ET.Element: + testcase = ET.Element("testcase", self.attrs, time="%.3f" % self.duration) + properties = self.make_properties_node() + if properties is not None: + testcase.append(properties) + testcase.extend(self.nodes) + return testcase + + def _add_simple(self, tag: str, message: str, data: Optional[str] = None) -> None: + node = ET.Element(tag, message=message) + node.text = bin_xml_escape(data) + self.append(node) + + def write_captured_output(self, report: TestReport) -> None: + if not self.xml.log_passing_tests and report.passed: + return + + content_out = report.capstdout + content_log = report.caplog + content_err = report.capstderr + if self.xml.logging == "no": + return + content_all = "" + if self.xml.logging in ["log", "all"]: + content_all = self._prepare_content(content_log, " Captured Log ") + if self.xml.logging in ["system-out", "out-err", "all"]: + content_all += self._prepare_content(content_out, " Captured Out ") + self._write_content(report, content_all, "system-out") + content_all = "" + if self.xml.logging in ["system-err", "out-err", "all"]: + content_all += self._prepare_content(content_err, " Captured Err ") + self._write_content(report, content_all, "system-err") + content_all = "" + if content_all: + self._write_content(report, content_all, "system-out") + + def _prepare_content(self, content: str, header: str) -> str: + return "\n".join([header.center(80, "-"), content, ""]) + + def _write_content(self, report: TestReport, content: str, jheader: str) -> None: + tag = ET.Element(jheader) + tag.text = bin_xml_escape(content) + self.append(tag) + + def append_pass(self, report: TestReport) -> None: + self.add_stats("passed") + + def append_failure(self, report: TestReport) -> None: + # msg = str(report.longrepr.reprtraceback.extraline) + if hasattr(report, "wasxfail"): + self._add_simple("skipped", "xfail-marked test passes unexpectedly") + else: + assert report.longrepr is not None + reprcrash: Optional[ReprFileLocation] = getattr( + report.longrepr, "reprcrash", None + ) + if reprcrash is not None: + message = reprcrash.message + else: + message = str(report.longrepr) + message = bin_xml_escape(message) + self._add_simple("failure", message, str(report.longrepr)) + + def append_collect_error(self, report: TestReport) -> None: + # msg = str(report.longrepr.reprtraceback.extraline) + assert report.longrepr is not None + self._add_simple("error", "collection failure", str(report.longrepr)) + + def append_collect_skipped(self, report: TestReport) -> None: + self._add_simple("skipped", "collection skipped", str(report.longrepr)) + + def append_error(self, report: TestReport) -> None: + assert report.longrepr is not None + reprcrash: Optional[ReprFileLocation] = getattr( + report.longrepr, "reprcrash", None + ) + if reprcrash is not None: + reason = reprcrash.message + else: + reason = str(report.longrepr) + + if report.when == "teardown": + msg = f'failed on teardown with "{reason}"' + else: + msg = f'failed on setup with "{reason}"' + self._add_simple("error", bin_xml_escape(msg), str(report.longrepr)) + + def append_skipped(self, report: TestReport) -> None: + if hasattr(report, "wasxfail"): + xfailreason = report.wasxfail + if xfailreason.startswith("reason: "): + xfailreason = xfailreason[8:] + xfailreason = bin_xml_escape(xfailreason) + skipped = ET.Element("skipped", type="pytest.xfail", message=xfailreason) + self.append(skipped) + else: + assert isinstance(report.longrepr, tuple) + filename, lineno, skipreason = report.longrepr + if skipreason.startswith("Skipped: "): + skipreason = skipreason[9:] + details = f"{filename}:{lineno}: {skipreason}" + + skipped = ET.Element("skipped", type="pytest.skip", message=skipreason) + skipped.text = bin_xml_escape(details) + self.append(skipped) + self.write_captured_output(report) + + def finalize(self) -> None: + data = self.to_xml() + self.__dict__.clear() + # Type ignored because mypy doesn't like overriding a method. + # Also the return value doesn't match... + self.to_xml = lambda: data # type: ignore[assignment] + + +def _warn_incompatibility_with_xunit2( + request: FixtureRequest, fixture_name: str +) -> None: + """Emit a PytestWarning about the given fixture being incompatible with newer xunit revisions.""" + from _pytest.warning_types import PytestWarning + + xml = request.config.stash.get(xml_key, None) + if xml is not None and xml.family not in ("xunit1", "legacy"): + request.node.warn( + PytestWarning( + "{fixture_name} is incompatible with junit_family '{family}' (use 'legacy' or 'xunit1')".format( + fixture_name=fixture_name, family=xml.family + ) + ) + ) + + +@pytest.fixture +def record_property(request: FixtureRequest) -> Callable[[str, object], None]: + """Add extra properties to the calling test. + + User properties become part of the test report and are available to the + configured reporters, like JUnit XML. + + The fixture is callable with ``name, value``. The value is automatically + XML-encoded. + + Example:: + + def test_function(record_property): + record_property("example_key", 1) + """ + _warn_incompatibility_with_xunit2(request, "record_property") + + def append_property(name: str, value: object) -> None: + request.node.user_properties.append((name, value)) + + return append_property + + +@pytest.fixture +def record_xml_attribute(request: FixtureRequest) -> Callable[[str, object], None]: + """Add extra xml attributes to the tag for the calling test. + + The fixture is callable with ``name, value``. The value is + automatically XML-encoded. + """ + from _pytest.warning_types import PytestExperimentalApiWarning + + request.node.warn( + PytestExperimentalApiWarning("record_xml_attribute is an experimental feature") + ) + + _warn_incompatibility_with_xunit2(request, "record_xml_attribute") + + # Declare noop + def add_attr_noop(name: str, value: object) -> None: + pass + + attr_func = add_attr_noop + + xml = request.config.stash.get(xml_key, None) + if xml is not None: + node_reporter = xml.node_reporter(request.node.nodeid) + attr_func = node_reporter.add_attribute + + return attr_func + + +def _check_record_param_type(param: str, v: str) -> None: + """Used by record_testsuite_property to check that the given parameter name is of the proper + type.""" + __tracebackhide__ = True + if not isinstance(v, str): + msg = "{param} parameter needs to be a string, but {g} given" # type: ignore[unreachable] + raise TypeError(msg.format(param=param, g=type(v).__name__)) + + +@pytest.fixture(scope="session") +def record_testsuite_property(request: FixtureRequest) -> Callable[[str, object], None]: + """Record a new ```` tag as child of the root ````. + + This is suitable to writing global information regarding the entire test + suite, and is compatible with ``xunit2`` JUnit family. + + This is a ``session``-scoped fixture which is called with ``(name, value)``. Example: + + .. code-block:: python + + def test_foo(record_testsuite_property): + record_testsuite_property("ARCH", "PPC") + record_testsuite_property("STORAGE_TYPE", "CEPH") + + :param name: + The property name. + :param value: + The property value. Will be converted to a string. + + .. warning:: + + Currently this fixture **does not work** with the + `pytest-xdist `__ plugin. See + :issue:`7767` for details. + """ + + __tracebackhide__ = True + + def record_func(name: str, value: object) -> None: + """No-op function in case --junitxml was not passed in the command-line.""" + __tracebackhide__ = True + _check_record_param_type("name", name) + + xml = request.config.stash.get(xml_key, None) + if xml is not None: + record_func = xml.add_global_property # noqa + return record_func + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("terminal reporting") + group.addoption( + "--junitxml", + "--junit-xml", + action="store", + dest="xmlpath", + metavar="path", + type=functools.partial(filename_arg, optname="--junitxml"), + default=None, + help="Create junit-xml style report file at given path", + ) + group.addoption( + "--junitprefix", + "--junit-prefix", + action="store", + metavar="str", + default=None, + help="Prepend prefix to classnames in junit-xml output", + ) + parser.addini( + "junit_suite_name", "Test suite name for JUnit report", default="pytest" + ) + parser.addini( + "junit_logging", + "Write captured log messages to JUnit report: " + "one of no|log|system-out|system-err|out-err|all", + default="no", + ) + parser.addini( + "junit_log_passing_tests", + "Capture log information for passing tests to JUnit report: ", + type="bool", + default=True, + ) + parser.addini( + "junit_duration_report", + "Duration time to report: one of total|call", + default="total", + ) # choices=['total', 'call']) + parser.addini( + "junit_family", + "Emit XML for schema: one of legacy|xunit1|xunit2", + default="xunit2", + ) + + +def pytest_configure(config: Config) -> None: + xmlpath = config.option.xmlpath + # Prevent opening xmllog on worker nodes (xdist). + if xmlpath and not hasattr(config, "workerinput"): + junit_family = config.getini("junit_family") + config.stash[xml_key] = LogXML( + xmlpath, + config.option.junitprefix, + config.getini("junit_suite_name"), + config.getini("junit_logging"), + config.getini("junit_duration_report"), + junit_family, + config.getini("junit_log_passing_tests"), + ) + config.pluginmanager.register(config.stash[xml_key]) + + +def pytest_unconfigure(config: Config) -> None: + xml = config.stash.get(xml_key, None) + if xml: + del config.stash[xml_key] + config.pluginmanager.unregister(xml) + + +def mangle_test_address(address: str) -> List[str]: + path, possible_open_bracket, params = address.partition("[") + names = path.split("::") + # Convert file path to dotted path. + names[0] = names[0].replace(nodes.SEP, ".") + names[0] = re.sub(r"\.py$", "", names[0]) + # Put any params back. + names[-1] += possible_open_bracket + params + return names + + +class LogXML: + def __init__( + self, + logfile, + prefix: Optional[str], + suite_name: str = "pytest", + logging: str = "no", + report_duration: str = "total", + family="xunit1", + log_passing_tests: bool = True, + ) -> None: + logfile = os.path.expanduser(os.path.expandvars(logfile)) + self.logfile = os.path.normpath(os.path.abspath(logfile)) + self.prefix = prefix + self.suite_name = suite_name + self.logging = logging + self.log_passing_tests = log_passing_tests + self.report_duration = report_duration + self.family = family + self.stats: Dict[str, int] = dict.fromkeys( + ["error", "passed", "failure", "skipped"], 0 + ) + self.node_reporters: Dict[ + Tuple[Union[str, TestReport], object], _NodeReporter + ] = {} + self.node_reporters_ordered: List[_NodeReporter] = [] + self.global_properties: List[Tuple[str, str]] = [] + + # List of reports that failed on call but teardown is pending. + self.open_reports: List[TestReport] = [] + self.cnt_double_fail_tests = 0 + + # Replaces convenience family with real family. + if self.family == "legacy": + self.family = "xunit1" + + def finalize(self, report: TestReport) -> None: + nodeid = getattr(report, "nodeid", report) + # Local hack to handle xdist report order. + workernode = getattr(report, "node", None) + reporter = self.node_reporters.pop((nodeid, workernode)) + + for propname, propvalue in report.user_properties: + reporter.add_property(propname, str(propvalue)) + + if reporter is not None: + reporter.finalize() + + def node_reporter(self, report: Union[TestReport, str]) -> _NodeReporter: + nodeid: Union[str, TestReport] = getattr(report, "nodeid", report) + # Local hack to handle xdist report order. + workernode = getattr(report, "node", None) + + key = nodeid, workernode + + if key in self.node_reporters: + # TODO: breaks for --dist=each + return self.node_reporters[key] + + reporter = _NodeReporter(nodeid, self) + + self.node_reporters[key] = reporter + self.node_reporters_ordered.append(reporter) + + return reporter + + def add_stats(self, key: str) -> None: + if key in self.stats: + self.stats[key] += 1 + + def _opentestcase(self, report: TestReport) -> _NodeReporter: + reporter = self.node_reporter(report) + reporter.record_testreport(report) + return reporter + + def pytest_runtest_logreport(self, report: TestReport) -> None: + """Handle a setup/call/teardown report, generating the appropriate + XML tags as necessary. + + Note: due to plugins like xdist, this hook may be called in interlaced + order with reports from other nodes. For example: + + Usual call order: + -> setup node1 + -> call node1 + -> teardown node1 + -> setup node2 + -> call node2 + -> teardown node2 + + Possible call order in xdist: + -> setup node1 + -> call node1 + -> setup node2 + -> call node2 + -> teardown node2 + -> teardown node1 + """ + close_report = None + if report.passed: + if report.when == "call": # ignore setup/teardown + reporter = self._opentestcase(report) + reporter.append_pass(report) + elif report.failed: + if report.when == "teardown": + # The following vars are needed when xdist plugin is used. + report_wid = getattr(report, "worker_id", None) + report_ii = getattr(report, "item_index", None) + close_report = next( + ( + rep + for rep in self.open_reports + if ( + rep.nodeid == report.nodeid + and getattr(rep, "item_index", None) == report_ii + and getattr(rep, "worker_id", None) == report_wid + ) + ), + None, + ) + if close_report: + # We need to open new testcase in case we have failure in + # call and error in teardown in order to follow junit + # schema. + self.finalize(close_report) + self.cnt_double_fail_tests += 1 + reporter = self._opentestcase(report) + if report.when == "call": + reporter.append_failure(report) + self.open_reports.append(report) + if not self.log_passing_tests: + reporter.write_captured_output(report) + else: + reporter.append_error(report) + elif report.skipped: + reporter = self._opentestcase(report) + reporter.append_skipped(report) + self.update_testcase_duration(report) + if report.when == "teardown": + reporter = self._opentestcase(report) + reporter.write_captured_output(report) + + self.finalize(report) + report_wid = getattr(report, "worker_id", None) + report_ii = getattr(report, "item_index", None) + close_report = next( + ( + rep + for rep in self.open_reports + if ( + rep.nodeid == report.nodeid + and getattr(rep, "item_index", None) == report_ii + and getattr(rep, "worker_id", None) == report_wid + ) + ), + None, + ) + if close_report: + self.open_reports.remove(close_report) + + def update_testcase_duration(self, report: TestReport) -> None: + """Accumulate total duration for nodeid from given report and update + the Junit.testcase with the new total if already created.""" + if self.report_duration == "total" or report.when == self.report_duration: + reporter = self.node_reporter(report) + reporter.duration += getattr(report, "duration", 0.0) + + def pytest_collectreport(self, report: TestReport) -> None: + if not report.passed: + reporter = self._opentestcase(report) + if report.failed: + reporter.append_collect_error(report) + else: + reporter.append_collect_skipped(report) + + def pytest_internalerror(self, excrepr: ExceptionRepr) -> None: + reporter = self.node_reporter("internal") + reporter.attrs.update(classname="pytest", name="internal") + reporter._add_simple("error", "internal error", str(excrepr)) + + def pytest_sessionstart(self) -> None: + self.suite_start_time = timing.time() + + def pytest_sessionfinish(self) -> None: + dirname = os.path.dirname(os.path.abspath(self.logfile)) + # exist_ok avoids filesystem race conditions between checking path existence and requesting creation + os.makedirs(dirname, exist_ok=True) + + with open(self.logfile, "w", encoding="utf-8") as logfile: + suite_stop_time = timing.time() + suite_time_delta = suite_stop_time - self.suite_start_time + + numtests = ( + self.stats["passed"] + + self.stats["failure"] + + self.stats["skipped"] + + self.stats["error"] + - self.cnt_double_fail_tests + ) + logfile.write('') + + suite_node = ET.Element( + "testsuite", + name=self.suite_name, + errors=str(self.stats["error"]), + failures=str(self.stats["failure"]), + skipped=str(self.stats["skipped"]), + tests=str(numtests), + time="%.3f" % suite_time_delta, + timestamp=datetime.fromtimestamp(self.suite_start_time).isoformat(), + hostname=platform.node(), + ) + global_properties = self._get_global_properties_node() + if global_properties is not None: + suite_node.append(global_properties) + for node_reporter in self.node_reporters_ordered: + suite_node.append(node_reporter.to_xml()) + testsuites = ET.Element("testsuites") + testsuites.append(suite_node) + logfile.write(ET.tostring(testsuites, encoding="unicode")) + + def pytest_terminal_summary(self, terminalreporter: TerminalReporter) -> None: + terminalreporter.write_sep("-", f"generated xml file: {self.logfile}") + + def add_global_property(self, name: str, value: object) -> None: + __tracebackhide__ = True + _check_record_param_type("name", name) + self.global_properties.append((name, bin_xml_escape(value))) + + def _get_global_properties_node(self) -> Optional[ET.Element]: + """Return a Junit node containing custom properties, if any.""" + if self.global_properties: + properties = ET.Element("properties") + for name, value in self.global_properties: + properties.append(ET.Element("property", name=name, value=value)) + return properties + return None diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/legacypath.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/legacypath.py new file mode 100644 index 000000000..af1d0c07e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/legacypath.py @@ -0,0 +1,479 @@ +"""Add backward compatibility support for the legacy py path type.""" +import dataclasses +import shlex +import subprocess +from pathlib import Path +from typing import List +from typing import Optional +from typing import TYPE_CHECKING +from typing import Union + +from iniconfig import SectionWrapper + +from _pytest.cacheprovider import Cache +from _pytest.compat import final +from _pytest.compat import LEGACY_PATH +from _pytest.compat import legacy_path +from _pytest.config import Config +from _pytest.config import hookimpl +from _pytest.config import PytestPluginManager +from _pytest.deprecated import check_ispytest +from _pytest.fixtures import fixture +from _pytest.fixtures import FixtureRequest +from _pytest.main import Session +from _pytest.monkeypatch import MonkeyPatch +from _pytest.nodes import Collector +from _pytest.nodes import Item +from _pytest.nodes import Node +from _pytest.pytester import HookRecorder +from _pytest.pytester import Pytester +from _pytest.pytester import RunResult +from _pytest.terminal import TerminalReporter +from _pytest.tmpdir import TempPathFactory + +if TYPE_CHECKING: + from typing_extensions import Final + + import pexpect + + +@final +class Testdir: + """ + Similar to :class:`Pytester`, but this class works with legacy legacy_path objects instead. + + All methods just forward to an internal :class:`Pytester` instance, converting results + to `legacy_path` objects as necessary. + """ + + __test__ = False + + CLOSE_STDIN: "Final" = Pytester.CLOSE_STDIN + TimeoutExpired: "Final" = Pytester.TimeoutExpired + + def __init__(self, pytester: Pytester, *, _ispytest: bool = False) -> None: + check_ispytest(_ispytest) + self._pytester = pytester + + @property + def tmpdir(self) -> LEGACY_PATH: + """Temporary directory where tests are executed.""" + return legacy_path(self._pytester.path) + + @property + def test_tmproot(self) -> LEGACY_PATH: + return legacy_path(self._pytester._test_tmproot) + + @property + def request(self): + return self._pytester._request + + @property + def plugins(self): + return self._pytester.plugins + + @plugins.setter + def plugins(self, plugins): + self._pytester.plugins = plugins + + @property + def monkeypatch(self) -> MonkeyPatch: + return self._pytester._monkeypatch + + def make_hook_recorder(self, pluginmanager) -> HookRecorder: + """See :meth:`Pytester.make_hook_recorder`.""" + return self._pytester.make_hook_recorder(pluginmanager) + + def chdir(self) -> None: + """See :meth:`Pytester.chdir`.""" + return self._pytester.chdir() + + def finalize(self) -> None: + """See :meth:`Pytester._finalize`.""" + return self._pytester._finalize() + + def makefile(self, ext, *args, **kwargs) -> LEGACY_PATH: + """See :meth:`Pytester.makefile`.""" + if ext and not ext.startswith("."): + # pytester.makefile is going to throw a ValueError in a way that + # testdir.makefile did not, because + # pathlib.Path is stricter suffixes than py.path + # This ext arguments is likely user error, but since testdir has + # allowed this, we will prepend "." as a workaround to avoid breaking + # testdir usage that worked before + ext = "." + ext + return legacy_path(self._pytester.makefile(ext, *args, **kwargs)) + + def makeconftest(self, source) -> LEGACY_PATH: + """See :meth:`Pytester.makeconftest`.""" + return legacy_path(self._pytester.makeconftest(source)) + + def makeini(self, source) -> LEGACY_PATH: + """See :meth:`Pytester.makeini`.""" + return legacy_path(self._pytester.makeini(source)) + + def getinicfg(self, source: str) -> SectionWrapper: + """See :meth:`Pytester.getinicfg`.""" + return self._pytester.getinicfg(source) + + def makepyprojecttoml(self, source) -> LEGACY_PATH: + """See :meth:`Pytester.makepyprojecttoml`.""" + return legacy_path(self._pytester.makepyprojecttoml(source)) + + def makepyfile(self, *args, **kwargs) -> LEGACY_PATH: + """See :meth:`Pytester.makepyfile`.""" + return legacy_path(self._pytester.makepyfile(*args, **kwargs)) + + def maketxtfile(self, *args, **kwargs) -> LEGACY_PATH: + """See :meth:`Pytester.maketxtfile`.""" + return legacy_path(self._pytester.maketxtfile(*args, **kwargs)) + + def syspathinsert(self, path=None) -> None: + """See :meth:`Pytester.syspathinsert`.""" + return self._pytester.syspathinsert(path) + + def mkdir(self, name) -> LEGACY_PATH: + """See :meth:`Pytester.mkdir`.""" + return legacy_path(self._pytester.mkdir(name)) + + def mkpydir(self, name) -> LEGACY_PATH: + """See :meth:`Pytester.mkpydir`.""" + return legacy_path(self._pytester.mkpydir(name)) + + def copy_example(self, name=None) -> LEGACY_PATH: + """See :meth:`Pytester.copy_example`.""" + return legacy_path(self._pytester.copy_example(name)) + + def getnode(self, config: Config, arg) -> Optional[Union[Item, Collector]]: + """See :meth:`Pytester.getnode`.""" + return self._pytester.getnode(config, arg) + + def getpathnode(self, path): + """See :meth:`Pytester.getpathnode`.""" + return self._pytester.getpathnode(path) + + def genitems(self, colitems: List[Union[Item, Collector]]) -> List[Item]: + """See :meth:`Pytester.genitems`.""" + return self._pytester.genitems(colitems) + + def runitem(self, source): + """See :meth:`Pytester.runitem`.""" + return self._pytester.runitem(source) + + def inline_runsource(self, source, *cmdlineargs): + """See :meth:`Pytester.inline_runsource`.""" + return self._pytester.inline_runsource(source, *cmdlineargs) + + def inline_genitems(self, *args): + """See :meth:`Pytester.inline_genitems`.""" + return self._pytester.inline_genitems(*args) + + def inline_run(self, *args, plugins=(), no_reraise_ctrlc: bool = False): + """See :meth:`Pytester.inline_run`.""" + return self._pytester.inline_run( + *args, plugins=plugins, no_reraise_ctrlc=no_reraise_ctrlc + ) + + def runpytest_inprocess(self, *args, **kwargs) -> RunResult: + """See :meth:`Pytester.runpytest_inprocess`.""" + return self._pytester.runpytest_inprocess(*args, **kwargs) + + def runpytest(self, *args, **kwargs) -> RunResult: + """See :meth:`Pytester.runpytest`.""" + return self._pytester.runpytest(*args, **kwargs) + + def parseconfig(self, *args) -> Config: + """See :meth:`Pytester.parseconfig`.""" + return self._pytester.parseconfig(*args) + + def parseconfigure(self, *args) -> Config: + """See :meth:`Pytester.parseconfigure`.""" + return self._pytester.parseconfigure(*args) + + def getitem(self, source, funcname="test_func"): + """See :meth:`Pytester.getitem`.""" + return self._pytester.getitem(source, funcname) + + def getitems(self, source): + """See :meth:`Pytester.getitems`.""" + return self._pytester.getitems(source) + + def getmodulecol(self, source, configargs=(), withinit=False): + """See :meth:`Pytester.getmodulecol`.""" + return self._pytester.getmodulecol( + source, configargs=configargs, withinit=withinit + ) + + def collect_by_name( + self, modcol: Collector, name: str + ) -> Optional[Union[Item, Collector]]: + """See :meth:`Pytester.collect_by_name`.""" + return self._pytester.collect_by_name(modcol, name) + + def popen( + self, + cmdargs, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=CLOSE_STDIN, + **kw, + ): + """See :meth:`Pytester.popen`.""" + return self._pytester.popen(cmdargs, stdout, stderr, stdin, **kw) + + def run(self, *cmdargs, timeout=None, stdin=CLOSE_STDIN) -> RunResult: + """See :meth:`Pytester.run`.""" + return self._pytester.run(*cmdargs, timeout=timeout, stdin=stdin) + + def runpython(self, script) -> RunResult: + """See :meth:`Pytester.runpython`.""" + return self._pytester.runpython(script) + + def runpython_c(self, command): + """See :meth:`Pytester.runpython_c`.""" + return self._pytester.runpython_c(command) + + def runpytest_subprocess(self, *args, timeout=None) -> RunResult: + """See :meth:`Pytester.runpytest_subprocess`.""" + return self._pytester.runpytest_subprocess(*args, timeout=timeout) + + def spawn_pytest( + self, string: str, expect_timeout: float = 10.0 + ) -> "pexpect.spawn": + """See :meth:`Pytester.spawn_pytest`.""" + return self._pytester.spawn_pytest(string, expect_timeout=expect_timeout) + + def spawn(self, cmd: str, expect_timeout: float = 10.0) -> "pexpect.spawn": + """See :meth:`Pytester.spawn`.""" + return self._pytester.spawn(cmd, expect_timeout=expect_timeout) + + def __repr__(self) -> str: + return f"" + + def __str__(self) -> str: + return str(self.tmpdir) + + +class LegacyTestdirPlugin: + @staticmethod + @fixture + def testdir(pytester: Pytester) -> Testdir: + """ + Identical to :fixture:`pytester`, and provides an instance whose methods return + legacy ``LEGACY_PATH`` objects instead when applicable. + + New code should avoid using :fixture:`testdir` in favor of :fixture:`pytester`. + """ + return Testdir(pytester, _ispytest=True) + + +@final +@dataclasses.dataclass +class TempdirFactory: + """Backward compatibility wrapper that implements :class:`py.path.local` + for :class:`TempPathFactory`. + + .. note:: + These days, it is preferred to use ``tmp_path_factory``. + + :ref:`About the tmpdir and tmpdir_factory fixtures`. + + """ + + _tmppath_factory: TempPathFactory + + def __init__( + self, tmppath_factory: TempPathFactory, *, _ispytest: bool = False + ) -> None: + check_ispytest(_ispytest) + self._tmppath_factory = tmppath_factory + + def mktemp(self, basename: str, numbered: bool = True) -> LEGACY_PATH: + """Same as :meth:`TempPathFactory.mktemp`, but returns a :class:`py.path.local` object.""" + return legacy_path(self._tmppath_factory.mktemp(basename, numbered).resolve()) + + def getbasetemp(self) -> LEGACY_PATH: + """Same as :meth:`TempPathFactory.getbasetemp`, but returns a :class:`py.path.local` object.""" + return legacy_path(self._tmppath_factory.getbasetemp().resolve()) + + +class LegacyTmpdirPlugin: + @staticmethod + @fixture(scope="session") + def tmpdir_factory(request: FixtureRequest) -> TempdirFactory: + """Return a :class:`pytest.TempdirFactory` instance for the test session.""" + # Set dynamically by pytest_configure(). + return request.config._tmpdirhandler # type: ignore + + @staticmethod + @fixture + def tmpdir(tmp_path: Path) -> LEGACY_PATH: + """Return a temporary directory path object which is unique to each test + function invocation, created as a sub directory of the base temporary + directory. + + By default, a new base temporary directory is created each test session, + and old bases are removed after 3 sessions, to aid in debugging. If + ``--basetemp`` is used then it is cleared each session. See :ref:`base + temporary directory`. + + The returned object is a `legacy_path`_ object. + + .. note:: + These days, it is preferred to use ``tmp_path``. + + :ref:`About the tmpdir and tmpdir_factory fixtures`. + + .. _legacy_path: https://py.readthedocs.io/en/latest/path.html + """ + return legacy_path(tmp_path) + + +def Cache_makedir(self: Cache, name: str) -> LEGACY_PATH: + """Return a directory path object with the given name. + + Same as :func:`mkdir`, but returns a legacy py path instance. + """ + return legacy_path(self.mkdir(name)) + + +def FixtureRequest_fspath(self: FixtureRequest) -> LEGACY_PATH: + """(deprecated) The file system path of the test module which collected this test.""" + return legacy_path(self.path) + + +def TerminalReporter_startdir(self: TerminalReporter) -> LEGACY_PATH: + """The directory from which pytest was invoked. + + Prefer to use ``startpath`` which is a :class:`pathlib.Path`. + + :type: LEGACY_PATH + """ + return legacy_path(self.startpath) + + +def Config_invocation_dir(self: Config) -> LEGACY_PATH: + """The directory from which pytest was invoked. + + Prefer to use :attr:`invocation_params.dir `, + which is a :class:`pathlib.Path`. + + :type: LEGACY_PATH + """ + return legacy_path(str(self.invocation_params.dir)) + + +def Config_rootdir(self: Config) -> LEGACY_PATH: + """The path to the :ref:`rootdir `. + + Prefer to use :attr:`rootpath`, which is a :class:`pathlib.Path`. + + :type: LEGACY_PATH + """ + return legacy_path(str(self.rootpath)) + + +def Config_inifile(self: Config) -> Optional[LEGACY_PATH]: + """The path to the :ref:`configfile `. + + Prefer to use :attr:`inipath`, which is a :class:`pathlib.Path`. + + :type: Optional[LEGACY_PATH] + """ + return legacy_path(str(self.inipath)) if self.inipath else None + + +def Session_stardir(self: Session) -> LEGACY_PATH: + """The path from which pytest was invoked. + + Prefer to use ``startpath`` which is a :class:`pathlib.Path`. + + :type: LEGACY_PATH + """ + return legacy_path(self.startpath) + + +def Config__getini_unknown_type( + self, name: str, type: str, value: Union[str, List[str]] +): + if type == "pathlist": + # TODO: This assert is probably not valid in all cases. + assert self.inipath is not None + dp = self.inipath.parent + input_values = shlex.split(value) if isinstance(value, str) else value + return [legacy_path(str(dp / x)) for x in input_values] + else: + raise ValueError(f"unknown configuration type: {type}", value) + + +def Node_fspath(self: Node) -> LEGACY_PATH: + """(deprecated) returns a legacy_path copy of self.path""" + return legacy_path(self.path) + + +def Node_fspath_set(self: Node, value: LEGACY_PATH) -> None: + self.path = Path(value) + + +@hookimpl(tryfirst=True) +def pytest_load_initial_conftests(early_config: Config) -> None: + """Monkeypatch legacy path attributes in several classes, as early as possible.""" + mp = MonkeyPatch() + early_config.add_cleanup(mp.undo) + + # Add Cache.makedir(). + mp.setattr(Cache, "makedir", Cache_makedir, raising=False) + + # Add FixtureRequest.fspath property. + mp.setattr(FixtureRequest, "fspath", property(FixtureRequest_fspath), raising=False) + + # Add TerminalReporter.startdir property. + mp.setattr( + TerminalReporter, "startdir", property(TerminalReporter_startdir), raising=False + ) + + # Add Config.{invocation_dir,rootdir,inifile} properties. + mp.setattr(Config, "invocation_dir", property(Config_invocation_dir), raising=False) + mp.setattr(Config, "rootdir", property(Config_rootdir), raising=False) + mp.setattr(Config, "inifile", property(Config_inifile), raising=False) + + # Add Session.startdir property. + mp.setattr(Session, "startdir", property(Session_stardir), raising=False) + + # Add pathlist configuration type. + mp.setattr(Config, "_getini_unknown_type", Config__getini_unknown_type) + + # Add Node.fspath property. + mp.setattr(Node, "fspath", property(Node_fspath, Node_fspath_set), raising=False) + + +@hookimpl +def pytest_configure(config: Config) -> None: + """Installs the LegacyTmpdirPlugin if the ``tmpdir`` plugin is also installed.""" + if config.pluginmanager.has_plugin("tmpdir"): + mp = MonkeyPatch() + config.add_cleanup(mp.undo) + # Create TmpdirFactory and attach it to the config object. + # + # This is to comply with existing plugins which expect the handler to be + # available at pytest_configure time, but ideally should be moved entirely + # to the tmpdir_factory session fixture. + try: + tmp_path_factory = config._tmp_path_factory # type: ignore[attr-defined] + except AttributeError: + # tmpdir plugin is blocked. + pass + else: + _tmpdirhandler = TempdirFactory(tmp_path_factory, _ispytest=True) + mp.setattr(config, "_tmpdirhandler", _tmpdirhandler, raising=False) + + config.pluginmanager.register(LegacyTmpdirPlugin, "legacypath-tmpdir") + + +@hookimpl +def pytest_plugin_registered(plugin: object, manager: PytestPluginManager) -> None: + # pytester is not loaded by default and is commonly loaded from a conftest, + # so checking for it in `pytest_configure` is not enough. + is_pytester = plugin is manager.get_plugin("pytester") + if is_pytester and not manager.is_registered(LegacyTestdirPlugin): + manager.register(LegacyTestdirPlugin, "legacypath-pytester") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/logging.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/logging.py new file mode 100644 index 000000000..9f2f1c793 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/logging.py @@ -0,0 +1,920 @@ +"""Access and control log capturing.""" +import io +import logging +import os +import re +from contextlib import contextmanager +from contextlib import nullcontext +from datetime import datetime +from datetime import timedelta +from datetime import timezone +from io import StringIO +from logging import LogRecord +from pathlib import Path +from typing import AbstractSet +from typing import Dict +from typing import Generator +from typing import List +from typing import Mapping +from typing import Optional +from typing import Tuple +from typing import TYPE_CHECKING +from typing import TypeVar +from typing import Union + +from _pytest import nodes +from _pytest._io import TerminalWriter +from _pytest.capture import CaptureManager +from _pytest.compat import final +from _pytest.config import _strtobool +from _pytest.config import Config +from _pytest.config import create_terminal_writer +from _pytest.config import hookimpl +from _pytest.config import UsageError +from _pytest.config.argparsing import Parser +from _pytest.deprecated import check_ispytest +from _pytest.fixtures import fixture +from _pytest.fixtures import FixtureRequest +from _pytest.main import Session +from _pytest.stash import StashKey +from _pytest.terminal import TerminalReporter + +if TYPE_CHECKING: + logging_StreamHandler = logging.StreamHandler[StringIO] + + from typing_extensions import Literal +else: + logging_StreamHandler = logging.StreamHandler + +DEFAULT_LOG_FORMAT = "%(levelname)-8s %(name)s:%(filename)s:%(lineno)d %(message)s" +DEFAULT_LOG_DATE_FORMAT = "%H:%M:%S" +_ANSI_ESCAPE_SEQ = re.compile(r"\x1b\[[\d;]+m") +caplog_handler_key = StashKey["LogCaptureHandler"]() +caplog_records_key = StashKey[Dict[str, List[logging.LogRecord]]]() + + +def _remove_ansi_escape_sequences(text: str) -> str: + return _ANSI_ESCAPE_SEQ.sub("", text) + + +class DatetimeFormatter(logging.Formatter): + """A logging formatter which formats record with + :func:`datetime.datetime.strftime` formatter instead of + :func:`time.strftime` in case of microseconds in format string. + """ + + def formatTime(self, record: LogRecord, datefmt=None) -> str: + if datefmt and "%f" in datefmt: + ct = self.converter(record.created) + tz = timezone(timedelta(seconds=ct.tm_gmtoff), ct.tm_zone) + # Construct `datetime.datetime` object from `struct_time` + # and msecs information from `record` + dt = datetime(*ct[0:6], microsecond=round(record.msecs * 1000), tzinfo=tz) + return dt.strftime(datefmt) + # Use `logging.Formatter` for non-microsecond formats + return super().formatTime(record, datefmt) + + +class ColoredLevelFormatter(DatetimeFormatter): + """A logging formatter which colorizes the %(levelname)..s part of the + log format passed to __init__.""" + + LOGLEVEL_COLOROPTS: Mapping[int, AbstractSet[str]] = { + logging.CRITICAL: {"red"}, + logging.ERROR: {"red", "bold"}, + logging.WARNING: {"yellow"}, + logging.WARN: {"yellow"}, + logging.INFO: {"green"}, + logging.DEBUG: {"purple"}, + logging.NOTSET: set(), + } + LEVELNAME_FMT_REGEX = re.compile(r"%\(levelname\)([+-.]?\d*(?:\.\d+)?s)") + + def __init__(self, terminalwriter: TerminalWriter, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) + self._terminalwriter = terminalwriter + self._original_fmt = self._style._fmt + self._level_to_fmt_mapping: Dict[int, str] = {} + + for level, color_opts in self.LOGLEVEL_COLOROPTS.items(): + self.add_color_level(level, *color_opts) + + def add_color_level(self, level: int, *color_opts: str) -> None: + """Add or update color opts for a log level. + + :param level: + Log level to apply a style to, e.g. ``logging.INFO``. + :param color_opts: + ANSI escape sequence color options. Capitalized colors indicates + background color, i.e. ``'green', 'Yellow', 'bold'`` will give bold + green text on yellow background. + + .. warning:: + This is an experimental API. + """ + + assert self._fmt is not None + levelname_fmt_match = self.LEVELNAME_FMT_REGEX.search(self._fmt) + if not levelname_fmt_match: + return + levelname_fmt = levelname_fmt_match.group() + + formatted_levelname = levelname_fmt % {"levelname": logging.getLevelName(level)} + + # add ANSI escape sequences around the formatted levelname + color_kwargs = {name: True for name in color_opts} + colorized_formatted_levelname = self._terminalwriter.markup( + formatted_levelname, **color_kwargs + ) + self._level_to_fmt_mapping[level] = self.LEVELNAME_FMT_REGEX.sub( + colorized_formatted_levelname, self._fmt + ) + + def format(self, record: logging.LogRecord) -> str: + fmt = self._level_to_fmt_mapping.get(record.levelno, self._original_fmt) + self._style._fmt = fmt + return super().format(record) + + +class PercentStyleMultiline(logging.PercentStyle): + """A logging style with special support for multiline messages. + + If the message of a record consists of multiple lines, this style + formats the message as if each line were logged separately. + """ + + def __init__(self, fmt: str, auto_indent: Union[int, str, bool, None]) -> None: + super().__init__(fmt) + self._auto_indent = self._get_auto_indent(auto_indent) + + @staticmethod + def _get_auto_indent(auto_indent_option: Union[int, str, bool, None]) -> int: + """Determine the current auto indentation setting. + + Specify auto indent behavior (on/off/fixed) by passing in + extra={"auto_indent": [value]} to the call to logging.log() or + using a --log-auto-indent [value] command line or the + log_auto_indent [value] config option. + + Default behavior is auto-indent off. + + Using the string "True" or "on" or the boolean True as the value + turns auto indent on, using the string "False" or "off" or the + boolean False or the int 0 turns it off, and specifying a + positive integer fixes the indentation position to the value + specified. + + Any other values for the option are invalid, and will silently be + converted to the default. + + :param None|bool|int|str auto_indent_option: + User specified option for indentation from command line, config + or extra kwarg. Accepts int, bool or str. str option accepts the + same range of values as boolean config options, as well as + positive integers represented in str form. + + :returns: + Indentation value, which can be + -1 (automatically determine indentation) or + 0 (auto-indent turned off) or + >0 (explicitly set indentation position). + """ + + if auto_indent_option is None: + return 0 + elif isinstance(auto_indent_option, bool): + if auto_indent_option: + return -1 + else: + return 0 + elif isinstance(auto_indent_option, int): + return int(auto_indent_option) + elif isinstance(auto_indent_option, str): + try: + return int(auto_indent_option) + except ValueError: + pass + try: + if _strtobool(auto_indent_option): + return -1 + except ValueError: + return 0 + + return 0 + + def format(self, record: logging.LogRecord) -> str: + if "\n" in record.message: + if hasattr(record, "auto_indent"): + # Passed in from the "extra={}" kwarg on the call to logging.log(). + auto_indent = self._get_auto_indent(record.auto_indent) # type: ignore[attr-defined] + else: + auto_indent = self._auto_indent + + if auto_indent: + lines = record.message.splitlines() + formatted = self._fmt % {**record.__dict__, "message": lines[0]} + + if auto_indent < 0: + indentation = _remove_ansi_escape_sequences(formatted).find( + lines[0] + ) + else: + # Optimizes logging by allowing a fixed indentation. + indentation = auto_indent + lines[0] = formatted + return ("\n" + " " * indentation).join(lines) + return self._fmt % record.__dict__ + + +def get_option_ini(config: Config, *names: str): + for name in names: + ret = config.getoption(name) # 'default' arg won't work as expected + if ret is None: + ret = config.getini(name) + if ret: + return ret + + +def pytest_addoption(parser: Parser) -> None: + """Add options to control log capturing.""" + group = parser.getgroup("logging") + + def add_option_ini(option, dest, default=None, type=None, **kwargs): + parser.addini( + dest, default=default, type=type, help="Default value for " + option + ) + group.addoption(option, dest=dest, **kwargs) + + add_option_ini( + "--log-level", + dest="log_level", + default=None, + metavar="LEVEL", + help=( + "Level of messages to catch/display." + " Not set by default, so it depends on the root/parent log handler's" + ' effective level, where it is "WARNING" by default.' + ), + ) + add_option_ini( + "--log-format", + dest="log_format", + default=DEFAULT_LOG_FORMAT, + help="Log format used by the logging module", + ) + add_option_ini( + "--log-date-format", + dest="log_date_format", + default=DEFAULT_LOG_DATE_FORMAT, + help="Log date format used by the logging module", + ) + parser.addini( + "log_cli", + default=False, + type="bool", + help='Enable log display during test run (also known as "live logging")', + ) + add_option_ini( + "--log-cli-level", dest="log_cli_level", default=None, help="CLI logging level" + ) + add_option_ini( + "--log-cli-format", + dest="log_cli_format", + default=None, + help="Log format used by the logging module", + ) + add_option_ini( + "--log-cli-date-format", + dest="log_cli_date_format", + default=None, + help="Log date format used by the logging module", + ) + add_option_ini( + "--log-file", + dest="log_file", + default=None, + help="Path to a file when logging will be written to", + ) + add_option_ini( + "--log-file-level", + dest="log_file_level", + default=None, + help="Log file logging level", + ) + add_option_ini( + "--log-file-format", + dest="log_file_format", + default=DEFAULT_LOG_FORMAT, + help="Log format used by the logging module", + ) + add_option_ini( + "--log-file-date-format", + dest="log_file_date_format", + default=DEFAULT_LOG_DATE_FORMAT, + help="Log date format used by the logging module", + ) + add_option_ini( + "--log-auto-indent", + dest="log_auto_indent", + default=None, + help="Auto-indent multiline messages passed to the logging module. Accepts true|on, false|off or an integer.", + ) + group.addoption( + "--log-disable", + action="append", + default=[], + dest="logger_disable", + help="Disable a logger by name. Can be passed multiple times.", + ) + + +_HandlerType = TypeVar("_HandlerType", bound=logging.Handler) + + +# Not using @contextmanager for performance reasons. +class catching_logs: + """Context manager that prepares the whole logging machinery properly.""" + + __slots__ = ("handler", "level", "orig_level") + + def __init__(self, handler: _HandlerType, level: Optional[int] = None) -> None: + self.handler = handler + self.level = level + + def __enter__(self): + root_logger = logging.getLogger() + if self.level is not None: + self.handler.setLevel(self.level) + root_logger.addHandler(self.handler) + if self.level is not None: + self.orig_level = root_logger.level + root_logger.setLevel(min(self.orig_level, self.level)) + return self.handler + + def __exit__(self, type, value, traceback): + root_logger = logging.getLogger() + if self.level is not None: + root_logger.setLevel(self.orig_level) + root_logger.removeHandler(self.handler) + + +class LogCaptureHandler(logging_StreamHandler): + """A logging handler that stores log records and the log text.""" + + def __init__(self) -> None: + """Create a new log handler.""" + super().__init__(StringIO()) + self.records: List[logging.LogRecord] = [] + + def emit(self, record: logging.LogRecord) -> None: + """Keep the log records in a list in addition to the log text.""" + self.records.append(record) + super().emit(record) + + def reset(self) -> None: + self.records = [] + self.stream = StringIO() + + def clear(self) -> None: + self.records.clear() + self.stream = StringIO() + + def handleError(self, record: logging.LogRecord) -> None: + if logging.raiseExceptions: + # Fail the test if the log message is bad (emit failed). + # The default behavior of logging is to print "Logging error" + # to stderr with the call stack and some extra details. + # pytest wants to make such mistakes visible during testing. + raise + + +@final +class LogCaptureFixture: + """Provides access and control of log capturing.""" + + def __init__(self, item: nodes.Node, *, _ispytest: bool = False) -> None: + check_ispytest(_ispytest) + self._item = item + self._initial_handler_level: Optional[int] = None + # Dict of log name -> log level. + self._initial_logger_levels: Dict[Optional[str], int] = {} + self._initial_disabled_logging_level: Optional[int] = None + + def _finalize(self) -> None: + """Finalize the fixture. + + This restores the log levels and the disabled logging levels changed by :meth:`set_level`. + """ + # Restore log levels. + if self._initial_handler_level is not None: + self.handler.setLevel(self._initial_handler_level) + for logger_name, level in self._initial_logger_levels.items(): + logger = logging.getLogger(logger_name) + logger.setLevel(level) + # Disable logging at the original disabled logging level. + if self._initial_disabled_logging_level is not None: + logging.disable(self._initial_disabled_logging_level) + self._initial_disabled_logging_level = None + + @property + def handler(self) -> LogCaptureHandler: + """Get the logging handler used by the fixture.""" + return self._item.stash[caplog_handler_key] + + def get_records( + self, when: "Literal['setup', 'call', 'teardown']" + ) -> List[logging.LogRecord]: + """Get the logging records for one of the possible test phases. + + :param when: + Which test phase to obtain the records from. + Valid values are: "setup", "call" and "teardown". + + :returns: The list of captured records at the given stage. + + .. versionadded:: 3.4 + """ + return self._item.stash[caplog_records_key].get(when, []) + + @property + def text(self) -> str: + """The formatted log text.""" + return _remove_ansi_escape_sequences(self.handler.stream.getvalue()) + + @property + def records(self) -> List[logging.LogRecord]: + """The list of log records.""" + return self.handler.records + + @property + def record_tuples(self) -> List[Tuple[str, int, str]]: + """A list of a stripped down version of log records intended + for use in assertion comparison. + + The format of the tuple is: + + (logger_name, log_level, message) + """ + return [(r.name, r.levelno, r.getMessage()) for r in self.records] + + @property + def messages(self) -> List[str]: + """A list of format-interpolated log messages. + + Unlike 'records', which contains the format string and parameters for + interpolation, log messages in this list are all interpolated. + + Unlike 'text', which contains the output from the handler, log + messages in this list are unadorned with levels, timestamps, etc, + making exact comparisons more reliable. + + Note that traceback or stack info (from :func:`logging.exception` or + the `exc_info` or `stack_info` arguments to the logging functions) is + not included, as this is added by the formatter in the handler. + + .. versionadded:: 3.7 + """ + return [r.getMessage() for r in self.records] + + def clear(self) -> None: + """Reset the list of log records and the captured log text.""" + self.handler.clear() + + def _force_enable_logging( + self, level: Union[int, str], logger_obj: logging.Logger + ) -> int: + """Enable the desired logging level if the global level was disabled via ``logging.disabled``. + + Only enables logging levels greater than or equal to the requested ``level``. + + Does nothing if the desired ``level`` wasn't disabled. + + :param level: + The logger level caplog should capture. + All logging is enabled if a non-standard logging level string is supplied. + Valid level strings are in :data:`logging._nameToLevel`. + :param logger_obj: The logger object to check. + + :return: The original disabled logging level. + """ + original_disable_level: int = logger_obj.manager.disable # type: ignore[attr-defined] + + if isinstance(level, str): + # Try to translate the level string to an int for `logging.disable()` + level = logging.getLevelName(level) + + if not isinstance(level, int): + # The level provided was not valid, so just un-disable all logging. + logging.disable(logging.NOTSET) + elif not logger_obj.isEnabledFor(level): + # Each level is `10` away from other levels. + # https://docs.python.org/3/library/logging.html#logging-levels + disable_level = max(level - 10, logging.NOTSET) + logging.disable(disable_level) + + return original_disable_level + + def set_level(self, level: Union[int, str], logger: Optional[str] = None) -> None: + """Set the threshold level of a logger for the duration of a test. + + Logging messages which are less severe than this level will not be captured. + + .. versionchanged:: 3.4 + The levels of the loggers changed by this function will be + restored to their initial values at the end of the test. + + Will enable the requested logging level if it was disabled via :meth:`logging.disable`. + + :param level: The level. + :param logger: The logger to update. If not given, the root logger. + """ + logger_obj = logging.getLogger(logger) + # Save the original log-level to restore it during teardown. + self._initial_logger_levels.setdefault(logger, logger_obj.level) + logger_obj.setLevel(level) + if self._initial_handler_level is None: + self._initial_handler_level = self.handler.level + self.handler.setLevel(level) + initial_disabled_logging_level = self._force_enable_logging(level, logger_obj) + if self._initial_disabled_logging_level is None: + self._initial_disabled_logging_level = initial_disabled_logging_level + + @contextmanager + def at_level( + self, level: Union[int, str], logger: Optional[str] = None + ) -> Generator[None, None, None]: + """Context manager that sets the level for capturing of logs. After + the end of the 'with' statement the level is restored to its original + value. + + Will enable the requested logging level if it was disabled via :meth:`logging.disable`. + + :param level: The level. + :param logger: The logger to update. If not given, the root logger. + """ + logger_obj = logging.getLogger(logger) + orig_level = logger_obj.level + logger_obj.setLevel(level) + handler_orig_level = self.handler.level + self.handler.setLevel(level) + original_disable_level = self._force_enable_logging(level, logger_obj) + try: + yield + finally: + logger_obj.setLevel(orig_level) + self.handler.setLevel(handler_orig_level) + logging.disable(original_disable_level) + + +@fixture +def caplog(request: FixtureRequest) -> Generator[LogCaptureFixture, None, None]: + """Access and control log capturing. + + Captured logs are available through the following properties/methods:: + + * caplog.messages -> list of format-interpolated log messages + * caplog.text -> string containing formatted log output + * caplog.records -> list of logging.LogRecord instances + * caplog.record_tuples -> list of (logger_name, level, message) tuples + * caplog.clear() -> clear captured records and formatted log output string + """ + result = LogCaptureFixture(request.node, _ispytest=True) + yield result + result._finalize() + + +def get_log_level_for_setting(config: Config, *setting_names: str) -> Optional[int]: + for setting_name in setting_names: + log_level = config.getoption(setting_name) + if log_level is None: + log_level = config.getini(setting_name) + if log_level: + break + else: + return None + + if isinstance(log_level, str): + log_level = log_level.upper() + try: + return int(getattr(logging, log_level, log_level)) + except ValueError as e: + # Python logging does not recognise this as a logging level + raise UsageError( + "'{}' is not recognized as a logging level name for " + "'{}'. Please consider passing the " + "logging level num instead.".format(log_level, setting_name) + ) from e + + +# run after terminalreporter/capturemanager are configured +@hookimpl(trylast=True) +def pytest_configure(config: Config) -> None: + config.pluginmanager.register(LoggingPlugin(config), "logging-plugin") + + +class LoggingPlugin: + """Attaches to the logging module and captures log messages for each test.""" + + def __init__(self, config: Config) -> None: + """Create a new plugin to capture log messages. + + The formatter can be safely shared across all handlers so + create a single one for the entire test session here. + """ + self._config = config + + # Report logging. + self.formatter = self._create_formatter( + get_option_ini(config, "log_format"), + get_option_ini(config, "log_date_format"), + get_option_ini(config, "log_auto_indent"), + ) + self.log_level = get_log_level_for_setting(config, "log_level") + self.caplog_handler = LogCaptureHandler() + self.caplog_handler.setFormatter(self.formatter) + self.report_handler = LogCaptureHandler() + self.report_handler.setFormatter(self.formatter) + + # File logging. + self.log_file_level = get_log_level_for_setting(config, "log_file_level") + log_file = get_option_ini(config, "log_file") or os.devnull + if log_file != os.devnull: + directory = os.path.dirname(os.path.abspath(log_file)) + if not os.path.isdir(directory): + os.makedirs(directory) + + self.log_file_handler = _FileHandler(log_file, mode="w", encoding="UTF-8") + log_file_format = get_option_ini(config, "log_file_format", "log_format") + log_file_date_format = get_option_ini( + config, "log_file_date_format", "log_date_format" + ) + + log_file_formatter = DatetimeFormatter( + log_file_format, datefmt=log_file_date_format + ) + self.log_file_handler.setFormatter(log_file_formatter) + + # CLI/live logging. + self.log_cli_level = get_log_level_for_setting( + config, "log_cli_level", "log_level" + ) + if self._log_cli_enabled(): + terminal_reporter = config.pluginmanager.get_plugin("terminalreporter") + # Guaranteed by `_log_cli_enabled()`. + assert terminal_reporter is not None + capture_manager = config.pluginmanager.get_plugin("capturemanager") + # if capturemanager plugin is disabled, live logging still works. + self.log_cli_handler: Union[ + _LiveLoggingStreamHandler, _LiveLoggingNullHandler + ] = _LiveLoggingStreamHandler(terminal_reporter, capture_manager) + else: + self.log_cli_handler = _LiveLoggingNullHandler() + log_cli_formatter = self._create_formatter( + get_option_ini(config, "log_cli_format", "log_format"), + get_option_ini(config, "log_cli_date_format", "log_date_format"), + get_option_ini(config, "log_auto_indent"), + ) + self.log_cli_handler.setFormatter(log_cli_formatter) + self._disable_loggers(loggers_to_disable=config.option.logger_disable) + + def _disable_loggers(self, loggers_to_disable: List[str]) -> None: + if not loggers_to_disable: + return + + for name in loggers_to_disable: + logger = logging.getLogger(name) + logger.disabled = True + + def _create_formatter(self, log_format, log_date_format, auto_indent): + # Color option doesn't exist if terminal plugin is disabled. + color = getattr(self._config.option, "color", "no") + if color != "no" and ColoredLevelFormatter.LEVELNAME_FMT_REGEX.search( + log_format + ): + formatter: logging.Formatter = ColoredLevelFormatter( + create_terminal_writer(self._config), log_format, log_date_format + ) + else: + formatter = DatetimeFormatter(log_format, log_date_format) + + formatter._style = PercentStyleMultiline( + formatter._style._fmt, auto_indent=auto_indent + ) + + return formatter + + def set_log_path(self, fname: str) -> None: + """Set the filename parameter for Logging.FileHandler(). + + Creates parent directory if it does not exist. + + .. warning:: + This is an experimental API. + """ + fpath = Path(fname) + + if not fpath.is_absolute(): + fpath = self._config.rootpath / fpath + + if not fpath.parent.exists(): + fpath.parent.mkdir(exist_ok=True, parents=True) + + # https://github.com/python/mypy/issues/11193 + stream: io.TextIOWrapper = fpath.open(mode="w", encoding="UTF-8") # type: ignore[assignment] + old_stream = self.log_file_handler.setStream(stream) + if old_stream: + old_stream.close() + + def _log_cli_enabled(self): + """Return whether live logging is enabled.""" + enabled = self._config.getoption( + "--log-cli-level" + ) is not None or self._config.getini("log_cli") + if not enabled: + return False + + terminal_reporter = self._config.pluginmanager.get_plugin("terminalreporter") + if terminal_reporter is None: + # terminal reporter is disabled e.g. by pytest-xdist. + return False + + return True + + @hookimpl(hookwrapper=True, tryfirst=True) + def pytest_sessionstart(self) -> Generator[None, None, None]: + self.log_cli_handler.set_when("sessionstart") + + with catching_logs(self.log_cli_handler, level=self.log_cli_level): + with catching_logs(self.log_file_handler, level=self.log_file_level): + yield + + @hookimpl(hookwrapper=True, tryfirst=True) + def pytest_collection(self) -> Generator[None, None, None]: + self.log_cli_handler.set_when("collection") + + with catching_logs(self.log_cli_handler, level=self.log_cli_level): + with catching_logs(self.log_file_handler, level=self.log_file_level): + yield + + @hookimpl(hookwrapper=True) + def pytest_runtestloop(self, session: Session) -> Generator[None, None, None]: + if session.config.option.collectonly: + yield + return + + if self._log_cli_enabled() and self._config.getoption("verbose") < 1: + # The verbose flag is needed to avoid messy test progress output. + self._config.option.verbose = 1 + + with catching_logs(self.log_cli_handler, level=self.log_cli_level): + with catching_logs(self.log_file_handler, level=self.log_file_level): + yield # Run all the tests. + + @hookimpl + def pytest_runtest_logstart(self) -> None: + self.log_cli_handler.reset() + self.log_cli_handler.set_when("start") + + @hookimpl + def pytest_runtest_logreport(self) -> None: + self.log_cli_handler.set_when("logreport") + + def _runtest_for(self, item: nodes.Item, when: str) -> Generator[None, None, None]: + """Implement the internals of the pytest_runtest_xxx() hooks.""" + with catching_logs( + self.caplog_handler, + level=self.log_level, + ) as caplog_handler, catching_logs( + self.report_handler, + level=self.log_level, + ) as report_handler: + caplog_handler.reset() + report_handler.reset() + item.stash[caplog_records_key][when] = caplog_handler.records + item.stash[caplog_handler_key] = caplog_handler + + yield + + log = report_handler.stream.getvalue().strip() + item.add_report_section(when, "log", log) + + @hookimpl(hookwrapper=True) + def pytest_runtest_setup(self, item: nodes.Item) -> Generator[None, None, None]: + self.log_cli_handler.set_when("setup") + + empty: Dict[str, List[logging.LogRecord]] = {} + item.stash[caplog_records_key] = empty + yield from self._runtest_for(item, "setup") + + @hookimpl(hookwrapper=True) + def pytest_runtest_call(self, item: nodes.Item) -> Generator[None, None, None]: + self.log_cli_handler.set_when("call") + + yield from self._runtest_for(item, "call") + + @hookimpl(hookwrapper=True) + def pytest_runtest_teardown(self, item: nodes.Item) -> Generator[None, None, None]: + self.log_cli_handler.set_when("teardown") + + yield from self._runtest_for(item, "teardown") + del item.stash[caplog_records_key] + del item.stash[caplog_handler_key] + + @hookimpl + def pytest_runtest_logfinish(self) -> None: + self.log_cli_handler.set_when("finish") + + @hookimpl(hookwrapper=True, tryfirst=True) + def pytest_sessionfinish(self) -> Generator[None, None, None]: + self.log_cli_handler.set_when("sessionfinish") + + with catching_logs(self.log_cli_handler, level=self.log_cli_level): + with catching_logs(self.log_file_handler, level=self.log_file_level): + yield + + @hookimpl + def pytest_unconfigure(self) -> None: + # Close the FileHandler explicitly. + # (logging.shutdown might have lost the weakref?!) + self.log_file_handler.close() + + +class _FileHandler(logging.FileHandler): + """A logging FileHandler with pytest tweaks.""" + + def handleError(self, record: logging.LogRecord) -> None: + # Handled by LogCaptureHandler. + pass + + +class _LiveLoggingStreamHandler(logging_StreamHandler): + """A logging StreamHandler used by the live logging feature: it will + write a newline before the first log message in each test. + + During live logging we must also explicitly disable stdout/stderr + capturing otherwise it will get captured and won't appear in the + terminal. + """ + + # Officially stream needs to be a IO[str], but TerminalReporter + # isn't. So force it. + stream: TerminalReporter = None # type: ignore + + def __init__( + self, + terminal_reporter: TerminalReporter, + capture_manager: Optional[CaptureManager], + ) -> None: + super().__init__(stream=terminal_reporter) # type: ignore[arg-type] + self.capture_manager = capture_manager + self.reset() + self.set_when(None) + self._test_outcome_written = False + + def reset(self) -> None: + """Reset the handler; should be called before the start of each test.""" + self._first_record_emitted = False + + def set_when(self, when: Optional[str]) -> None: + """Prepare for the given test phase (setup/call/teardown).""" + self._when = when + self._section_name_shown = False + if when == "start": + self._test_outcome_written = False + + def emit(self, record: logging.LogRecord) -> None: + ctx_manager = ( + self.capture_manager.global_and_fixture_disabled() + if self.capture_manager + else nullcontext() + ) + with ctx_manager: + if not self._first_record_emitted: + self.stream.write("\n") + self._first_record_emitted = True + elif self._when in ("teardown", "finish"): + if not self._test_outcome_written: + self._test_outcome_written = True + self.stream.write("\n") + if not self._section_name_shown and self._when: + self.stream.section("live log " + self._when, sep="-", bold=True) + self._section_name_shown = True + super().emit(record) + + def handleError(self, record: logging.LogRecord) -> None: + # Handled by LogCaptureHandler. + pass + + +class _LiveLoggingNullHandler(logging.NullHandler): + """A logging handler used when live logging is disabled.""" + + def reset(self) -> None: + pass + + def set_when(self, when: str) -> None: + pass + + def handleError(self, record: logging.LogRecord) -> None: + # Handled by LogCaptureHandler. + pass diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/main.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/main.py new file mode 100644 index 000000000..ea89a63fa --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/main.py @@ -0,0 +1,913 @@ +"""Core implementation of the testing process: init, session, runtest loop.""" +import argparse +import dataclasses +import fnmatch +import functools +import importlib +import os +import sys +from pathlib import Path +from typing import Callable +from typing import Dict +from typing import FrozenSet +from typing import Iterator +from typing import List +from typing import Optional +from typing import Sequence +from typing import Set +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import Union + +import _pytest._code +from _pytest import nodes +from _pytest.compat import final +from _pytest.compat import overload +from _pytest.config import Config +from _pytest.config import directory_arg +from _pytest.config import ExitCode +from _pytest.config import hookimpl +from _pytest.config import PytestPluginManager +from _pytest.config import UsageError +from _pytest.config.argparsing import Parser +from _pytest.fixtures import FixtureManager +from _pytest.outcomes import exit +from _pytest.pathlib import absolutepath +from _pytest.pathlib import bestrelpath +from _pytest.pathlib import fnmatch_ex +from _pytest.pathlib import safe_exists +from _pytest.pathlib import visit +from _pytest.reports import CollectReport +from _pytest.reports import TestReport +from _pytest.runner import collect_one_node +from _pytest.runner import SetupState + + +if TYPE_CHECKING: + from typing_extensions import Literal + + +def pytest_addoption(parser: Parser) -> None: + parser.addini( + "norecursedirs", + "Directory patterns to avoid for recursion", + type="args", + default=[ + "*.egg", + ".*", + "_darcs", + "build", + "CVS", + "dist", + "node_modules", + "venv", + "{arch}", + ], + ) + parser.addini( + "testpaths", + "Directories to search for tests when no files or directories are given on the " + "command line", + type="args", + default=[], + ) + group = parser.getgroup("general", "Running and selection options") + group._addoption( + "-x", + "--exitfirst", + action="store_const", + dest="maxfail", + const=1, + help="Exit instantly on first error or failed test", + ) + group = parser.getgroup("pytest-warnings") + group.addoption( + "-W", + "--pythonwarnings", + action="append", + help="Set which warnings to report, see -W option of Python itself", + ) + parser.addini( + "filterwarnings", + type="linelist", + help="Each line specifies a pattern for " + "warnings.filterwarnings. " + "Processed after -W/--pythonwarnings.", + ) + group._addoption( + "--maxfail", + metavar="num", + action="store", + type=int, + dest="maxfail", + default=0, + help="Exit after first num failures or errors", + ) + group._addoption( + "--strict-config", + action="store_true", + help="Any warnings encountered while parsing the `pytest` section of the " + "configuration file raise errors", + ) + group._addoption( + "--strict-markers", + action="store_true", + help="Markers not registered in the `markers` section of the configuration " + "file raise errors", + ) + group._addoption( + "--strict", + action="store_true", + help="(Deprecated) alias to --strict-markers", + ) + group._addoption( + "-c", + "--config-file", + metavar="FILE", + type=str, + dest="inifilename", + help="Load configuration from `FILE` instead of trying to locate one of the " + "implicit configuration files.", + ) + group._addoption( + "--continue-on-collection-errors", + action="store_true", + default=False, + dest="continue_on_collection_errors", + help="Force test execution even if collection errors occur", + ) + group._addoption( + "--rootdir", + action="store", + dest="rootdir", + help="Define root directory for tests. Can be relative path: 'root_dir', './root_dir', " + "'root_dir/another_dir/'; absolute path: '/home/user/root_dir'; path with variables: " + "'$HOME/root_dir'.", + ) + + group = parser.getgroup("collect", "collection") + group.addoption( + "--collectonly", + "--collect-only", + "--co", + action="store_true", + help="Only collect tests, don't execute them", + ) + group.addoption( + "--pyargs", + action="store_true", + help="Try to interpret all arguments as Python packages", + ) + group.addoption( + "--ignore", + action="append", + metavar="path", + help="Ignore path during collection (multi-allowed)", + ) + group.addoption( + "--ignore-glob", + action="append", + metavar="path", + help="Ignore path pattern during collection (multi-allowed)", + ) + group.addoption( + "--deselect", + action="append", + metavar="nodeid_prefix", + help="Deselect item (via node id prefix) during collection (multi-allowed)", + ) + group.addoption( + "--confcutdir", + dest="confcutdir", + default=None, + metavar="dir", + type=functools.partial(directory_arg, optname="--confcutdir"), + help="Only load conftest.py's relative to specified dir", + ) + group.addoption( + "--noconftest", + action="store_true", + dest="noconftest", + default=False, + help="Don't load any conftest.py files", + ) + group.addoption( + "--keepduplicates", + "--keep-duplicates", + action="store_true", + dest="keepduplicates", + default=False, + help="Keep duplicate tests", + ) + group.addoption( + "--collect-in-virtualenv", + action="store_true", + dest="collect_in_virtualenv", + default=False, + help="Don't ignore tests in a local virtualenv directory", + ) + group.addoption( + "--import-mode", + default="prepend", + choices=["prepend", "append", "importlib"], + dest="importmode", + help="Prepend/append to sys.path when importing test modules and conftest " + "files. Default: prepend.", + ) + + group = parser.getgroup("debugconfig", "test session debugging and configuration") + group.addoption( + "--basetemp", + dest="basetemp", + default=None, + type=validate_basetemp, + metavar="dir", + help=( + "Base temporary directory for this test run. " + "(Warning: this directory is removed if it exists.)" + ), + ) + + +def validate_basetemp(path: str) -> str: + # GH 7119 + msg = "basetemp must not be empty, the current working directory or any parent directory of it" + + # empty path + if not path: + raise argparse.ArgumentTypeError(msg) + + def is_ancestor(base: Path, query: Path) -> bool: + """Return whether query is an ancestor of base.""" + if base == query: + return True + return query in base.parents + + # check if path is an ancestor of cwd + if is_ancestor(Path.cwd(), Path(path).absolute()): + raise argparse.ArgumentTypeError(msg) + + # check symlinks for ancestors + if is_ancestor(Path.cwd().resolve(), Path(path).resolve()): + raise argparse.ArgumentTypeError(msg) + + return path + + +def wrap_session( + config: Config, doit: Callable[[Config, "Session"], Optional[Union[int, ExitCode]]] +) -> Union[int, ExitCode]: + """Skeleton command line program.""" + session = Session.from_config(config) + session.exitstatus = ExitCode.OK + initstate = 0 + try: + try: + config._do_configure() + initstate = 1 + config.hook.pytest_sessionstart(session=session) + initstate = 2 + session.exitstatus = doit(config, session) or 0 + except UsageError: + session.exitstatus = ExitCode.USAGE_ERROR + raise + except Failed: + session.exitstatus = ExitCode.TESTS_FAILED + except (KeyboardInterrupt, exit.Exception): + excinfo = _pytest._code.ExceptionInfo.from_current() + exitstatus: Union[int, ExitCode] = ExitCode.INTERRUPTED + if isinstance(excinfo.value, exit.Exception): + if excinfo.value.returncode is not None: + exitstatus = excinfo.value.returncode + if initstate < 2: + sys.stderr.write(f"{excinfo.typename}: {excinfo.value.msg}\n") + config.hook.pytest_keyboard_interrupt(excinfo=excinfo) + session.exitstatus = exitstatus + except BaseException: + session.exitstatus = ExitCode.INTERNAL_ERROR + excinfo = _pytest._code.ExceptionInfo.from_current() + try: + config.notify_exception(excinfo, config.option) + except exit.Exception as exc: + if exc.returncode is not None: + session.exitstatus = exc.returncode + sys.stderr.write(f"{type(exc).__name__}: {exc}\n") + else: + if isinstance(excinfo.value, SystemExit): + sys.stderr.write("mainloop: caught unexpected SystemExit!\n") + + finally: + # Explicitly break reference cycle. + excinfo = None # type: ignore + os.chdir(session.startpath) + if initstate >= 2: + try: + config.hook.pytest_sessionfinish( + session=session, exitstatus=session.exitstatus + ) + except exit.Exception as exc: + if exc.returncode is not None: + session.exitstatus = exc.returncode + sys.stderr.write(f"{type(exc).__name__}: {exc}\n") + config._ensure_unconfigure() + return session.exitstatus + + +def pytest_cmdline_main(config: Config) -> Union[int, ExitCode]: + return wrap_session(config, _main) + + +def _main(config: Config, session: "Session") -> Optional[Union[int, ExitCode]]: + """Default command line protocol for initialization, session, + running tests and reporting.""" + config.hook.pytest_collection(session=session) + config.hook.pytest_runtestloop(session=session) + + if session.testsfailed: + return ExitCode.TESTS_FAILED + elif session.testscollected == 0: + return ExitCode.NO_TESTS_COLLECTED + return None + + +def pytest_collection(session: "Session") -> None: + session.perform_collect() + + +def pytest_runtestloop(session: "Session") -> bool: + if session.testsfailed and not session.config.option.continue_on_collection_errors: + raise session.Interrupted( + "%d error%s during collection" + % (session.testsfailed, "s" if session.testsfailed != 1 else "") + ) + + if session.config.option.collectonly: + return True + + for i, item in enumerate(session.items): + nextitem = session.items[i + 1] if i + 1 < len(session.items) else None + item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem) + if session.shouldfail: + raise session.Failed(session.shouldfail) + if session.shouldstop: + raise session.Interrupted(session.shouldstop) + return True + + +def _in_venv(path: Path) -> bool: + """Attempt to detect if ``path`` is the root of a Virtual Environment by + checking for the existence of the appropriate activate script.""" + bindir = path.joinpath("Scripts" if sys.platform.startswith("win") else "bin") + try: + if not bindir.is_dir(): + return False + except OSError: + return False + activates = ( + "activate", + "activate.csh", + "activate.fish", + "Activate", + "Activate.bat", + "Activate.ps1", + ) + return any(fname.name in activates for fname in bindir.iterdir()) + + +def pytest_ignore_collect(collection_path: Path, config: Config) -> Optional[bool]: + ignore_paths = config._getconftest_pathlist( + "collect_ignore", path=collection_path.parent, rootpath=config.rootpath + ) + ignore_paths = ignore_paths or [] + excludeopt = config.getoption("ignore") + if excludeopt: + ignore_paths.extend(absolutepath(x) for x in excludeopt) + + if collection_path in ignore_paths: + return True + + ignore_globs = config._getconftest_pathlist( + "collect_ignore_glob", path=collection_path.parent, rootpath=config.rootpath + ) + ignore_globs = ignore_globs or [] + excludeglobopt = config.getoption("ignore_glob") + if excludeglobopt: + ignore_globs.extend(absolutepath(x) for x in excludeglobopt) + + if any(fnmatch.fnmatch(str(collection_path), str(glob)) for glob in ignore_globs): + return True + + allow_in_venv = config.getoption("collect_in_virtualenv") + if not allow_in_venv and _in_venv(collection_path): + return True + + if collection_path.is_dir(): + norecursepatterns = config.getini("norecursedirs") + if any(fnmatch_ex(pat, collection_path) for pat in norecursepatterns): + return True + + return None + + +def pytest_collection_modifyitems(items: List[nodes.Item], config: Config) -> None: + deselect_prefixes = tuple(config.getoption("deselect") or []) + if not deselect_prefixes: + return + + remaining = [] + deselected = [] + for colitem in items: + if colitem.nodeid.startswith(deselect_prefixes): + deselected.append(colitem) + else: + remaining.append(colitem) + + if deselected: + config.hook.pytest_deselected(items=deselected) + items[:] = remaining + + +class FSHookProxy: + def __init__(self, pm: PytestPluginManager, remove_mods) -> None: + self.pm = pm + self.remove_mods = remove_mods + + def __getattr__(self, name: str): + x = self.pm.subset_hook_caller(name, remove_plugins=self.remove_mods) + self.__dict__[name] = x + return x + + +class Interrupted(KeyboardInterrupt): + """Signals that the test run was interrupted.""" + + __module__ = "builtins" # For py3. + + +class Failed(Exception): + """Signals a stop as failed test run.""" + + +@dataclasses.dataclass +class _bestrelpath_cache(Dict[Path, str]): + __slots__ = ("path",) + + path: Path + + def __missing__(self, path: Path) -> str: + r = bestrelpath(self.path, path) + self[path] = r + return r + + +@final +class Session(nodes.FSCollector): + """The root of the collection tree. + + ``Session`` collects the initial paths given as arguments to pytest. + """ + + Interrupted = Interrupted + Failed = Failed + # Set on the session by runner.pytest_sessionstart. + _setupstate: SetupState + # Set on the session by fixtures.pytest_sessionstart. + _fixturemanager: FixtureManager + exitstatus: Union[int, ExitCode] + + def __init__(self, config: Config) -> None: + super().__init__( + path=config.rootpath, + fspath=None, + parent=None, + config=config, + session=self, + nodeid="", + ) + self.testsfailed = 0 + self.testscollected = 0 + self.shouldstop: Union[bool, str] = False + self.shouldfail: Union[bool, str] = False + self.trace = config.trace.root.get("collection") + self._initialpaths: FrozenSet[Path] = frozenset() + + self._bestrelpathcache: Dict[Path, str] = _bestrelpath_cache(config.rootpath) + + self.config.pluginmanager.register(self, name="session") + + @classmethod + def from_config(cls, config: Config) -> "Session": + session: Session = cls._create(config=config) + return session + + def __repr__(self) -> str: + return "<%s %s exitstatus=%r testsfailed=%d testscollected=%d>" % ( + self.__class__.__name__, + self.name, + getattr(self, "exitstatus", ""), + self.testsfailed, + self.testscollected, + ) + + @property + def startpath(self) -> Path: + """The path from which pytest was invoked. + + .. versionadded:: 7.0.0 + """ + return self.config.invocation_params.dir + + def _node_location_to_relpath(self, node_path: Path) -> str: + # bestrelpath is a quite slow function. + return self._bestrelpathcache[node_path] + + @hookimpl(tryfirst=True) + def pytest_collectstart(self) -> None: + if self.shouldfail: + raise self.Failed(self.shouldfail) + if self.shouldstop: + raise self.Interrupted(self.shouldstop) + + @hookimpl(tryfirst=True) + def pytest_runtest_logreport( + self, report: Union[TestReport, CollectReport] + ) -> None: + if report.failed and not hasattr(report, "wasxfail"): + self.testsfailed += 1 + maxfail = self.config.getvalue("maxfail") + if maxfail and self.testsfailed >= maxfail: + self.shouldfail = "stopping after %d failures" % (self.testsfailed) + + pytest_collectreport = pytest_runtest_logreport + + def isinitpath(self, path: Union[str, "os.PathLike[str]"]) -> bool: + # Optimization: Path(Path(...)) is much slower than isinstance. + path_ = path if isinstance(path, Path) else Path(path) + return path_ in self._initialpaths + + def gethookproxy(self, fspath: "os.PathLike[str]"): + # Optimization: Path(Path(...)) is much slower than isinstance. + path = fspath if isinstance(fspath, Path) else Path(fspath) + pm = self.config.pluginmanager + # Check if we have the common case of running + # hooks with all conftest.py files. + my_conftestmodules = pm._getconftestmodules( + path, + self.config.getoption("importmode"), + rootpath=self.config.rootpath, + ) + remove_mods = pm._conftest_plugins.difference(my_conftestmodules) + if remove_mods: + # One or more conftests are not in use at this fspath. + from .config.compat import PathAwareHookProxy + + proxy = PathAwareHookProxy(FSHookProxy(pm, remove_mods)) + else: + # All plugins are active for this fspath. + proxy = self.config.hook + return proxy + + def _recurse(self, direntry: "os.DirEntry[str]") -> bool: + if direntry.name == "__pycache__": + return False + fspath = Path(direntry.path) + ihook = self.gethookproxy(fspath.parent) + if ihook.pytest_ignore_collect(collection_path=fspath, config=self.config): + return False + return True + + def _collectfile( + self, fspath: Path, handle_dupes: bool = True + ) -> Sequence[nodes.Collector]: + assert ( + fspath.is_file() + ), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format( + fspath, fspath.is_dir(), fspath.exists(), fspath.is_symlink() + ) + ihook = self.gethookproxy(fspath) + if not self.isinitpath(fspath): + if ihook.pytest_ignore_collect(collection_path=fspath, config=self.config): + return () + + if handle_dupes: + keepduplicates = self.config.getoption("keepduplicates") + if not keepduplicates: + duplicate_paths = self.config.pluginmanager._duplicatepaths + if fspath in duplicate_paths: + return () + else: + duplicate_paths.add(fspath) + + return ihook.pytest_collect_file(file_path=fspath, parent=self) # type: ignore[no-any-return] + + @overload + def perform_collect( + self, args: Optional[Sequence[str]] = ..., genitems: "Literal[True]" = ... + ) -> Sequence[nodes.Item]: + ... + + @overload + def perform_collect( # noqa: F811 + self, args: Optional[Sequence[str]] = ..., genitems: bool = ... + ) -> Sequence[Union[nodes.Item, nodes.Collector]]: + ... + + def perform_collect( # noqa: F811 + self, args: Optional[Sequence[str]] = None, genitems: bool = True + ) -> Sequence[Union[nodes.Item, nodes.Collector]]: + """Perform the collection phase for this session. + + This is called by the default :hook:`pytest_collection` hook + implementation; see the documentation of this hook for more details. + For testing purposes, it may also be called directly on a fresh + ``Session``. + + This function normally recursively expands any collectors collected + from the session to their items, and only items are returned. For + testing purposes, this may be suppressed by passing ``genitems=False``, + in which case the return value contains these collectors unexpanded, + and ``session.items`` is empty. + """ + if args is None: + args = self.config.args + + self.trace("perform_collect", self, args) + self.trace.root.indent += 1 + + self._notfound: List[Tuple[str, Sequence[nodes.Collector]]] = [] + self._initial_parts: List[Tuple[Path, List[str]]] = [] + self.items: List[nodes.Item] = [] + + hook = self.config.hook + + items: Sequence[Union[nodes.Item, nodes.Collector]] = self.items + try: + initialpaths: List[Path] = [] + for arg in args: + fspath, parts = resolve_collection_argument( + self.config.invocation_params.dir, + arg, + as_pypath=self.config.option.pyargs, + ) + self._initial_parts.append((fspath, parts)) + initialpaths.append(fspath) + self._initialpaths = frozenset(initialpaths) + rep = collect_one_node(self) + self.ihook.pytest_collectreport(report=rep) + self.trace.root.indent -= 1 + if self._notfound: + errors = [] + for arg, collectors in self._notfound: + if collectors: + errors.append( + f"not found: {arg}\n(no name {arg!r} in any of {collectors!r})" + ) + else: + errors.append(f"found no collectors for {arg}") + + raise UsageError(*errors) + if not genitems: + items = rep.result + else: + if rep.passed: + for node in rep.result: + self.items.extend(self.genitems(node)) + + self.config.pluginmanager.check_pending() + hook.pytest_collection_modifyitems( + session=self, config=self.config, items=items + ) + finally: + hook.pytest_collection_finish(session=self) + + self.testscollected = len(items) + return items + + def collect(self) -> Iterator[Union[nodes.Item, nodes.Collector]]: + from _pytest.python import Package + + # Keep track of any collected nodes in here, so we don't duplicate fixtures. + node_cache1: Dict[Path, Sequence[nodes.Collector]] = {} + node_cache2: Dict[Tuple[Type[nodes.Collector], Path], nodes.Collector] = {} + + # Keep track of any collected collectors in matchnodes paths, so they + # are not collected more than once. + matchnodes_cache: Dict[Tuple[Type[nodes.Collector], str], CollectReport] = {} + + # Directories of pkgs with dunder-init files. + pkg_roots: Dict[Path, Package] = {} + + for argpath, names in self._initial_parts: + self.trace("processing argument", (argpath, names)) + self.trace.root.indent += 1 + + # Start with a Session root, and delve to argpath item (dir or file) + # and stack all Packages found on the way. + # No point in finding packages when collecting doctests. + if not self.config.getoption("doctestmodules", False): + pm = self.config.pluginmanager + for parent in (argpath, *argpath.parents): + if not pm._is_in_confcutdir(argpath): + break + + if parent.is_dir(): + pkginit = parent / "__init__.py" + if pkginit.is_file() and pkginit not in node_cache1: + col = self._collectfile(pkginit, handle_dupes=False) + if col: + if isinstance(col[0], Package): + pkg_roots[parent] = col[0] + node_cache1[col[0].path] = [col[0]] + + # If it's a directory argument, recurse and look for any Subpackages. + # Let the Package collector deal with subnodes, don't collect here. + if argpath.is_dir(): + assert not names, f"invalid arg {(argpath, names)!r}" + + seen_dirs: Set[Path] = set() + for direntry in visit(argpath, self._recurse): + if not direntry.is_file(): + continue + + path = Path(direntry.path) + dirpath = path.parent + + if dirpath not in seen_dirs: + # Collect packages first. + seen_dirs.add(dirpath) + pkginit = dirpath / "__init__.py" + if pkginit.exists(): + for x in self._collectfile(pkginit): + yield x + if isinstance(x, Package): + pkg_roots[dirpath] = x + if dirpath in pkg_roots: + # Do not collect packages here. + continue + + for x in self._collectfile(path): + key2 = (type(x), x.path) + if key2 in node_cache2: + yield node_cache2[key2] + else: + node_cache2[key2] = x + yield x + else: + assert argpath.is_file() + + if argpath in node_cache1: + col = node_cache1[argpath] + else: + collect_root = pkg_roots.get(argpath.parent, self) + col = collect_root._collectfile(argpath, handle_dupes=False) + if col: + node_cache1[argpath] = col + + matching = [] + work: List[ + Tuple[Sequence[Union[nodes.Item, nodes.Collector]], Sequence[str]] + ] = [(col, names)] + while work: + self.trace("matchnodes", col, names) + self.trace.root.indent += 1 + + matchnodes, matchnames = work.pop() + for node in matchnodes: + if not matchnames: + matching.append(node) + continue + if not isinstance(node, nodes.Collector): + continue + key = (type(node), node.nodeid) + if key in matchnodes_cache: + rep = matchnodes_cache[key] + else: + rep = collect_one_node(node) + matchnodes_cache[key] = rep + if rep.passed: + submatchnodes = [] + for r in rep.result: + # TODO: Remove parametrized workaround once collection structure contains + # parametrization. + if ( + r.name == matchnames[0] + or r.name.split("[")[0] == matchnames[0] + ): + submatchnodes.append(r) + if submatchnodes: + work.append((submatchnodes, matchnames[1:])) + else: + # Report collection failures here to avoid failing to run some test + # specified in the command line because the module could not be + # imported (#134). + node.ihook.pytest_collectreport(report=rep) + + self.trace("matchnodes finished -> ", len(matching), "nodes") + self.trace.root.indent -= 1 + + if not matching: + report_arg = "::".join((str(argpath), *names)) + self._notfound.append((report_arg, col)) + continue + + # If __init__.py was the only file requested, then the matched + # node will be the corresponding Package (by default), and the + # first yielded item will be the __init__ Module itself, so + # just use that. If this special case isn't taken, then all the + # files in the package will be yielded. + if argpath.name == "__init__.py" and isinstance(matching[0], Package): + try: + yield next(iter(matching[0].collect())) + except StopIteration: + # The package collects nothing with only an __init__.py + # file in it, which gets ignored by the default + # "python_files" option. + pass + continue + + yield from matching + + self.trace.root.indent -= 1 + + def genitems( + self, node: Union[nodes.Item, nodes.Collector] + ) -> Iterator[nodes.Item]: + self.trace("genitems", node) + if isinstance(node, nodes.Item): + node.ihook.pytest_itemcollected(item=node) + yield node + else: + assert isinstance(node, nodes.Collector) + rep = collect_one_node(node) + if rep.passed: + for subnode in rep.result: + yield from self.genitems(subnode) + node.ihook.pytest_collectreport(report=rep) + + +def search_pypath(module_name: str) -> str: + """Search sys.path for the given a dotted module name, and return its file system path.""" + try: + spec = importlib.util.find_spec(module_name) + # AttributeError: looks like package module, but actually filename + # ImportError: module does not exist + # ValueError: not a module name + except (AttributeError, ImportError, ValueError): + return module_name + if spec is None or spec.origin is None or spec.origin == "namespace": + return module_name + elif spec.submodule_search_locations: + return os.path.dirname(spec.origin) + else: + return spec.origin + + +def resolve_collection_argument( + invocation_path: Path, arg: str, *, as_pypath: bool = False +) -> Tuple[Path, List[str]]: + """Parse path arguments optionally containing selection parts and return (fspath, names). + + Command-line arguments can point to files and/or directories, and optionally contain + parts for specific tests selection, for example: + + "pkg/tests/test_foo.py::TestClass::test_foo" + + This function ensures the path exists, and returns a tuple: + + (Path("/full/path/to/pkg/tests/test_foo.py"), ["TestClass", "test_foo"]) + + When as_pypath is True, expects that the command-line argument actually contains + module paths instead of file-system paths: + + "pkg.tests.test_foo::TestClass::test_foo" + + In which case we search sys.path for a matching module, and then return the *path* to the + found module. + + If the path doesn't exist, raise UsageError. + If the path is a directory and selection parts are present, raise UsageError. + """ + base, squacket, rest = str(arg).partition("[") + strpath, *parts = base.split("::") + if parts: + parts[-1] = f"{parts[-1]}{squacket}{rest}" + if as_pypath: + strpath = search_pypath(strpath) + fspath = invocation_path / strpath + fspath = absolutepath(fspath) + if not safe_exists(fspath): + msg = ( + "module or package not found: {arg} (missing __init__.py?)" + if as_pypath + else "file or directory not found: {arg}" + ) + raise UsageError(msg.format(arg=arg)) + if parts and fspath.is_dir(): + msg = ( + "package argument cannot contain :: selection parts: {arg}" + if as_pypath + else "directory argument cannot contain :: selection parts: {arg}" + ) + raise UsageError(msg.format(arg=arg)) + return fspath, parts diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/mark/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/mark/__init__.py new file mode 100644 index 000000000..de46b4c8a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/mark/__init__.py @@ -0,0 +1,269 @@ +"""Generic mechanism for marking and selecting python functions.""" +import dataclasses +from typing import AbstractSet +from typing import Collection +from typing import List +from typing import Optional +from typing import TYPE_CHECKING +from typing import Union + +from .expression import Expression +from .expression import ParseError +from .structures import EMPTY_PARAMETERSET_OPTION +from .structures import get_empty_parameterset_mark +from .structures import Mark +from .structures import MARK_GEN +from .structures import MarkDecorator +from .structures import MarkGenerator +from .structures import ParameterSet +from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config import hookimpl +from _pytest.config import UsageError +from _pytest.config.argparsing import Parser +from _pytest.stash import StashKey + +if TYPE_CHECKING: + from _pytest.nodes import Item + + +__all__ = [ + "MARK_GEN", + "Mark", + "MarkDecorator", + "MarkGenerator", + "ParameterSet", + "get_empty_parameterset_mark", +] + + +old_mark_config_key = StashKey[Optional[Config]]() + + +def param( + *values: object, + marks: Union[MarkDecorator, Collection[Union[MarkDecorator, Mark]]] = (), + id: Optional[str] = None, +) -> ParameterSet: + """Specify a parameter in `pytest.mark.parametrize`_ calls or + :ref:`parametrized fixtures `. + + .. code-block:: python + + @pytest.mark.parametrize( + "test_input,expected", + [ + ("3+5", 8), + pytest.param("6*9", 42, marks=pytest.mark.xfail), + ], + ) + def test_eval(test_input, expected): + assert eval(test_input) == expected + + :param values: Variable args of the values of the parameter set, in order. + :param marks: A single mark or a list of marks to be applied to this parameter set. + :param id: The id to attribute to this parameter set. + """ + return ParameterSet.param(*values, marks=marks, id=id) + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("general") + group._addoption( + "-k", + action="store", + dest="keyword", + default="", + metavar="EXPRESSION", + help="Only run tests which match the given substring expression. " + "An expression is a Python evaluatable expression " + "where all names are substring-matched against test names " + "and their parent classes. Example: -k 'test_method or test_" + "other' matches all test functions and classes whose name " + "contains 'test_method' or 'test_other', while -k 'not test_method' " + "matches those that don't contain 'test_method' in their names. " + "-k 'not test_method and not test_other' will eliminate the matches. " + "Additionally keywords are matched to classes and functions " + "containing extra names in their 'extra_keyword_matches' set, " + "as well as functions which have names assigned directly to them. " + "The matching is case-insensitive.", + ) + + group._addoption( + "-m", + action="store", + dest="markexpr", + default="", + metavar="MARKEXPR", + help="Only run tests matching given mark expression. " + "For example: -m 'mark1 and not mark2'.", + ) + + group.addoption( + "--markers", + action="store_true", + help="show markers (builtin, plugin and per-project ones).", + ) + + parser.addini("markers", "Markers for test functions", "linelist") + parser.addini(EMPTY_PARAMETERSET_OPTION, "Default marker for empty parametersets") + + +@hookimpl(tryfirst=True) +def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]: + import _pytest.config + + if config.option.markers: + config._do_configure() + tw = _pytest.config.create_terminal_writer(config) + for line in config.getini("markers"): + parts = line.split(":", 1) + name = parts[0] + rest = parts[1] if len(parts) == 2 else "" + tw.write("@pytest.mark.%s:" % name, bold=True) + tw.line(rest) + tw.line() + config._ensure_unconfigure() + return 0 + + return None + + +@dataclasses.dataclass +class KeywordMatcher: + """A matcher for keywords. + + Given a list of names, matches any substring of one of these names. The + string inclusion check is case-insensitive. + + Will match on the name of colitem, including the names of its parents. + Only matches names of items which are either a :class:`Class` or a + :class:`Function`. + + Additionally, matches on names in the 'extra_keyword_matches' set of + any item, as well as names directly assigned to test functions. + """ + + __slots__ = ("_names",) + + _names: AbstractSet[str] + + @classmethod + def from_item(cls, item: "Item") -> "KeywordMatcher": + mapped_names = set() + + # Add the names of the current item and any parent items. + import pytest + + for node in item.listchain(): + if not isinstance(node, pytest.Session): + mapped_names.add(node.name) + + # Add the names added as extra keywords to current or parent items. + mapped_names.update(item.listextrakeywords()) + + # Add the names attached to the current function through direct assignment. + function_obj = getattr(item, "function", None) + if function_obj: + mapped_names.update(function_obj.__dict__) + + # Add the markers to the keywords as we no longer handle them correctly. + mapped_names.update(mark.name for mark in item.iter_markers()) + + return cls(mapped_names) + + def __call__(self, subname: str) -> bool: + subname = subname.lower() + names = (name.lower() for name in self._names) + + for name in names: + if subname in name: + return True + return False + + +def deselect_by_keyword(items: "List[Item]", config: Config) -> None: + keywordexpr = config.option.keyword.lstrip() + if not keywordexpr: + return + + expr = _parse_expression(keywordexpr, "Wrong expression passed to '-k'") + + remaining = [] + deselected = [] + for colitem in items: + if not expr.evaluate(KeywordMatcher.from_item(colitem)): + deselected.append(colitem) + else: + remaining.append(colitem) + + if deselected: + config.hook.pytest_deselected(items=deselected) + items[:] = remaining + + +@dataclasses.dataclass +class MarkMatcher: + """A matcher for markers which are present. + + Tries to match on any marker names, attached to the given colitem. + """ + + __slots__ = ("own_mark_names",) + + own_mark_names: AbstractSet[str] + + @classmethod + def from_item(cls, item: "Item") -> "MarkMatcher": + mark_names = {mark.name for mark in item.iter_markers()} + return cls(mark_names) + + def __call__(self, name: str) -> bool: + return name in self.own_mark_names + + +def deselect_by_mark(items: "List[Item]", config: Config) -> None: + matchexpr = config.option.markexpr + if not matchexpr: + return + + expr = _parse_expression(matchexpr, "Wrong expression passed to '-m'") + remaining: List[Item] = [] + deselected: List[Item] = [] + for item in items: + if expr.evaluate(MarkMatcher.from_item(item)): + remaining.append(item) + else: + deselected.append(item) + if deselected: + config.hook.pytest_deselected(items=deselected) + items[:] = remaining + + +def _parse_expression(expr: str, exc_message: str) -> Expression: + try: + return Expression.compile(expr) + except ParseError as e: + raise UsageError(f"{exc_message}: {expr}: {e}") from None + + +def pytest_collection_modifyitems(items: "List[Item]", config: Config) -> None: + deselect_by_keyword(items, config) + deselect_by_mark(items, config) + + +def pytest_configure(config: Config) -> None: + config.stash[old_mark_config_key] = MARK_GEN._config + MARK_GEN._config = config + + empty_parameterset = config.getini(EMPTY_PARAMETERSET_OPTION) + + if empty_parameterset not in ("skip", "xfail", "fail_at_collect", None, ""): + raise UsageError( + "{!s} must be one of skip, xfail or fail_at_collect" + " but it is {!r}".format(EMPTY_PARAMETERSET_OPTION, empty_parameterset) + ) + + +def pytest_unconfigure(config: Config) -> None: + MARK_GEN._config = config.stash.get(old_mark_config_key, None) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/mark/expression.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/mark/expression.py new file mode 100644 index 000000000..9287bcee5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/mark/expression.py @@ -0,0 +1,228 @@ +r"""Evaluate match expressions, as used by `-k` and `-m`. + +The grammar is: + +expression: expr? EOF +expr: and_expr ('or' and_expr)* +and_expr: not_expr ('and' not_expr)* +not_expr: 'not' not_expr | '(' expr ')' | ident +ident: (\w|:|\+|-|\.|\[|\]|\\|/)+ + +The semantics are: + +- Empty expression evaluates to False. +- ident evaluates to True of False according to a provided matcher function. +- or/and/not evaluate according to the usual boolean semantics. +""" +import ast +import dataclasses +import enum +import re +import sys +import types +from typing import Callable +from typing import Iterator +from typing import Mapping +from typing import NoReturn +from typing import Optional +from typing import Sequence + +if sys.version_info >= (3, 8): + astNameConstant = ast.Constant +else: + astNameConstant = ast.NameConstant + + +__all__ = [ + "Expression", + "ParseError", +] + + +class TokenType(enum.Enum): + LPAREN = "left parenthesis" + RPAREN = "right parenthesis" + OR = "or" + AND = "and" + NOT = "not" + IDENT = "identifier" + EOF = "end of input" + + +@dataclasses.dataclass(frozen=True) +class Token: + __slots__ = ("type", "value", "pos") + type: TokenType + value: str + pos: int + + +class ParseError(Exception): + """The expression contains invalid syntax. + + :param column: The column in the line where the error occurred (1-based). + :param message: A description of the error. + """ + + def __init__(self, column: int, message: str) -> None: + self.column = column + self.message = message + + def __str__(self) -> str: + return f"at column {self.column}: {self.message}" + + +class Scanner: + __slots__ = ("tokens", "current") + + def __init__(self, input: str) -> None: + self.tokens = self.lex(input) + self.current = next(self.tokens) + + def lex(self, input: str) -> Iterator[Token]: + pos = 0 + while pos < len(input): + if input[pos] in (" ", "\t"): + pos += 1 + elif input[pos] == "(": + yield Token(TokenType.LPAREN, "(", pos) + pos += 1 + elif input[pos] == ")": + yield Token(TokenType.RPAREN, ")", pos) + pos += 1 + else: + match = re.match(r"(:?\w|:|\+|-|\.|\[|\]|\\|/)+", input[pos:]) + if match: + value = match.group(0) + if value == "or": + yield Token(TokenType.OR, value, pos) + elif value == "and": + yield Token(TokenType.AND, value, pos) + elif value == "not": + yield Token(TokenType.NOT, value, pos) + else: + yield Token(TokenType.IDENT, value, pos) + pos += len(value) + else: + raise ParseError( + pos + 1, + f'unexpected character "{input[pos]}"', + ) + yield Token(TokenType.EOF, "", pos) + + def accept(self, type: TokenType, *, reject: bool = False) -> Optional[Token]: + if self.current.type is type: + token = self.current + if token.type is not TokenType.EOF: + self.current = next(self.tokens) + return token + if reject: + self.reject((type,)) + return None + + def reject(self, expected: Sequence[TokenType]) -> NoReturn: + raise ParseError( + self.current.pos + 1, + "expected {}; got {}".format( + " OR ".join(type.value for type in expected), + self.current.type.value, + ), + ) + + +# True, False and None are legal match expression identifiers, +# but illegal as Python identifiers. To fix this, this prefix +# is added to identifiers in the conversion to Python AST. +IDENT_PREFIX = "$" + + +def expression(s: Scanner) -> ast.Expression: + if s.accept(TokenType.EOF): + ret: ast.expr = astNameConstant(False) + else: + ret = expr(s) + s.accept(TokenType.EOF, reject=True) + return ast.fix_missing_locations(ast.Expression(ret)) + + +def expr(s: Scanner) -> ast.expr: + ret = and_expr(s) + while s.accept(TokenType.OR): + rhs = and_expr(s) + ret = ast.BoolOp(ast.Or(), [ret, rhs]) + return ret + + +def and_expr(s: Scanner) -> ast.expr: + ret = not_expr(s) + while s.accept(TokenType.AND): + rhs = not_expr(s) + ret = ast.BoolOp(ast.And(), [ret, rhs]) + return ret + + +def not_expr(s: Scanner) -> ast.expr: + if s.accept(TokenType.NOT): + return ast.UnaryOp(ast.Not(), not_expr(s)) + if s.accept(TokenType.LPAREN): + ret = expr(s) + s.accept(TokenType.RPAREN, reject=True) + return ret + ident = s.accept(TokenType.IDENT) + if ident: + return ast.Name(IDENT_PREFIX + ident.value, ast.Load()) + s.reject((TokenType.NOT, TokenType.LPAREN, TokenType.IDENT)) + + +class MatcherAdapter(Mapping[str, bool]): + """Adapts a matcher function to a locals mapping as required by eval().""" + + def __init__(self, matcher: Callable[[str], bool]) -> None: + self.matcher = matcher + + def __getitem__(self, key: str) -> bool: + return self.matcher(key[len(IDENT_PREFIX) :]) + + def __iter__(self) -> Iterator[str]: + raise NotImplementedError() + + def __len__(self) -> int: + raise NotImplementedError() + + +class Expression: + """A compiled match expression as used by -k and -m. + + The expression can be evaluated against different matchers. + """ + + __slots__ = ("code",) + + def __init__(self, code: types.CodeType) -> None: + self.code = code + + @classmethod + def compile(self, input: str) -> "Expression": + """Compile a match expression. + + :param input: The input expression - one line. + """ + astexpr = expression(Scanner(input)) + code: types.CodeType = compile( + astexpr, + filename="", + mode="eval", + ) + return Expression(code) + + def evaluate(self, matcher: Callable[[str], bool]) -> bool: + """Evaluate the match expression. + + :param matcher: + Given an identifier, should return whether it matches or not. + Should be prepared to handle arbitrary strings as input. + + :returns: Whether the expression matches or not. + """ + ret: bool = eval(self.code, {"__builtins__": {}}, MatcherAdapter(matcher)) + return ret diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/mark/structures.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/mark/structures.py new file mode 100644 index 000000000..55620f042 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/mark/structures.py @@ -0,0 +1,618 @@ +import collections.abc +import dataclasses +import inspect +import warnings +from typing import Any +from typing import Callable +from typing import Collection +from typing import Iterable +from typing import Iterator +from typing import List +from typing import Mapping +from typing import MutableMapping +from typing import NamedTuple +from typing import Optional +from typing import overload +from typing import Sequence +from typing import Set +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import TypeVar +from typing import Union + +from .._code import getfslineno +from ..compat import ascii_escaped +from ..compat import final +from ..compat import NOTSET +from ..compat import NotSetType +from _pytest.config import Config +from _pytest.deprecated import check_ispytest +from _pytest.outcomes import fail +from _pytest.warning_types import PytestUnknownMarkWarning + +if TYPE_CHECKING: + from ..nodes import Node + + +EMPTY_PARAMETERSET_OPTION = "empty_parameter_set_mark" + + +def istestfunc(func) -> bool: + return callable(func) and getattr(func, "__name__", "") != "" + + +def get_empty_parameterset_mark( + config: Config, argnames: Sequence[str], func +) -> "MarkDecorator": + from ..nodes import Collector + + fs, lineno = getfslineno(func) + reason = "got empty parameter set %r, function %s at %s:%d" % ( + argnames, + func.__name__, + fs, + lineno, + ) + + requested_mark = config.getini(EMPTY_PARAMETERSET_OPTION) + if requested_mark in ("", None, "skip"): + mark = MARK_GEN.skip(reason=reason) + elif requested_mark == "xfail": + mark = MARK_GEN.xfail(reason=reason, run=False) + elif requested_mark == "fail_at_collect": + f_name = func.__name__ + _, lineno = getfslineno(func) + raise Collector.CollectError( + "Empty parameter set in '%s' at line %d" % (f_name, lineno + 1) + ) + else: + raise LookupError(requested_mark) + return mark + + +class ParameterSet(NamedTuple): + values: Sequence[Union[object, NotSetType]] + marks: Collection[Union["MarkDecorator", "Mark"]] + id: Optional[str] + + @classmethod + def param( + cls, + *values: object, + marks: Union["MarkDecorator", Collection[Union["MarkDecorator", "Mark"]]] = (), + id: Optional[str] = None, + ) -> "ParameterSet": + if isinstance(marks, MarkDecorator): + marks = (marks,) + else: + assert isinstance(marks, collections.abc.Collection) + + if id is not None: + if not isinstance(id, str): + raise TypeError(f"Expected id to be a string, got {type(id)}: {id!r}") + id = ascii_escaped(id) + return cls(values, marks, id) + + @classmethod + def extract_from( + cls, + parameterset: Union["ParameterSet", Sequence[object], object], + force_tuple: bool = False, + ) -> "ParameterSet": + """Extract from an object or objects. + + :param parameterset: + A legacy style parameterset that may or may not be a tuple, + and may or may not be wrapped into a mess of mark objects. + + :param force_tuple: + Enforce tuple wrapping so single argument tuple values + don't get decomposed and break tests. + """ + + if isinstance(parameterset, cls): + return parameterset + if force_tuple: + return cls.param(parameterset) + else: + # TODO: Refactor to fix this type-ignore. Currently the following + # passes type-checking but crashes: + # + # @pytest.mark.parametrize(('x', 'y'), [1, 2]) + # def test_foo(x, y): pass + return cls(parameterset, marks=[], id=None) # type: ignore[arg-type] + + @staticmethod + def _parse_parametrize_args( + argnames: Union[str, Sequence[str]], + argvalues: Iterable[Union["ParameterSet", Sequence[object], object]], + *args, + **kwargs, + ) -> Tuple[Sequence[str], bool]: + if isinstance(argnames, str): + argnames = [x.strip() for x in argnames.split(",") if x.strip()] + force_tuple = len(argnames) == 1 + else: + force_tuple = False + return argnames, force_tuple + + @staticmethod + def _parse_parametrize_parameters( + argvalues: Iterable[Union["ParameterSet", Sequence[object], object]], + force_tuple: bool, + ) -> List["ParameterSet"]: + return [ + ParameterSet.extract_from(x, force_tuple=force_tuple) for x in argvalues + ] + + @classmethod + def _for_parametrize( + cls, + argnames: Union[str, Sequence[str]], + argvalues: Iterable[Union["ParameterSet", Sequence[object], object]], + func, + config: Config, + nodeid: str, + ) -> Tuple[Sequence[str], List["ParameterSet"]]: + argnames, force_tuple = cls._parse_parametrize_args(argnames, argvalues) + parameters = cls._parse_parametrize_parameters(argvalues, force_tuple) + del argvalues + + if parameters: + # Check all parameter sets have the correct number of values. + for param in parameters: + if len(param.values) != len(argnames): + msg = ( + '{nodeid}: in "parametrize" the number of names ({names_len}):\n' + " {names}\n" + "must be equal to the number of values ({values_len}):\n" + " {values}" + ) + fail( + msg.format( + nodeid=nodeid, + values=param.values, + names=argnames, + names_len=len(argnames), + values_len=len(param.values), + ), + pytrace=False, + ) + else: + # Empty parameter set (likely computed at runtime): create a single + # parameter set with NOTSET values, with the "empty parameter set" mark applied to it. + mark = get_empty_parameterset_mark(config, argnames, func) + parameters.append( + ParameterSet(values=(NOTSET,) * len(argnames), marks=[mark], id=None) + ) + return argnames, parameters + + +@final +@dataclasses.dataclass(frozen=True) +class Mark: + """A pytest mark.""" + + #: Name of the mark. + name: str + #: Positional arguments of the mark decorator. + args: Tuple[Any, ...] + #: Keyword arguments of the mark decorator. + kwargs: Mapping[str, Any] + + #: Source Mark for ids with parametrize Marks. + _param_ids_from: Optional["Mark"] = dataclasses.field(default=None, repr=False) + #: Resolved/generated ids with parametrize Marks. + _param_ids_generated: Optional[Sequence[str]] = dataclasses.field( + default=None, repr=False + ) + + def __init__( + self, + name: str, + args: Tuple[Any, ...], + kwargs: Mapping[str, Any], + param_ids_from: Optional["Mark"] = None, + param_ids_generated: Optional[Sequence[str]] = None, + *, + _ispytest: bool = False, + ) -> None: + """:meta private:""" + check_ispytest(_ispytest) + # Weirdness to bypass frozen=True. + object.__setattr__(self, "name", name) + object.__setattr__(self, "args", args) + object.__setattr__(self, "kwargs", kwargs) + object.__setattr__(self, "_param_ids_from", param_ids_from) + object.__setattr__(self, "_param_ids_generated", param_ids_generated) + + def _has_param_ids(self) -> bool: + return "ids" in self.kwargs or len(self.args) >= 4 + + def combined_with(self, other: "Mark") -> "Mark": + """Return a new Mark which is a combination of this + Mark and another Mark. + + Combines by appending args and merging kwargs. + + :param Mark other: The mark to combine with. + :rtype: Mark + """ + assert self.name == other.name + + # Remember source of ids with parametrize Marks. + param_ids_from: Optional[Mark] = None + if self.name == "parametrize": + if other._has_param_ids(): + param_ids_from = other + elif self._has_param_ids(): + param_ids_from = self + + return Mark( + self.name, + self.args + other.args, + dict(self.kwargs, **other.kwargs), + param_ids_from=param_ids_from, + _ispytest=True, + ) + + +# A generic parameter designating an object to which a Mark may +# be applied -- a test function (callable) or class. +# Note: a lambda is not allowed, but this can't be represented. +Markable = TypeVar("Markable", bound=Union[Callable[..., object], type]) + + +@dataclasses.dataclass +class MarkDecorator: + """A decorator for applying a mark on test functions and classes. + + ``MarkDecorators`` are created with ``pytest.mark``:: + + mark1 = pytest.mark.NAME # Simple MarkDecorator + mark2 = pytest.mark.NAME(name1=value) # Parametrized MarkDecorator + + and can then be applied as decorators to test functions:: + + @mark2 + def test_function(): + pass + + When a ``MarkDecorator`` is called, it does the following: + + 1. If called with a single class as its only positional argument and no + additional keyword arguments, it attaches the mark to the class so it + gets applied automatically to all test cases found in that class. + + 2. If called with a single function as its only positional argument and + no additional keyword arguments, it attaches the mark to the function, + containing all the arguments already stored internally in the + ``MarkDecorator``. + + 3. When called in any other case, it returns a new ``MarkDecorator`` + instance with the original ``MarkDecorator``'s content updated with + the arguments passed to this call. + + Note: The rules above prevent a ``MarkDecorator`` from storing only a + single function or class reference as its positional argument with no + additional keyword or positional arguments. You can work around this by + using `with_args()`. + """ + + mark: Mark + + def __init__(self, mark: Mark, *, _ispytest: bool = False) -> None: + """:meta private:""" + check_ispytest(_ispytest) + self.mark = mark + + @property + def name(self) -> str: + """Alias for mark.name.""" + return self.mark.name + + @property + def args(self) -> Tuple[Any, ...]: + """Alias for mark.args.""" + return self.mark.args + + @property + def kwargs(self) -> Mapping[str, Any]: + """Alias for mark.kwargs.""" + return self.mark.kwargs + + @property + def markname(self) -> str: + """:meta private:""" + return self.name # for backward-compat (2.4.1 had this attr) + + def with_args(self, *args: object, **kwargs: object) -> "MarkDecorator": + """Return a MarkDecorator with extra arguments added. + + Unlike calling the MarkDecorator, with_args() can be used even + if the sole argument is a callable/class. + """ + mark = Mark(self.name, args, kwargs, _ispytest=True) + return MarkDecorator(self.mark.combined_with(mark), _ispytest=True) + + # Type ignored because the overloads overlap with an incompatible + # return type. Not much we can do about that. Thankfully mypy picks + # the first match so it works out even if we break the rules. + @overload + def __call__(self, arg: Markable) -> Markable: # type: ignore[misc] + pass + + @overload + def __call__(self, *args: object, **kwargs: object) -> "MarkDecorator": + pass + + def __call__(self, *args: object, **kwargs: object): + """Call the MarkDecorator.""" + if args and not kwargs: + func = args[0] + is_class = inspect.isclass(func) + if len(args) == 1 and (istestfunc(func) or is_class): + store_mark(func, self.mark) + return func + return self.with_args(*args, **kwargs) + + +def get_unpacked_marks( + obj: Union[object, type], + *, + consider_mro: bool = True, +) -> List[Mark]: + """Obtain the unpacked marks that are stored on an object. + + If obj is a class and consider_mro is true, return marks applied to + this class and all of its super-classes in MRO order. If consider_mro + is false, only return marks applied directly to this class. + """ + if isinstance(obj, type): + if not consider_mro: + mark_lists = [obj.__dict__.get("pytestmark", [])] + else: + mark_lists = [ + x.__dict__.get("pytestmark", []) for x in reversed(obj.__mro__) + ] + mark_list = [] + for item in mark_lists: + if isinstance(item, list): + mark_list.extend(item) + else: + mark_list.append(item) + else: + mark_attribute = getattr(obj, "pytestmark", []) + if isinstance(mark_attribute, list): + mark_list = mark_attribute + else: + mark_list = [mark_attribute] + return list(normalize_mark_list(mark_list)) + + +def normalize_mark_list( + mark_list: Iterable[Union[Mark, MarkDecorator]] +) -> Iterable[Mark]: + """ + Normalize an iterable of Mark or MarkDecorator objects into a list of marks + by retrieving the `mark` attribute on MarkDecorator instances. + + :param mark_list: marks to normalize + :returns: A new list of the extracted Mark objects + """ + for mark in mark_list: + mark_obj = getattr(mark, "mark", mark) + if not isinstance(mark_obj, Mark): + raise TypeError(f"got {repr(mark_obj)} instead of Mark") + yield mark_obj + + +def store_mark(obj, mark: Mark) -> None: + """Store a Mark on an object. + + This is used to implement the Mark declarations/decorators correctly. + """ + assert isinstance(mark, Mark), mark + # Always reassign name to avoid updating pytestmark in a reference that + # was only borrowed. + obj.pytestmark = [*get_unpacked_marks(obj, consider_mro=False), mark] + + +# Typing for builtin pytest marks. This is cheating; it gives builtin marks +# special privilege, and breaks modularity. But practicality beats purity... +if TYPE_CHECKING: + from _pytest.scope import _ScopeName + + class _SkipMarkDecorator(MarkDecorator): + @overload # type: ignore[override,misc,no-overload-impl] + def __call__(self, arg: Markable) -> Markable: + ... + + @overload + def __call__(self, reason: str = ...) -> "MarkDecorator": + ... + + class _SkipifMarkDecorator(MarkDecorator): + def __call__( # type: ignore[override] + self, + condition: Union[str, bool] = ..., + *conditions: Union[str, bool], + reason: str = ..., + ) -> MarkDecorator: + ... + + class _XfailMarkDecorator(MarkDecorator): + @overload # type: ignore[override,misc,no-overload-impl] + def __call__(self, arg: Markable) -> Markable: + ... + + @overload + def __call__( + self, + condition: Union[str, bool] = ..., + *conditions: Union[str, bool], + reason: str = ..., + run: bool = ..., + raises: Union[Type[BaseException], Tuple[Type[BaseException], ...]] = ..., + strict: bool = ..., + ) -> MarkDecorator: + ... + + class _ParametrizeMarkDecorator(MarkDecorator): + def __call__( # type: ignore[override] + self, + argnames: Union[str, Sequence[str]], + argvalues: Iterable[Union[ParameterSet, Sequence[object], object]], + *, + indirect: Union[bool, Sequence[str]] = ..., + ids: Optional[ + Union[ + Iterable[Union[None, str, float, int, bool]], + Callable[[Any], Optional[object]], + ] + ] = ..., + scope: Optional[_ScopeName] = ..., + ) -> MarkDecorator: + ... + + class _UsefixturesMarkDecorator(MarkDecorator): + def __call__(self, *fixtures: str) -> MarkDecorator: # type: ignore[override] + ... + + class _FilterwarningsMarkDecorator(MarkDecorator): + def __call__(self, *filters: str) -> MarkDecorator: # type: ignore[override] + ... + + +@final +class MarkGenerator: + """Factory for :class:`MarkDecorator` objects - exposed as + a ``pytest.mark`` singleton instance. + + Example:: + + import pytest + + @pytest.mark.slowtest + def test_function(): + pass + + applies a 'slowtest' :class:`Mark` on ``test_function``. + """ + + # See TYPE_CHECKING above. + if TYPE_CHECKING: + skip: _SkipMarkDecorator + skipif: _SkipifMarkDecorator + xfail: _XfailMarkDecorator + parametrize: _ParametrizeMarkDecorator + usefixtures: _UsefixturesMarkDecorator + filterwarnings: _FilterwarningsMarkDecorator + + def __init__(self, *, _ispytest: bool = False) -> None: + check_ispytest(_ispytest) + self._config: Optional[Config] = None + self._markers: Set[str] = set() + + def __getattr__(self, name: str) -> MarkDecorator: + """Generate a new :class:`MarkDecorator` with the given name.""" + if name[0] == "_": + raise AttributeError("Marker name must NOT start with underscore") + + if self._config is not None: + # We store a set of markers as a performance optimisation - if a mark + # name is in the set we definitely know it, but a mark may be known and + # not in the set. We therefore start by updating the set! + if name not in self._markers: + for line in self._config.getini("markers"): + # example lines: "skipif(condition): skip the given test if..." + # or "hypothesis: tests which use Hypothesis", so to get the + # marker name we split on both `:` and `(`. + marker = line.split(":")[0].split("(")[0].strip() + self._markers.add(marker) + + # If the name is not in the set of known marks after updating, + # then it really is time to issue a warning or an error. + if name not in self._markers: + if self._config.option.strict_markers or self._config.option.strict: + fail( + f"{name!r} not found in `markers` configuration option", + pytrace=False, + ) + + # Raise a specific error for common misspellings of "parametrize". + if name in ["parameterize", "parametrise", "parameterise"]: + __tracebackhide__ = True + fail(f"Unknown '{name}' mark, did you mean 'parametrize'?") + + warnings.warn( + "Unknown pytest.mark.%s - is this a typo? You can register " + "custom marks to avoid this warning - for details, see " + "https://docs.pytest.org/en/stable/how-to/mark.html" % name, + PytestUnknownMarkWarning, + 2, + ) + + return MarkDecorator(Mark(name, (), {}, _ispytest=True), _ispytest=True) + + +MARK_GEN = MarkGenerator(_ispytest=True) + + +@final +class NodeKeywords(MutableMapping[str, Any]): + __slots__ = ("node", "parent", "_markers") + + def __init__(self, node: "Node") -> None: + self.node = node + self.parent = node.parent + self._markers = {node.name: True} + + def __getitem__(self, key: str) -> Any: + try: + return self._markers[key] + except KeyError: + if self.parent is None: + raise + return self.parent.keywords[key] + + def __setitem__(self, key: str, value: Any) -> None: + self._markers[key] = value + + # Note: we could've avoided explicitly implementing some of the methods + # below and use the collections.abc fallback, but that would be slow. + + def __contains__(self, key: object) -> bool: + return ( + key in self._markers + or self.parent is not None + and key in self.parent.keywords + ) + + def update( # type: ignore[override] + self, + other: Union[Mapping[str, Any], Iterable[Tuple[str, Any]]] = (), + **kwds: Any, + ) -> None: + self._markers.update(other) + self._markers.update(kwds) + + def __delitem__(self, key: str) -> None: + raise ValueError("cannot delete key in keywords dict") + + def __iter__(self) -> Iterator[str]: + # Doesn't need to be fast. + yield from self._markers + if self.parent is not None: + for keyword in self.parent.keywords: + # self._marks and self.parent.keywords can have duplicates. + if keyword not in self._markers: + yield keyword + + def __len__(self) -> int: + # Doesn't need to be fast. + return sum(1 for keyword in self) + + def __repr__(self) -> str: + return f"" diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/monkeypatch.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/monkeypatch.py new file mode 100644 index 000000000..9e51ff335 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/monkeypatch.py @@ -0,0 +1,421 @@ +"""Monkeypatching and mocking functionality.""" +import os +import re +import sys +import warnings +from contextlib import contextmanager +from typing import Any +from typing import Generator +from typing import List +from typing import Mapping +from typing import MutableMapping +from typing import Optional +from typing import overload +from typing import Tuple +from typing import TypeVar +from typing import Union + +from _pytest.compat import final +from _pytest.fixtures import fixture +from _pytest.warning_types import PytestWarning + +RE_IMPORT_ERROR_NAME = re.compile(r"^No module named (.*)$") + + +K = TypeVar("K") +V = TypeVar("V") + + +@fixture +def monkeypatch() -> Generator["MonkeyPatch", None, None]: + """A convenient fixture for monkey-patching. + + The fixture provides these methods to modify objects, dictionaries, or + :data:`os.environ`: + + * :meth:`monkeypatch.setattr(obj, name, value, raising=True) ` + * :meth:`monkeypatch.delattr(obj, name, raising=True) ` + * :meth:`monkeypatch.setitem(mapping, name, value) ` + * :meth:`monkeypatch.delitem(obj, name, raising=True) ` + * :meth:`monkeypatch.setenv(name, value, prepend=None) ` + * :meth:`monkeypatch.delenv(name, raising=True) ` + * :meth:`monkeypatch.syspath_prepend(path) ` + * :meth:`monkeypatch.chdir(path) ` + * :meth:`monkeypatch.context() ` + + All modifications will be undone after the requesting test function or + fixture has finished. The ``raising`` parameter determines if a :class:`KeyError` + or :class:`AttributeError` will be raised if the set/deletion operation does not have the + specified target. + + To undo modifications done by the fixture in a contained scope, + use :meth:`context() `. + """ + mpatch = MonkeyPatch() + yield mpatch + mpatch.undo() + + +def resolve(name: str) -> object: + # Simplified from zope.dottedname. + parts = name.split(".") + + used = parts.pop(0) + found: object = __import__(used) + for part in parts: + used += "." + part + try: + found = getattr(found, part) + except AttributeError: + pass + else: + continue + # We use explicit un-nesting of the handling block in order + # to avoid nested exceptions. + try: + __import__(used) + except ImportError as ex: + expected = str(ex).split()[-1] + if expected == used: + raise + else: + raise ImportError(f"import error in {used}: {ex}") from ex + found = annotated_getattr(found, part, used) + return found + + +def annotated_getattr(obj: object, name: str, ann: str) -> object: + try: + obj = getattr(obj, name) + except AttributeError as e: + raise AttributeError( + "{!r} object at {} has no attribute {!r}".format( + type(obj).__name__, ann, name + ) + ) from e + return obj + + +def derive_importpath(import_path: str, raising: bool) -> Tuple[str, object]: + if not isinstance(import_path, str) or "." not in import_path: + raise TypeError(f"must be absolute import path string, not {import_path!r}") + module, attr = import_path.rsplit(".", 1) + target = resolve(module) + if raising: + annotated_getattr(target, attr, ann=module) + return attr, target + + +class Notset: + def __repr__(self) -> str: + return "" + + +notset = Notset() + + +@final +class MonkeyPatch: + """Helper to conveniently monkeypatch attributes/items/environment + variables/syspath. + + Returned by the :fixture:`monkeypatch` fixture. + + .. versionchanged:: 6.2 + Can now also be used directly as `pytest.MonkeyPatch()`, for when + the fixture is not available. In this case, use + :meth:`with MonkeyPatch.context() as mp: ` or remember to call + :meth:`undo` explicitly. + """ + + def __init__(self) -> None: + self._setattr: List[Tuple[object, str, object]] = [] + self._setitem: List[Tuple[Mapping[Any, Any], object, object]] = [] + self._cwd: Optional[str] = None + self._savesyspath: Optional[List[str]] = None + + @classmethod + @contextmanager + def context(cls) -> Generator["MonkeyPatch", None, None]: + """Context manager that returns a new :class:`MonkeyPatch` object + which undoes any patching done inside the ``with`` block upon exit. + + Example: + + .. code-block:: python + + import functools + + + def test_partial(monkeypatch): + with monkeypatch.context() as m: + m.setattr(functools, "partial", 3) + + Useful in situations where it is desired to undo some patches before the test ends, + such as mocking ``stdlib`` functions that might break pytest itself if mocked (for examples + of this see :issue:`3290`). + """ + m = cls() + try: + yield m + finally: + m.undo() + + @overload + def setattr( + self, + target: str, + name: object, + value: Notset = ..., + raising: bool = ..., + ) -> None: + ... + + @overload + def setattr( + self, + target: object, + name: str, + value: object, + raising: bool = ..., + ) -> None: + ... + + def setattr( + self, + target: Union[str, object], + name: Union[object, str], + value: object = notset, + raising: bool = True, + ) -> None: + """ + Set attribute value on target, memorizing the old value. + + For example: + + .. code-block:: python + + import os + + monkeypatch.setattr(os, "getcwd", lambda: "/") + + The code above replaces the :func:`os.getcwd` function by a ``lambda`` which + always returns ``"/"``. + + For convenience, you can specify a string as ``target`` which + will be interpreted as a dotted import path, with the last part + being the attribute name: + + .. code-block:: python + + monkeypatch.setattr("os.getcwd", lambda: "/") + + Raises :class:`AttributeError` if the attribute does not exist, unless + ``raising`` is set to False. + + **Where to patch** + + ``monkeypatch.setattr`` works by (temporarily) changing the object that a name points to with another one. + There can be many names pointing to any individual object, so for patching to work you must ensure + that you patch the name used by the system under test. + + See the section :ref:`Where to patch ` in the :mod:`unittest.mock` + docs for a complete explanation, which is meant for :func:`unittest.mock.patch` but + applies to ``monkeypatch.setattr`` as well. + """ + __tracebackhide__ = True + import inspect + + if isinstance(value, Notset): + if not isinstance(target, str): + raise TypeError( + "use setattr(target, name, value) or " + "setattr(target, value) with target being a dotted " + "import string" + ) + value = name + name, target = derive_importpath(target, raising) + else: + if not isinstance(name, str): + raise TypeError( + "use setattr(target, name, value) with name being a string or " + "setattr(target, value) with target being a dotted " + "import string" + ) + + oldval = getattr(target, name, notset) + if raising and oldval is notset: + raise AttributeError(f"{target!r} has no attribute {name!r}") + + # avoid class descriptors like staticmethod/classmethod + if inspect.isclass(target): + oldval = target.__dict__.get(name, notset) + self._setattr.append((target, name, oldval)) + setattr(target, name, value) + + def delattr( + self, + target: Union[object, str], + name: Union[str, Notset] = notset, + raising: bool = True, + ) -> None: + """Delete attribute ``name`` from ``target``. + + If no ``name`` is specified and ``target`` is a string + it will be interpreted as a dotted import path with the + last part being the attribute name. + + Raises AttributeError it the attribute does not exist, unless + ``raising`` is set to False. + """ + __tracebackhide__ = True + import inspect + + if isinstance(name, Notset): + if not isinstance(target, str): + raise TypeError( + "use delattr(target, name) or " + "delattr(target) with target being a dotted " + "import string" + ) + name, target = derive_importpath(target, raising) + + if not hasattr(target, name): + if raising: + raise AttributeError(name) + else: + oldval = getattr(target, name, notset) + # Avoid class descriptors like staticmethod/classmethod. + if inspect.isclass(target): + oldval = target.__dict__.get(name, notset) + self._setattr.append((target, name, oldval)) + delattr(target, name) + + def setitem(self, dic: Mapping[K, V], name: K, value: V) -> None: + """Set dictionary entry ``name`` to value.""" + self._setitem.append((dic, name, dic.get(name, notset))) + # Not all Mapping types support indexing, but MutableMapping doesn't support TypedDict + dic[name] = value # type: ignore[index] + + def delitem(self, dic: Mapping[K, V], name: K, raising: bool = True) -> None: + """Delete ``name`` from dict. + + Raises ``KeyError`` if it doesn't exist, unless ``raising`` is set to + False. + """ + if name not in dic: + if raising: + raise KeyError(name) + else: + self._setitem.append((dic, name, dic.get(name, notset))) + # Not all Mapping types support indexing, but MutableMapping doesn't support TypedDict + del dic[name] # type: ignore[attr-defined] + + def setenv(self, name: str, value: str, prepend: Optional[str] = None) -> None: + """Set environment variable ``name`` to ``value``. + + If ``prepend`` is a character, read the current environment variable + value and prepend the ``value`` adjoined with the ``prepend`` + character. + """ + if not isinstance(value, str): + warnings.warn( # type: ignore[unreachable] + PytestWarning( + "Value of environment variable {name} type should be str, but got " + "{value!r} (type: {type}); converted to str implicitly".format( + name=name, value=value, type=type(value).__name__ + ) + ), + stacklevel=2, + ) + value = str(value) + if prepend and name in os.environ: + value = value + prepend + os.environ[name] + self.setitem(os.environ, name, value) + + def delenv(self, name: str, raising: bool = True) -> None: + """Delete ``name`` from the environment. + + Raises ``KeyError`` if it does not exist, unless ``raising`` is set to + False. + """ + environ: MutableMapping[str, str] = os.environ + self.delitem(environ, name, raising=raising) + + def syspath_prepend(self, path) -> None: + """Prepend ``path`` to ``sys.path`` list of import locations.""" + + if self._savesyspath is None: + self._savesyspath = sys.path[:] + sys.path.insert(0, str(path)) + + # https://github.com/pypa/setuptools/blob/d8b901bc/docs/pkg_resources.txt#L162-L171 + # this is only needed when pkg_resources was already loaded by the namespace package + if "pkg_resources" in sys.modules: + from pkg_resources import fixup_namespace_packages + + fixup_namespace_packages(str(path)) + + # A call to syspathinsert() usually means that the caller wants to + # import some dynamically created files, thus with python3 we + # invalidate its import caches. + # This is especially important when any namespace package is in use, + # since then the mtime based FileFinder cache (that gets created in + # this case already) gets not invalidated when writing the new files + # quickly afterwards. + from importlib import invalidate_caches + + invalidate_caches() + + def chdir(self, path: Union[str, "os.PathLike[str]"]) -> None: + """Change the current working directory to the specified path. + + :param path: + The path to change into. + """ + if self._cwd is None: + self._cwd = os.getcwd() + os.chdir(path) + + def undo(self) -> None: + """Undo previous changes. + + This call consumes the undo stack. Calling it a second time has no + effect unless you do more monkeypatching after the undo call. + + There is generally no need to call `undo()`, since it is + called automatically during tear-down. + + .. note:: + The same `monkeypatch` fixture is used across a + single test function invocation. If `monkeypatch` is used both by + the test function itself and one of the test fixtures, + calling `undo()` will undo all of the changes made in + both functions. + + Prefer to use :meth:`context() ` instead. + """ + for obj, name, value in reversed(self._setattr): + if value is not notset: + setattr(obj, name, value) + else: + delattr(obj, name) + self._setattr[:] = [] + for dictionary, key, value in reversed(self._setitem): + if value is notset: + try: + # Not all Mapping types support indexing, but MutableMapping doesn't support TypedDict + del dictionary[key] # type: ignore[attr-defined] + except KeyError: + pass # Was already deleted, so we have the desired state. + else: + # Not all Mapping types support indexing, but MutableMapping doesn't support TypedDict + dictionary[key] = value # type: ignore[index] + self._setitem[:] = [] + if self._savesyspath is not None: + sys.path[:] = self._savesyspath + self._savesyspath = None + + if self._cwd is not None: + os.chdir(self._cwd) + self._cwd = None diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/nodes.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/nodes.py new file mode 100644 index 000000000..667a02b77 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/nodes.py @@ -0,0 +1,783 @@ +import os +import warnings +from inspect import signature +from pathlib import Path +from typing import Any +from typing import Callable +from typing import cast +from typing import Iterable +from typing import Iterator +from typing import List +from typing import MutableMapping +from typing import Optional +from typing import overload +from typing import Set +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import TypeVar +from typing import Union + +import _pytest._code +from _pytest._code import getfslineno +from _pytest._code.code import ExceptionInfo +from _pytest._code.code import TerminalRepr +from _pytest._code.code import Traceback +from _pytest.compat import cached_property +from _pytest.compat import LEGACY_PATH +from _pytest.config import Config +from _pytest.config import ConftestImportFailure +from _pytest.deprecated import FSCOLLECTOR_GETHOOKPROXY_ISINITPATH +from _pytest.deprecated import NODE_CTOR_FSPATH_ARG +from _pytest.mark.structures import Mark +from _pytest.mark.structures import MarkDecorator +from _pytest.mark.structures import NodeKeywords +from _pytest.outcomes import fail +from _pytest.pathlib import absolutepath +from _pytest.pathlib import commonpath +from _pytest.stash import Stash +from _pytest.warning_types import PytestWarning + +if TYPE_CHECKING: + # Imported here due to circular import. + from _pytest.main import Session + from _pytest._code.code import _TracebackStyle + + +SEP = "/" + +tracebackcutdir = Path(_pytest.__file__).parent + + +def iterparentnodeids(nodeid: str) -> Iterator[str]: + """Return the parent node IDs of a given node ID, inclusive. + + For the node ID + + "testing/code/test_excinfo.py::TestFormattedExcinfo::test_repr_source" + + the result would be + + "" + "testing" + "testing/code" + "testing/code/test_excinfo.py" + "testing/code/test_excinfo.py::TestFormattedExcinfo" + "testing/code/test_excinfo.py::TestFormattedExcinfo::test_repr_source" + + Note that / components are only considered until the first ::. + """ + pos = 0 + first_colons: Optional[int] = nodeid.find("::") + if first_colons == -1: + first_colons = None + # The root Session node - always present. + yield "" + # Eagerly consume SEP parts until first colons. + while True: + at = nodeid.find(SEP, pos, first_colons) + if at == -1: + break + if at > 0: + yield nodeid[:at] + pos = at + len(SEP) + # Eagerly consume :: parts. + while True: + at = nodeid.find("::", pos) + if at == -1: + break + if at > 0: + yield nodeid[:at] + pos = at + len("::") + # The node ID itself. + if nodeid: + yield nodeid + + +def _check_path(path: Path, fspath: LEGACY_PATH) -> None: + if Path(fspath) != path: + raise ValueError( + f"Path({fspath!r}) != {path!r}\n" + "if both path and fspath are given they need to be equal" + ) + + +def _imply_path( + node_type: Type["Node"], + path: Optional[Path], + fspath: Optional[LEGACY_PATH], +) -> Path: + if fspath is not None: + warnings.warn( + NODE_CTOR_FSPATH_ARG.format( + node_type_name=node_type.__name__, + ), + stacklevel=6, + ) + if path is not None: + if fspath is not None: + _check_path(path, fspath) + return path + else: + assert fspath is not None + return Path(fspath) + + +_NodeType = TypeVar("_NodeType", bound="Node") + + +class NodeMeta(type): + def __call__(self, *k, **kw): + msg = ( + "Direct construction of {name} has been deprecated, please use {name}.from_parent.\n" + "See " + "https://docs.pytest.org/en/stable/deprecations.html#node-construction-changed-to-node-from-parent" + " for more details." + ).format(name=f"{self.__module__}.{self.__name__}") + fail(msg, pytrace=False) + + def _create(self, *k, **kw): + try: + return super().__call__(*k, **kw) + except TypeError: + sig = signature(getattr(self, "__init__")) + known_kw = {k: v for k, v in kw.items() if k in sig.parameters} + from .warning_types import PytestDeprecationWarning + + warnings.warn( + PytestDeprecationWarning( + f"{self} is not using a cooperative constructor and only takes {set(known_kw)}.\n" + "See https://docs.pytest.org/en/stable/deprecations.html" + "#constructors-of-custom-pytest-node-subclasses-should-take-kwargs " + "for more details." + ) + ) + + return super().__call__(*k, **known_kw) + + +class Node(metaclass=NodeMeta): + r"""Base class of :class:`Collector` and :class:`Item`, the components of + the test collection tree. + + ``Collector``\'s are the internal nodes of the tree, and ``Item``\'s are the + leaf nodes. + """ + + # Implemented in the legacypath plugin. + #: A ``LEGACY_PATH`` copy of the :attr:`path` attribute. Intended for usage + #: for methods not migrated to ``pathlib.Path`` yet, such as + #: :meth:`Item.reportinfo`. Will be deprecated in a future release, prefer + #: using :attr:`path` instead. + fspath: LEGACY_PATH + + # Use __slots__ to make attribute access faster. + # Note that __dict__ is still available. + __slots__ = ( + "name", + "parent", + "config", + "session", + "path", + "_nodeid", + "_store", + "__dict__", + ) + + def __init__( + self, + name: str, + parent: "Optional[Node]" = None, + config: Optional[Config] = None, + session: "Optional[Session]" = None, + fspath: Optional[LEGACY_PATH] = None, + path: Optional[Path] = None, + nodeid: Optional[str] = None, + ) -> None: + #: A unique name within the scope of the parent node. + self.name: str = name + + #: The parent collector node. + self.parent = parent + + if config: + #: The pytest config object. + self.config: Config = config + else: + if not parent: + raise TypeError("config or parent must be provided") + self.config = parent.config + + if session: + #: The pytest session this node is part of. + self.session: Session = session + else: + if not parent: + raise TypeError("session or parent must be provided") + self.session = parent.session + + if path is None and fspath is None: + path = getattr(parent, "path", None) + #: Filesystem path where this node was collected from (can be None). + self.path: Path = _imply_path(type(self), path, fspath=fspath) + + # The explicit annotation is to avoid publicly exposing NodeKeywords. + #: Keywords/markers collected from all scopes. + self.keywords: MutableMapping[str, Any] = NodeKeywords(self) + + #: The marker objects belonging to this node. + self.own_markers: List[Mark] = [] + + #: Allow adding of extra keywords to use for matching. + self.extra_keyword_matches: Set[str] = set() + + if nodeid is not None: + assert "::()" not in nodeid + self._nodeid = nodeid + else: + if not self.parent: + raise TypeError("nodeid or parent must be provided") + self._nodeid = self.parent.nodeid + "::" + self.name + + #: A place where plugins can store information on the node for their + #: own use. + self.stash: Stash = Stash() + # Deprecated alias. Was never public. Can be removed in a few releases. + self._store = self.stash + + @classmethod + def from_parent(cls, parent: "Node", **kw): + """Public constructor for Nodes. + + This indirection got introduced in order to enable removing + the fragile logic from the node constructors. + + Subclasses can use ``super().from_parent(...)`` when overriding the + construction. + + :param parent: The parent node of this Node. + """ + if "config" in kw: + raise TypeError("config is not a valid argument for from_parent") + if "session" in kw: + raise TypeError("session is not a valid argument for from_parent") + return cls._create(parent=parent, **kw) + + @property + def ihook(self): + """fspath-sensitive hook proxy used to call pytest hooks.""" + return self.session.gethookproxy(self.path) + + def __repr__(self) -> str: + return "<{} {}>".format(self.__class__.__name__, getattr(self, "name", None)) + + def warn(self, warning: Warning) -> None: + """Issue a warning for this Node. + + Warnings will be displayed after the test session, unless explicitly suppressed. + + :param Warning warning: + The warning instance to issue. + + :raises ValueError: If ``warning`` instance is not a subclass of Warning. + + Example usage: + + .. code-block:: python + + node.warn(PytestWarning("some message")) + node.warn(UserWarning("some message")) + + .. versionchanged:: 6.2 + Any subclass of :class:`Warning` is now accepted, rather than only + :class:`PytestWarning ` subclasses. + """ + # enforce type checks here to avoid getting a generic type error later otherwise. + if not isinstance(warning, Warning): + raise ValueError( + "warning must be an instance of Warning or subclass, got {!r}".format( + warning + ) + ) + path, lineno = get_fslocation_from_item(self) + assert lineno is not None + warnings.warn_explicit( + warning, + category=None, + filename=str(path), + lineno=lineno + 1, + ) + + # Methods for ordering nodes. + + @property + def nodeid(self) -> str: + """A ::-separated string denoting its collection tree address.""" + return self._nodeid + + def __hash__(self) -> int: + return hash(self._nodeid) + + def setup(self) -> None: + pass + + def teardown(self) -> None: + pass + + def listchain(self) -> List["Node"]: + """Return list of all parent collectors up to self, starting from + the root of collection tree. + + :returns: The nodes. + """ + chain = [] + item: Optional[Node] = self + while item is not None: + chain.append(item) + item = item.parent + chain.reverse() + return chain + + def add_marker( + self, marker: Union[str, MarkDecorator], append: bool = True + ) -> None: + """Dynamically add a marker object to the node. + + :param marker: + The marker. + :param append: + Whether to append the marker, or prepend it. + """ + from _pytest.mark import MARK_GEN + + if isinstance(marker, MarkDecorator): + marker_ = marker + elif isinstance(marker, str): + marker_ = getattr(MARK_GEN, marker) + else: + raise ValueError("is not a string or pytest.mark.* Marker") + self.keywords[marker_.name] = marker_ + if append: + self.own_markers.append(marker_.mark) + else: + self.own_markers.insert(0, marker_.mark) + + def iter_markers(self, name: Optional[str] = None) -> Iterator[Mark]: + """Iterate over all markers of the node. + + :param name: If given, filter the results by the name attribute. + :returns: An iterator of the markers of the node. + """ + return (x[1] for x in self.iter_markers_with_node(name=name)) + + def iter_markers_with_node( + self, name: Optional[str] = None + ) -> Iterator[Tuple["Node", Mark]]: + """Iterate over all markers of the node. + + :param name: If given, filter the results by the name attribute. + :returns: An iterator of (node, mark) tuples. + """ + for node in reversed(self.listchain()): + for mark in node.own_markers: + if name is None or getattr(mark, "name", None) == name: + yield node, mark + + @overload + def get_closest_marker(self, name: str) -> Optional[Mark]: + ... + + @overload + def get_closest_marker(self, name: str, default: Mark) -> Mark: + ... + + def get_closest_marker( + self, name: str, default: Optional[Mark] = None + ) -> Optional[Mark]: + """Return the first marker matching the name, from closest (for + example function) to farther level (for example module level). + + :param default: Fallback return value if no marker was found. + :param name: Name to filter by. + """ + return next(self.iter_markers(name=name), default) + + def listextrakeywords(self) -> Set[str]: + """Return a set of all extra keywords in self and any parents.""" + extra_keywords: Set[str] = set() + for item in self.listchain(): + extra_keywords.update(item.extra_keyword_matches) + return extra_keywords + + def listnames(self) -> List[str]: + return [x.name for x in self.listchain()] + + def addfinalizer(self, fin: Callable[[], object]) -> None: + """Register a function to be called without arguments when this node is + finalized. + + This method can only be called when this node is active + in a setup chain, for example during self.setup(). + """ + self.session._setupstate.addfinalizer(fin, self) + + def getparent(self, cls: Type[_NodeType]) -> Optional[_NodeType]: + """Get the next parent node (including self) which is an instance of + the given class. + + :param cls: The node class to search for. + :returns: The node, if found. + """ + current: Optional[Node] = self + while current and not isinstance(current, cls): + current = current.parent + assert current is None or isinstance(current, cls) + return current + + def _traceback_filter(self, excinfo: ExceptionInfo[BaseException]) -> Traceback: + return excinfo.traceback + + def _repr_failure_py( + self, + excinfo: ExceptionInfo[BaseException], + style: "Optional[_TracebackStyle]" = None, + ) -> TerminalRepr: + from _pytest.fixtures import FixtureLookupError + + if isinstance(excinfo.value, ConftestImportFailure): + excinfo = ExceptionInfo.from_exc_info(excinfo.value.excinfo) + if isinstance(excinfo.value, fail.Exception): + if not excinfo.value.pytrace: + style = "value" + if isinstance(excinfo.value, FixtureLookupError): + return excinfo.value.formatrepr() + + tbfilter: Union[bool, Callable[[ExceptionInfo[BaseException]], Traceback]] + if self.config.getoption("fulltrace", False): + style = "long" + tbfilter = False + else: + tbfilter = self._traceback_filter + if style == "auto": + style = "long" + # XXX should excinfo.getrepr record all data and toterminal() process it? + if style is None: + if self.config.getoption("tbstyle", "auto") == "short": + style = "short" + else: + style = "long" + + if self.config.getoption("verbose", 0) > 1: + truncate_locals = False + else: + truncate_locals = True + + # excinfo.getrepr() formats paths relative to the CWD if `abspath` is False. + # It is possible for a fixture/test to change the CWD while this code runs, which + # would then result in the user seeing confusing paths in the failure message. + # To fix this, if the CWD changed, always display the full absolute path. + # It will be better to just always display paths relative to invocation_dir, but + # this requires a lot of plumbing (#6428). + try: + abspath = Path(os.getcwd()) != self.config.invocation_params.dir + except OSError: + abspath = True + + return excinfo.getrepr( + funcargs=True, + abspath=abspath, + showlocals=self.config.getoption("showlocals", False), + style=style, + tbfilter=tbfilter, + truncate_locals=truncate_locals, + ) + + def repr_failure( + self, + excinfo: ExceptionInfo[BaseException], + style: "Optional[_TracebackStyle]" = None, + ) -> Union[str, TerminalRepr]: + """Return a representation of a collection or test failure. + + .. seealso:: :ref:`non-python tests` + + :param excinfo: Exception information for the failure. + """ + return self._repr_failure_py(excinfo, style) + + +def get_fslocation_from_item(node: "Node") -> Tuple[Union[str, Path], Optional[int]]: + """Try to extract the actual location from a node, depending on available attributes: + + * "location": a pair (path, lineno) + * "obj": a Python object that the node wraps. + * "fspath": just a path + + :rtype: A tuple of (str|Path, int) with filename and 0-based line number. + """ + # See Item.location. + location: Optional[Tuple[str, Optional[int], str]] = getattr(node, "location", None) + if location is not None: + return location[:2] + obj = getattr(node, "obj", None) + if obj is not None: + return getfslineno(obj) + return getattr(node, "fspath", "unknown location"), -1 + + +class Collector(Node): + """Base class of all collectors. + + Collector create children through `collect()` and thus iteratively build + the collection tree. + """ + + class CollectError(Exception): + """An error during collection, contains a custom message.""" + + def collect(self) -> Iterable[Union["Item", "Collector"]]: + """Collect children (items and collectors) for this collector.""" + raise NotImplementedError("abstract") + + # TODO: This omits the style= parameter which breaks Liskov Substitution. + def repr_failure( # type: ignore[override] + self, excinfo: ExceptionInfo[BaseException] + ) -> Union[str, TerminalRepr]: + """Return a representation of a collection failure. + + :param excinfo: Exception information for the failure. + """ + if isinstance(excinfo.value, self.CollectError) and not self.config.getoption( + "fulltrace", False + ): + exc = excinfo.value + return str(exc.args[0]) + + # Respect explicit tbstyle option, but default to "short" + # (_repr_failure_py uses "long" with "fulltrace" option always). + tbstyle = self.config.getoption("tbstyle", "auto") + if tbstyle == "auto": + tbstyle = "short" + + return self._repr_failure_py(excinfo, style=tbstyle) + + def _traceback_filter(self, excinfo: ExceptionInfo[BaseException]) -> Traceback: + if hasattr(self, "path"): + traceback = excinfo.traceback + ntraceback = traceback.cut(path=self.path) + if ntraceback == traceback: + ntraceback = ntraceback.cut(excludepath=tracebackcutdir) + return excinfo.traceback.filter(excinfo) + return excinfo.traceback + + +def _check_initialpaths_for_relpath(session: "Session", path: Path) -> Optional[str]: + for initial_path in session._initialpaths: + if commonpath(path, initial_path) == initial_path: + rel = str(path.relative_to(initial_path)) + return "" if rel == "." else rel + return None + + +class FSCollector(Collector): + """Base class for filesystem collectors.""" + + def __init__( + self, + fspath: Optional[LEGACY_PATH] = None, + path_or_parent: Optional[Union[Path, Node]] = None, + path: Optional[Path] = None, + name: Optional[str] = None, + parent: Optional[Node] = None, + config: Optional[Config] = None, + session: Optional["Session"] = None, + nodeid: Optional[str] = None, + ) -> None: + if path_or_parent: + if isinstance(path_or_parent, Node): + assert parent is None + parent = cast(FSCollector, path_or_parent) + elif isinstance(path_or_parent, Path): + assert path is None + path = path_or_parent + + path = _imply_path(type(self), path, fspath=fspath) + if name is None: + name = path.name + if parent is not None and parent.path != path: + try: + rel = path.relative_to(parent.path) + except ValueError: + pass + else: + name = str(rel) + name = name.replace(os.sep, SEP) + self.path = path + + if session is None: + assert parent is not None + session = parent.session + + if nodeid is None: + try: + nodeid = str(self.path.relative_to(session.config.rootpath)) + except ValueError: + nodeid = _check_initialpaths_for_relpath(session, path) + + if nodeid and os.sep != SEP: + nodeid = nodeid.replace(os.sep, SEP) + + super().__init__( + name=name, + parent=parent, + config=config, + session=session, + nodeid=nodeid, + path=path, + ) + + @classmethod + def from_parent( + cls, + parent, + *, + fspath: Optional[LEGACY_PATH] = None, + path: Optional[Path] = None, + **kw, + ): + """The public constructor.""" + return super().from_parent(parent=parent, fspath=fspath, path=path, **kw) + + def gethookproxy(self, fspath: "os.PathLike[str]"): + warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2) + return self.session.gethookproxy(fspath) + + def isinitpath(self, path: Union[str, "os.PathLike[str]"]) -> bool: + warnings.warn(FSCOLLECTOR_GETHOOKPROXY_ISINITPATH, stacklevel=2) + return self.session.isinitpath(path) + + +class File(FSCollector): + """Base class for collecting tests from a file. + + :ref:`non-python tests`. + """ + + +class Item(Node): + """Base class of all test invocation items. + + Note that for a single function there might be multiple test invocation items. + """ + + nextitem = None + + def __init__( + self, + name, + parent=None, + config: Optional[Config] = None, + session: Optional["Session"] = None, + nodeid: Optional[str] = None, + **kw, + ) -> None: + # The first two arguments are intentionally passed positionally, + # to keep plugins who define a node type which inherits from + # (pytest.Item, pytest.File) working (see issue #8435). + # They can be made kwargs when the deprecation above is done. + super().__init__( + name, + parent, + config=config, + session=session, + nodeid=nodeid, + **kw, + ) + self._report_sections: List[Tuple[str, str, str]] = [] + + #: A list of tuples (name, value) that holds user defined properties + #: for this test. + self.user_properties: List[Tuple[str, object]] = [] + + self._check_item_and_collector_diamond_inheritance() + + def _check_item_and_collector_diamond_inheritance(self) -> None: + """ + Check if the current type inherits from both File and Collector + at the same time, emitting a warning accordingly (#8447). + """ + cls = type(self) + + # We inject an attribute in the type to avoid issuing this warning + # for the same class more than once, which is not helpful. + # It is a hack, but was deemed acceptable in order to avoid + # flooding the user in the common case. + attr_name = "_pytest_diamond_inheritance_warning_shown" + if getattr(cls, attr_name, False): + return + setattr(cls, attr_name, True) + + problems = ", ".join( + base.__name__ for base in cls.__bases__ if issubclass(base, Collector) + ) + if problems: + warnings.warn( + f"{cls.__name__} is an Item subclass and should not be a collector, " + f"however its bases {problems} are collectors.\n" + "Please split the Collectors and the Item into separate node types.\n" + "Pytest Doc example: https://docs.pytest.org/en/latest/example/nonpython.html\n" + "example pull request on a plugin: https://github.com/asmeurer/pytest-flakes/pull/40/", + PytestWarning, + ) + + def runtest(self) -> None: + """Run the test case for this item. + + Must be implemented by subclasses. + + .. seealso:: :ref:`non-python tests` + """ + raise NotImplementedError("runtest must be implemented by Item subclass") + + def add_report_section(self, when: str, key: str, content: str) -> None: + """Add a new report section, similar to what's done internally to add + stdout and stderr captured output:: + + item.add_report_section("call", "stdout", "report section contents") + + :param str when: + One of the possible capture states, ``"setup"``, ``"call"``, ``"teardown"``. + :param str key: + Name of the section, can be customized at will. Pytest uses ``"stdout"`` and + ``"stderr"`` internally. + :param str content: + The full contents as a string. + """ + if content: + self._report_sections.append((when, key, content)) + + def reportinfo(self) -> Tuple[Union["os.PathLike[str]", str], Optional[int], str]: + """Get location information for this item for test reports. + + Returns a tuple with three elements: + + - The path of the test (default ``self.path``) + - The 0-based line number of the test (default ``None``) + - A name of the test to be shown (default ``""``) + + .. seealso:: :ref:`non-python tests` + """ + return self.path, None, "" + + @cached_property + def location(self) -> Tuple[str, Optional[int], str]: + """ + Returns a tuple of ``(relfspath, lineno, testname)`` for this item + where ``relfspath`` is file path relative to ``config.rootpath`` + and lineno is a 0-based line number. + """ + location = self.reportinfo() + path = absolutepath(os.fspath(location[0])) + relfspath = self.session._node_location_to_relpath(path) + assert type(location[2]) is str + return (relfspath, location[1], location[2]) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/nose.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/nose.py new file mode 100644 index 000000000..273bd045f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/nose.py @@ -0,0 +1,50 @@ +"""Run testsuites written for nose.""" +import warnings + +from _pytest.config import hookimpl +from _pytest.deprecated import NOSE_SUPPORT +from _pytest.fixtures import getfixturemarker +from _pytest.nodes import Item +from _pytest.python import Function +from _pytest.unittest import TestCaseFunction + + +@hookimpl(trylast=True) +def pytest_runtest_setup(item: Item) -> None: + if not isinstance(item, Function): + return + # Don't do nose style setup/teardown on direct unittest style classes. + if isinstance(item, TestCaseFunction): + return + + # Capture the narrowed type of item for the teardown closure, + # see https://github.com/python/mypy/issues/2608 + func = item + + call_optional(func.obj, "setup", func.nodeid) + func.addfinalizer(lambda: call_optional(func.obj, "teardown", func.nodeid)) + + # NOTE: Module- and class-level fixtures are handled in python.py + # with `pluginmanager.has_plugin("nose")` checks. + # It would have been nicer to implement them outside of core, but + # it's not straightforward. + + +def call_optional(obj: object, name: str, nodeid: str) -> bool: + method = getattr(obj, name, None) + if method is None: + return False + is_fixture = getfixturemarker(method) is not None + if is_fixture: + return False + if not callable(method): + return False + # Warn about deprecation of this plugin. + method_name = getattr(method, "__name__", str(method)) + warnings.warn( + NOSE_SUPPORT.format(nodeid=nodeid, method=method_name, stage=name), stacklevel=2 + ) + # If there are any problems allow the exception to raise rather than + # silently ignoring it. + method() + return True diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/outcomes.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/outcomes.py new file mode 100644 index 000000000..1be97dda4 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/outcomes.py @@ -0,0 +1,311 @@ +"""Exception classes and constants handling test outcomes as well as +functions creating them.""" +import sys +import warnings +from typing import Any +from typing import Callable +from typing import cast +from typing import NoReturn +from typing import Optional +from typing import Type +from typing import TypeVar + +from _pytest.deprecated import KEYWORD_MSG_ARG + +TYPE_CHECKING = False # Avoid circular import through compat. + +if TYPE_CHECKING: + from typing_extensions import Protocol +else: + # typing.Protocol is only available starting from Python 3.8. It is also + # available from typing_extensions, but we don't want a runtime dependency + # on that. So use a dummy runtime implementation. + from typing import Generic + + Protocol = Generic + + +class OutcomeException(BaseException): + """OutcomeException and its subclass instances indicate and contain info + about test and collection outcomes.""" + + def __init__(self, msg: Optional[str] = None, pytrace: bool = True) -> None: + if msg is not None and not isinstance(msg, str): + error_msg = ( # type: ignore[unreachable] + "{} expected string as 'msg' parameter, got '{}' instead.\n" + "Perhaps you meant to use a mark?" + ) + raise TypeError(error_msg.format(type(self).__name__, type(msg).__name__)) + super().__init__(msg) + self.msg = msg + self.pytrace = pytrace + + def __repr__(self) -> str: + if self.msg is not None: + return self.msg + return f"<{self.__class__.__name__} instance>" + + __str__ = __repr__ + + +TEST_OUTCOME = (OutcomeException, Exception) + + +class Skipped(OutcomeException): + # XXX hackish: on 3k we fake to live in the builtins + # in order to have Skipped exception printing shorter/nicer + __module__ = "builtins" + + def __init__( + self, + msg: Optional[str] = None, + pytrace: bool = True, + allow_module_level: bool = False, + *, + _use_item_location: bool = False, + ) -> None: + super().__init__(msg=msg, pytrace=pytrace) + self.allow_module_level = allow_module_level + # If true, the skip location is reported as the item's location, + # instead of the place that raises the exception/calls skip(). + self._use_item_location = _use_item_location + + +class Failed(OutcomeException): + """Raised from an explicit call to pytest.fail().""" + + __module__ = "builtins" + + +class Exit(Exception): + """Raised for immediate program exits (no tracebacks/summaries).""" + + def __init__( + self, msg: str = "unknown reason", returncode: Optional[int] = None + ) -> None: + self.msg = msg + self.returncode = returncode + super().__init__(msg) + + +# Elaborate hack to work around https://github.com/python/mypy/issues/2087. +# Ideally would just be `exit.Exception = Exit` etc. + +_F = TypeVar("_F", bound=Callable[..., object]) +_ET = TypeVar("_ET", bound=Type[BaseException]) + + +class _WithException(Protocol[_F, _ET]): + Exception: _ET + __call__: _F + + +def _with_exception(exception_type: _ET) -> Callable[[_F], _WithException[_F, _ET]]: + def decorate(func: _F) -> _WithException[_F, _ET]: + func_with_exception = cast(_WithException[_F, _ET], func) + func_with_exception.Exception = exception_type + return func_with_exception + + return decorate + + +# Exposed helper methods. + + +@_with_exception(Exit) +def exit( + reason: str = "", returncode: Optional[int] = None, *, msg: Optional[str] = None +) -> NoReturn: + """Exit testing process. + + :param reason: + The message to show as the reason for exiting pytest. reason has a default value + only because `msg` is deprecated. + + :param returncode: + Return code to be used when exiting pytest. + + :param msg: + Same as ``reason``, but deprecated. Will be removed in a future version, use ``reason`` instead. + """ + __tracebackhide__ = True + from _pytest.config import UsageError + + if reason and msg: + raise UsageError( + "cannot pass reason and msg to exit(), `msg` is deprecated, use `reason`." + ) + if not reason: + if msg is None: + raise UsageError("exit() requires a reason argument") + warnings.warn(KEYWORD_MSG_ARG.format(func="exit"), stacklevel=2) + reason = msg + raise Exit(reason, returncode) + + +@_with_exception(Skipped) +def skip( + reason: str = "", *, allow_module_level: bool = False, msg: Optional[str] = None +) -> NoReturn: + """Skip an executing test with the given message. + + This function should be called only during testing (setup, call or teardown) or + during collection by using the ``allow_module_level`` flag. This function can + be called in doctests as well. + + :param reason: + The message to show the user as reason for the skip. + + :param allow_module_level: + Allows this function to be called at module level. + Raising the skip exception at module level will stop + the execution of the module and prevent the collection of all tests in the module, + even those defined before the `skip` call. + + Defaults to False. + + :param msg: + Same as ``reason``, but deprecated. Will be removed in a future version, use ``reason`` instead. + + .. note:: + It is better to use the :ref:`pytest.mark.skipif ref` marker when + possible to declare a test to be skipped under certain conditions + like mismatching platforms or dependencies. + Similarly, use the ``# doctest: +SKIP`` directive (see :py:data:`doctest.SKIP`) + to skip a doctest statically. + """ + __tracebackhide__ = True + reason = _resolve_msg_to_reason("skip", reason, msg) + raise Skipped(msg=reason, allow_module_level=allow_module_level) + + +@_with_exception(Failed) +def fail(reason: str = "", pytrace: bool = True, msg: Optional[str] = None) -> NoReturn: + """Explicitly fail an executing test with the given message. + + :param reason: + The message to show the user as reason for the failure. + + :param pytrace: + If False, msg represents the full failure information and no + python traceback will be reported. + + :param msg: + Same as ``reason``, but deprecated. Will be removed in a future version, use ``reason`` instead. + """ + __tracebackhide__ = True + reason = _resolve_msg_to_reason("fail", reason, msg) + raise Failed(msg=reason, pytrace=pytrace) + + +def _resolve_msg_to_reason( + func_name: str, reason: str, msg: Optional[str] = None +) -> str: + """ + Handles converting the deprecated msg parameter if provided into + reason, raising a deprecation warning. This function will be removed + when the optional msg argument is removed from here in future. + + :param str func_name: + The name of the offending function, this is formatted into the deprecation message. + + :param str reason: + The reason= passed into either pytest.fail() or pytest.skip() + + :param str msg: + The msg= passed into either pytest.fail() or pytest.skip(). This will + be converted into reason if it is provided to allow pytest.skip(msg=) or + pytest.fail(msg=) to continue working in the interim period. + + :returns: + The value to use as reason. + + """ + __tracebackhide__ = True + if msg is not None: + if reason: + from pytest import UsageError + + raise UsageError( + f"Passing both ``reason`` and ``msg`` to pytest.{func_name}(...) is not permitted." + ) + warnings.warn(KEYWORD_MSG_ARG.format(func=func_name), stacklevel=3) + reason = msg + return reason + + +class XFailed(Failed): + """Raised from an explicit call to pytest.xfail().""" + + +@_with_exception(XFailed) +def xfail(reason: str = "") -> NoReturn: + """Imperatively xfail an executing test or setup function with the given reason. + + This function should be called only during testing (setup, call or teardown). + + :param reason: + The message to show the user as reason for the xfail. + + .. note:: + It is better to use the :ref:`pytest.mark.xfail ref` marker when + possible to declare a test to be xfailed under certain conditions + like known bugs or missing features. + """ + __tracebackhide__ = True + raise XFailed(reason) + + +def importorskip( + modname: str, minversion: Optional[str] = None, reason: Optional[str] = None +) -> Any: + """Import and return the requested module ``modname``, or skip the + current test if the module cannot be imported. + + :param modname: + The name of the module to import. + :param minversion: + If given, the imported module's ``__version__`` attribute must be at + least this minimal version, otherwise the test is still skipped. + :param reason: + If given, this reason is shown as the message when the module cannot + be imported. + + :returns: + The imported module. This should be assigned to its canonical name. + + Example:: + + docutils = pytest.importorskip("docutils") + """ + import warnings + + __tracebackhide__ = True + compile(modname, "", "eval") # to catch syntaxerrors + + with warnings.catch_warnings(): + # Make sure to ignore ImportWarnings that might happen because + # of existing directories with the same name we're trying to + # import but without a __init__.py file. + warnings.simplefilter("ignore") + try: + __import__(modname) + except ImportError as exc: + if reason is None: + reason = f"could not import {modname!r}: {exc}" + raise Skipped(reason, allow_module_level=True) from None + mod = sys.modules[modname] + if minversion is None: + return mod + verattr = getattr(mod, "__version__", None) + if minversion is not None: + # Imported lazily to improve start-up time. + from packaging.version import Version + + if verattr is None or Version(verattr) < Version(minversion): + raise Skipped( + "module %r has __version__ %r, required is: %r" + % (modname, verattr, minversion), + allow_module_level=True, + ) + return mod diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/pastebin.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/pastebin.py new file mode 100644 index 000000000..22c7a6223 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/pastebin.py @@ -0,0 +1,110 @@ +"""Submit failure or test session information to a pastebin service.""" +import tempfile +from io import StringIO +from typing import IO +from typing import Union + +import pytest +from _pytest.config import Config +from _pytest.config import create_terminal_writer +from _pytest.config.argparsing import Parser +from _pytest.stash import StashKey +from _pytest.terminal import TerminalReporter + + +pastebinfile_key = StashKey[IO[bytes]]() + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("terminal reporting") + group._addoption( + "--pastebin", + metavar="mode", + action="store", + dest="pastebin", + default=None, + choices=["failed", "all"], + help="Send failed|all info to bpaste.net pastebin service", + ) + + +@pytest.hookimpl(trylast=True) +def pytest_configure(config: Config) -> None: + if config.option.pastebin == "all": + tr = config.pluginmanager.getplugin("terminalreporter") + # If no terminal reporter plugin is present, nothing we can do here; + # this can happen when this function executes in a worker node + # when using pytest-xdist, for example. + if tr is not None: + # pastebin file will be UTF-8 encoded binary file. + config.stash[pastebinfile_key] = tempfile.TemporaryFile("w+b") + oldwrite = tr._tw.write + + def tee_write(s, **kwargs): + oldwrite(s, **kwargs) + if isinstance(s, str): + s = s.encode("utf-8") + config.stash[pastebinfile_key].write(s) + + tr._tw.write = tee_write + + +def pytest_unconfigure(config: Config) -> None: + if pastebinfile_key in config.stash: + pastebinfile = config.stash[pastebinfile_key] + # Get terminal contents and delete file. + pastebinfile.seek(0) + sessionlog = pastebinfile.read() + pastebinfile.close() + del config.stash[pastebinfile_key] + # Undo our patching in the terminal reporter. + tr = config.pluginmanager.getplugin("terminalreporter") + del tr._tw.__dict__["write"] + # Write summary. + tr.write_sep("=", "Sending information to Paste Service") + pastebinurl = create_new_paste(sessionlog) + tr.write_line("pastebin session-log: %s\n" % pastebinurl) + + +def create_new_paste(contents: Union[str, bytes]) -> str: + """Create a new paste using the bpaste.net service. + + :contents: Paste contents string. + :returns: URL to the pasted contents, or an error message. + """ + import re + from urllib.request import urlopen + from urllib.parse import urlencode + + params = {"code": contents, "lexer": "text", "expiry": "1week"} + url = "https://bpa.st" + try: + response: str = ( + urlopen(url, data=urlencode(params).encode("ascii")).read().decode("utf-8") + ) + except OSError as exc_info: # urllib errors + return "bad response: %s" % exc_info + m = re.search(r'href="/raw/(\w+)"', response) + if m: + return f"{url}/show/{m.group(1)}" + else: + return "bad response: invalid format ('" + response + "')" + + +def pytest_terminal_summary(terminalreporter: TerminalReporter) -> None: + if terminalreporter.config.option.pastebin != "failed": + return + if "failed" in terminalreporter.stats: + terminalreporter.write_sep("=", "Sending information to Paste Service") + for rep in terminalreporter.stats["failed"]: + try: + msg = rep.longrepr.reprtraceback.reprentries[-1].reprfileloc + except AttributeError: + msg = terminalreporter._getfailureheadline(rep) + file = StringIO() + tw = create_terminal_writer(terminalreporter.config, file) + rep.toterminal(tw) + s = file.getvalue() + assert len(s) + pastebinurl = create_new_paste(s) + terminalreporter.write_line(f"{msg} --> {pastebinurl}") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/pathlib.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/pathlib.py new file mode 100644 index 000000000..c2f8535f5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/pathlib.py @@ -0,0 +1,804 @@ +import atexit +import contextlib +import fnmatch +import importlib.util +import itertools +import os +import shutil +import sys +import types +import uuid +import warnings +from enum import Enum +from errno import EBADF +from errno import ELOOP +from errno import ENOENT +from errno import ENOTDIR +from functools import partial +from os.path import expanduser +from os.path import expandvars +from os.path import isabs +from os.path import sep +from pathlib import Path +from pathlib import PurePath +from posixpath import sep as posix_sep +from types import ModuleType +from typing import Callable +from typing import Dict +from typing import Iterable +from typing import Iterator +from typing import List +from typing import Optional +from typing import Set +from typing import Tuple +from typing import Type +from typing import TypeVar +from typing import Union + +from _pytest.compat import assert_never +from _pytest.outcomes import skip +from _pytest.warning_types import PytestWarning + +LOCK_TIMEOUT = 60 * 60 * 24 * 3 + + +_AnyPurePath = TypeVar("_AnyPurePath", bound=PurePath) + +# The following function, variables and comments were +# copied from cpython 3.9 Lib/pathlib.py file. + +# EBADF - guard against macOS `stat` throwing EBADF +_IGNORED_ERRORS = (ENOENT, ENOTDIR, EBADF, ELOOP) + +_IGNORED_WINERRORS = ( + 21, # ERROR_NOT_READY - drive exists but is not accessible + 1921, # ERROR_CANT_RESOLVE_FILENAME - fix for broken symlink pointing to itself +) + + +def _ignore_error(exception): + return ( + getattr(exception, "errno", None) in _IGNORED_ERRORS + or getattr(exception, "winerror", None) in _IGNORED_WINERRORS + ) + + +def get_lock_path(path: _AnyPurePath) -> _AnyPurePath: + return path.joinpath(".lock") + + +def on_rm_rf_error( + func, + path: str, + excinfo: Union[ + BaseException, + Tuple[Type[BaseException], BaseException, Optional[types.TracebackType]], + ], + *, + start_path: Path, +) -> bool: + """Handle known read-only errors during rmtree. + + The returned value is used only by our own tests. + """ + if isinstance(excinfo, BaseException): + exc = excinfo + else: + exc = excinfo[1] + + # Another process removed the file in the middle of the "rm_rf" (xdist for example). + # More context: https://github.com/pytest-dev/pytest/issues/5974#issuecomment-543799018 + if isinstance(exc, FileNotFoundError): + return False + + if not isinstance(exc, PermissionError): + warnings.warn( + PytestWarning(f"(rm_rf) error removing {path}\n{type(exc)}: {exc}") + ) + return False + + if func not in (os.rmdir, os.remove, os.unlink): + if func not in (os.open,): + warnings.warn( + PytestWarning( + "(rm_rf) unknown function {} when removing {}:\n{}: {}".format( + func, path, type(exc), exc + ) + ) + ) + return False + + # Chmod + retry. + import stat + + def chmod_rw(p: str) -> None: + mode = os.stat(p).st_mode + os.chmod(p, mode | stat.S_IRUSR | stat.S_IWUSR) + + # For files, we need to recursively go upwards in the directories to + # ensure they all are also writable. + p = Path(path) + if p.is_file(): + for parent in p.parents: + chmod_rw(str(parent)) + # Stop when we reach the original path passed to rm_rf. + if parent == start_path: + break + chmod_rw(str(path)) + + func(path) + return True + + +def ensure_extended_length_path(path: Path) -> Path: + """Get the extended-length version of a path (Windows). + + On Windows, by default, the maximum length of a path (MAX_PATH) is 260 + characters, and operations on paths longer than that fail. But it is possible + to overcome this by converting the path to "extended-length" form before + performing the operation: + https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#maximum-path-length-limitation + + On Windows, this function returns the extended-length absolute version of path. + On other platforms it returns path unchanged. + """ + if sys.platform.startswith("win32"): + path = path.resolve() + path = Path(get_extended_length_path_str(str(path))) + return path + + +def get_extended_length_path_str(path: str) -> str: + """Convert a path to a Windows extended length path.""" + long_path_prefix = "\\\\?\\" + unc_long_path_prefix = "\\\\?\\UNC\\" + if path.startswith((long_path_prefix, unc_long_path_prefix)): + return path + # UNC + if path.startswith("\\\\"): + return unc_long_path_prefix + path[2:] + return long_path_prefix + path + + +def rm_rf(path: Path) -> None: + """Remove the path contents recursively, even if some elements + are read-only.""" + path = ensure_extended_length_path(path) + onerror = partial(on_rm_rf_error, start_path=path) + if sys.version_info >= (3, 12): + shutil.rmtree(str(path), onexc=onerror) + else: + shutil.rmtree(str(path), onerror=onerror) + + +def find_prefixed(root: Path, prefix: str) -> Iterator[Path]: + """Find all elements in root that begin with the prefix, case insensitive.""" + l_prefix = prefix.lower() + for x in root.iterdir(): + if x.name.lower().startswith(l_prefix): + yield x + + +def extract_suffixes(iter: Iterable[PurePath], prefix: str) -> Iterator[str]: + """Return the parts of the paths following the prefix. + + :param iter: Iterator over path names. + :param prefix: Expected prefix of the path names. + """ + p_len = len(prefix) + for p in iter: + yield p.name[p_len:] + + +def find_suffixes(root: Path, prefix: str) -> Iterator[str]: + """Combine find_prefixes and extract_suffixes.""" + return extract_suffixes(find_prefixed(root, prefix), prefix) + + +def parse_num(maybe_num) -> int: + """Parse number path suffixes, returns -1 on error.""" + try: + return int(maybe_num) + except ValueError: + return -1 + + +def _force_symlink( + root: Path, target: Union[str, PurePath], link_to: Union[str, Path] +) -> None: + """Helper to create the current symlink. + + It's full of race conditions that are reasonably OK to ignore + for the context of best effort linking to the latest test run. + + The presumption being that in case of much parallelism + the inaccuracy is going to be acceptable. + """ + current_symlink = root.joinpath(target) + try: + current_symlink.unlink() + except OSError: + pass + try: + current_symlink.symlink_to(link_to) + except Exception: + pass + + +def make_numbered_dir(root: Path, prefix: str, mode: int = 0o700) -> Path: + """Create a directory with an increased number as suffix for the given prefix.""" + for i in range(10): + # try up to 10 times to create the folder + max_existing = max(map(parse_num, find_suffixes(root, prefix)), default=-1) + new_number = max_existing + 1 + new_path = root.joinpath(f"{prefix}{new_number}") + try: + new_path.mkdir(mode=mode) + except Exception: + pass + else: + _force_symlink(root, prefix + "current", new_path) + return new_path + else: + raise OSError( + "could not create numbered dir with prefix " + "{prefix} in {root} after 10 tries".format(prefix=prefix, root=root) + ) + + +def create_cleanup_lock(p: Path) -> Path: + """Create a lock to prevent premature folder cleanup.""" + lock_path = get_lock_path(p) + try: + fd = os.open(str(lock_path), os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644) + except FileExistsError as e: + raise OSError(f"cannot create lockfile in {p}") from e + else: + pid = os.getpid() + spid = str(pid).encode() + os.write(fd, spid) + os.close(fd) + if not lock_path.is_file(): + raise OSError("lock path got renamed after successful creation") + return lock_path + + +def register_cleanup_lock_removal(lock_path: Path, register=atexit.register): + """Register a cleanup function for removing a lock, by default on atexit.""" + pid = os.getpid() + + def cleanup_on_exit(lock_path: Path = lock_path, original_pid: int = pid) -> None: + current_pid = os.getpid() + if current_pid != original_pid: + # fork + return + try: + lock_path.unlink() + except OSError: + pass + + return register(cleanup_on_exit) + + +def maybe_delete_a_numbered_dir(path: Path) -> None: + """Remove a numbered directory if its lock can be obtained and it does + not seem to be in use.""" + path = ensure_extended_length_path(path) + lock_path = None + try: + lock_path = create_cleanup_lock(path) + parent = path.parent + + garbage = parent.joinpath(f"garbage-{uuid.uuid4()}") + path.rename(garbage) + rm_rf(garbage) + except OSError: + # known races: + # * other process did a cleanup at the same time + # * deletable folder was found + # * process cwd (Windows) + return + finally: + # If we created the lock, ensure we remove it even if we failed + # to properly remove the numbered dir. + if lock_path is not None: + try: + lock_path.unlink() + except OSError: + pass + + +def ensure_deletable(path: Path, consider_lock_dead_if_created_before: float) -> bool: + """Check if `path` is deletable based on whether the lock file is expired.""" + if path.is_symlink(): + return False + lock = get_lock_path(path) + try: + if not lock.is_file(): + return True + except OSError: + # we might not have access to the lock file at all, in this case assume + # we don't have access to the entire directory (#7491). + return False + try: + lock_time = lock.stat().st_mtime + except Exception: + return False + else: + if lock_time < consider_lock_dead_if_created_before: + # We want to ignore any errors while trying to remove the lock such as: + # - PermissionDenied, like the file permissions have changed since the lock creation; + # - FileNotFoundError, in case another pytest process got here first; + # and any other cause of failure. + with contextlib.suppress(OSError): + lock.unlink() + return True + return False + + +def try_cleanup(path: Path, consider_lock_dead_if_created_before: float) -> None: + """Try to cleanup a folder if we can ensure it's deletable.""" + if ensure_deletable(path, consider_lock_dead_if_created_before): + maybe_delete_a_numbered_dir(path) + + +def cleanup_candidates(root: Path, prefix: str, keep: int) -> Iterator[Path]: + """List candidates for numbered directories to be removed - follows py.path.""" + max_existing = max(map(parse_num, find_suffixes(root, prefix)), default=-1) + max_delete = max_existing - keep + paths = find_prefixed(root, prefix) + paths, paths2 = itertools.tee(paths) + numbers = map(parse_num, extract_suffixes(paths2, prefix)) + for path, number in zip(paths, numbers): + if number <= max_delete: + yield path + + +def cleanup_dead_symlinks(root: Path): + for left_dir in root.iterdir(): + if left_dir.is_symlink(): + if not left_dir.resolve().exists(): + left_dir.unlink() + + +def cleanup_numbered_dir( + root: Path, prefix: str, keep: int, consider_lock_dead_if_created_before: float +) -> None: + """Cleanup for lock driven numbered directories.""" + if not root.exists(): + return + for path in cleanup_candidates(root, prefix, keep): + try_cleanup(path, consider_lock_dead_if_created_before) + for path in root.glob("garbage-*"): + try_cleanup(path, consider_lock_dead_if_created_before) + + cleanup_dead_symlinks(root) + + +def make_numbered_dir_with_cleanup( + root: Path, + prefix: str, + keep: int, + lock_timeout: float, + mode: int, +) -> Path: + """Create a numbered dir with a cleanup lock and remove old ones.""" + e = None + for i in range(10): + try: + p = make_numbered_dir(root, prefix, mode) + # Only lock the current dir when keep is not 0 + if keep != 0: + lock_path = create_cleanup_lock(p) + register_cleanup_lock_removal(lock_path) + except Exception as exc: + e = exc + else: + consider_lock_dead_if_created_before = p.stat().st_mtime - lock_timeout + # Register a cleanup for program exit + atexit.register( + cleanup_numbered_dir, + root, + prefix, + keep, + consider_lock_dead_if_created_before, + ) + return p + assert e is not None + raise e + + +def resolve_from_str(input: str, rootpath: Path) -> Path: + input = expanduser(input) + input = expandvars(input) + if isabs(input): + return Path(input) + else: + return rootpath.joinpath(input) + + +def fnmatch_ex(pattern: str, path: Union[str, "os.PathLike[str]"]) -> bool: + """A port of FNMatcher from py.path.common which works with PurePath() instances. + + The difference between this algorithm and PurePath.match() is that the + latter matches "**" glob expressions for each part of the path, while + this algorithm uses the whole path instead. + + For example: + "tests/foo/bar/doc/test_foo.py" matches pattern "tests/**/doc/test*.py" + with this algorithm, but not with PurePath.match(). + + This algorithm was ported to keep backward-compatibility with existing + settings which assume paths match according this logic. + + References: + * https://bugs.python.org/issue29249 + * https://bugs.python.org/issue34731 + """ + path = PurePath(path) + iswin32 = sys.platform.startswith("win") + + if iswin32 and sep not in pattern and posix_sep in pattern: + # Running on Windows, the pattern has no Windows path separators, + # and the pattern has one or more Posix path separators. Replace + # the Posix path separators with the Windows path separator. + pattern = pattern.replace(posix_sep, sep) + + if sep not in pattern: + name = path.name + else: + name = str(path) + if path.is_absolute() and not os.path.isabs(pattern): + pattern = f"*{os.sep}{pattern}" + return fnmatch.fnmatch(name, pattern) + + +def parts(s: str) -> Set[str]: + parts = s.split(sep) + return {sep.join(parts[: i + 1]) or sep for i in range(len(parts))} + + +def symlink_or_skip(src, dst, **kwargs): + """Make a symlink, or skip the test in case symlinks are not supported.""" + try: + os.symlink(str(src), str(dst), **kwargs) + except OSError as e: + skip(f"symlinks not supported: {e}") + + +class ImportMode(Enum): + """Possible values for `mode` parameter of `import_path`.""" + + prepend = "prepend" + append = "append" + importlib = "importlib" + + +class ImportPathMismatchError(ImportError): + """Raised on import_path() if there is a mismatch of __file__'s. + + This can happen when `import_path` is called multiple times with different filenames that has + the same basename but reside in packages + (for example "/tests1/test_foo.py" and "/tests2/test_foo.py"). + """ + + +def import_path( + p: Union[str, "os.PathLike[str]"], + *, + mode: Union[str, ImportMode] = ImportMode.prepend, + root: Path, +) -> ModuleType: + """Import and return a module from the given path, which can be a file (a module) or + a directory (a package). + + The import mechanism used is controlled by the `mode` parameter: + + * `mode == ImportMode.prepend`: the directory containing the module (or package, taking + `__init__.py` files into account) will be put at the *start* of `sys.path` before + being imported with `importlib.import_module`. + + * `mode == ImportMode.append`: same as `prepend`, but the directory will be appended + to the end of `sys.path`, if not already in `sys.path`. + + * `mode == ImportMode.importlib`: uses more fine control mechanisms provided by `importlib` + to import the module, which avoids having to muck with `sys.path` at all. It effectively + allows having same-named test modules in different places. + + :param root: + Used as an anchor when mode == ImportMode.importlib to obtain + a unique name for the module being imported so it can safely be stored + into ``sys.modules``. + + :raises ImportPathMismatchError: + If after importing the given `path` and the module `__file__` + are different. Only raised in `prepend` and `append` modes. + """ + mode = ImportMode(mode) + + path = Path(p) + + if not path.exists(): + raise ImportError(path) + + if mode is ImportMode.importlib: + module_name = module_name_from_path(path, root) + with contextlib.suppress(KeyError): + return sys.modules[module_name] + + for meta_importer in sys.meta_path: + spec = meta_importer.find_spec(module_name, [str(path.parent)]) + if spec is not None: + break + else: + spec = importlib.util.spec_from_file_location(module_name, str(path)) + + if spec is None: + raise ImportError(f"Can't find module {module_name} at location {path}") + mod = importlib.util.module_from_spec(spec) + sys.modules[module_name] = mod + spec.loader.exec_module(mod) # type: ignore[union-attr] + insert_missing_modules(sys.modules, module_name) + return mod + + pkg_path = resolve_package_path(path) + if pkg_path is not None: + pkg_root = pkg_path.parent + names = list(path.with_suffix("").relative_to(pkg_root).parts) + if names[-1] == "__init__": + names.pop() + module_name = ".".join(names) + else: + pkg_root = path.parent + module_name = path.stem + + # Change sys.path permanently: restoring it at the end of this function would cause surprising + # problems because of delayed imports: for example, a conftest.py file imported by this function + # might have local imports, which would fail at runtime if we restored sys.path. + if mode is ImportMode.append: + if str(pkg_root) not in sys.path: + sys.path.append(str(pkg_root)) + elif mode is ImportMode.prepend: + if str(pkg_root) != sys.path[0]: + sys.path.insert(0, str(pkg_root)) + else: + assert_never(mode) + + importlib.import_module(module_name) + + mod = sys.modules[module_name] + if path.name == "__init__.py": + return mod + + ignore = os.environ.get("PY_IGNORE_IMPORTMISMATCH", "") + if ignore != "1": + module_file = mod.__file__ + if module_file is None: + raise ImportPathMismatchError(module_name, module_file, path) + + if module_file.endswith((".pyc", ".pyo")): + module_file = module_file[:-1] + if module_file.endswith(os.sep + "__init__.py"): + module_file = module_file[: -(len(os.sep + "__init__.py"))] + + try: + is_same = _is_same(str(path), module_file) + except FileNotFoundError: + is_same = False + + if not is_same: + raise ImportPathMismatchError(module_name, module_file, path) + + return mod + + +# Implement a special _is_same function on Windows which returns True if the two filenames +# compare equal, to circumvent os.path.samefile returning False for mounts in UNC (#7678). +if sys.platform.startswith("win"): + + def _is_same(f1: str, f2: str) -> bool: + return Path(f1) == Path(f2) or os.path.samefile(f1, f2) + +else: + + def _is_same(f1: str, f2: str) -> bool: + return os.path.samefile(f1, f2) + + +def module_name_from_path(path: Path, root: Path) -> str: + """ + Return a dotted module name based on the given path, anchored on root. + + For example: path="projects/src/tests/test_foo.py" and root="/projects", the + resulting module name will be "src.tests.test_foo". + """ + path = path.with_suffix("") + try: + relative_path = path.relative_to(root) + except ValueError: + # If we can't get a relative path to root, use the full path, except + # for the first part ("d:\\" or "/" depending on the platform, for example). + path_parts = path.parts[1:] + else: + # Use the parts for the relative path to the root path. + path_parts = relative_path.parts + + # Module name for packages do not contain the __init__ file, unless + # the `__init__.py` file is at the root. + if len(path_parts) >= 2 and path_parts[-1] == "__init__": + path_parts = path_parts[:-1] + + return ".".join(path_parts) + + +def insert_missing_modules(modules: Dict[str, ModuleType], module_name: str) -> None: + """ + Used by ``import_path`` to create intermediate modules when using mode=importlib. + + When we want to import a module as "src.tests.test_foo" for example, we need + to create empty modules "src" and "src.tests" after inserting "src.tests.test_foo", + otherwise "src.tests.test_foo" is not importable by ``__import__``. + """ + module_parts = module_name.split(".") + child_module: Union[ModuleType, None] = None + module: Union[ModuleType, None] = None + child_name: str = "" + while module_name: + if module_name not in modules: + try: + # If sys.meta_path is empty, calling import_module will issue + # a warning and raise ModuleNotFoundError. To avoid the + # warning, we check sys.meta_path explicitly and raise the error + # ourselves to fall back to creating a dummy module. + if not sys.meta_path: + raise ModuleNotFoundError + module = importlib.import_module(module_name) + except ModuleNotFoundError: + module = ModuleType( + module_name, + doc="Empty module created by pytest's importmode=importlib.", + ) + else: + module = modules[module_name] + if child_module: + # Add child attribute to the parent that can reference the child + # modules. + if not hasattr(module, child_name): + setattr(module, child_name, child_module) + modules[module_name] = module + # Keep track of the child module while moving up the tree. + child_module, child_name = module, module_name.rpartition(".")[-1] + module_parts.pop(-1) + module_name = ".".join(module_parts) + + +def resolve_package_path(path: Path) -> Optional[Path]: + """Return the Python package path by looking for the last + directory upwards which still contains an __init__.py. + + Returns None if it can not be determined. + """ + result = None + for parent in itertools.chain((path,), path.parents): + if parent.is_dir(): + if not parent.joinpath("__init__.py").is_file(): + break + if not parent.name.isidentifier(): + break + result = parent + return result + + +def scandir(path: Union[str, "os.PathLike[str]"]) -> List["os.DirEntry[str]"]: + """Scan a directory recursively, in breadth-first order. + + The returned entries are sorted. + """ + entries = [] + with os.scandir(path) as s: + # Skip entries with symlink loops and other brokenness, so the caller + # doesn't have to deal with it. + for entry in s: + try: + entry.is_file() + except OSError as err: + if _ignore_error(err): + continue + raise + entries.append(entry) + entries.sort(key=lambda entry: entry.name) + return entries + + +def visit( + path: Union[str, "os.PathLike[str]"], recurse: Callable[["os.DirEntry[str]"], bool] +) -> Iterator["os.DirEntry[str]"]: + """Walk a directory recursively, in breadth-first order. + + The `recurse` predicate determines whether a directory is recursed. + + Entries at each directory level are sorted. + """ + entries = scandir(path) + yield from entries + for entry in entries: + if entry.is_dir() and recurse(entry): + yield from visit(entry.path, recurse) + + +def absolutepath(path: Union[Path, str]) -> Path: + """Convert a path to an absolute path using os.path.abspath. + + Prefer this over Path.resolve() (see #6523). + Prefer this over Path.absolute() (not public, doesn't normalize). + """ + return Path(os.path.abspath(str(path))) + + +def commonpath(path1: Path, path2: Path) -> Optional[Path]: + """Return the common part shared with the other path, or None if there is + no common part. + + If one path is relative and one is absolute, returns None. + """ + try: + return Path(os.path.commonpath((str(path1), str(path2)))) + except ValueError: + return None + + +def bestrelpath(directory: Path, dest: Path) -> str: + """Return a string which is a relative path from directory to dest such + that directory/bestrelpath == dest. + + The paths must be either both absolute or both relative. + + If no such path can be determined, returns dest. + """ + assert isinstance(directory, Path) + assert isinstance(dest, Path) + if dest == directory: + return os.curdir + # Find the longest common directory. + base = commonpath(directory, dest) + # Can be the case on Windows for two absolute paths on different drives. + # Can be the case for two relative paths without common prefix. + # Can be the case for a relative path and an absolute path. + if not base: + return str(dest) + reldirectory = directory.relative_to(base) + reldest = dest.relative_to(base) + return os.path.join( + # Back from directory to base. + *([os.pardir] * len(reldirectory.parts)), + # Forward from base to dest. + *reldest.parts, + ) + + +# Originates from py. path.local.copy(), with siginficant trims and adjustments. +# TODO(py38): Replace with shutil.copytree(..., symlinks=True, dirs_exist_ok=True) +def copytree(source: Path, target: Path) -> None: + """Recursively copy a source directory to target.""" + assert source.is_dir() + for entry in visit(source, recurse=lambda entry: not entry.is_symlink()): + x = Path(entry) + relpath = x.relative_to(source) + newx = target / relpath + newx.parent.mkdir(exist_ok=True) + if x.is_symlink(): + newx.symlink_to(os.readlink(x)) + elif x.is_file(): + shutil.copyfile(x, newx) + elif x.is_dir(): + newx.mkdir(exist_ok=True) + + +def safe_exists(p: Path) -> bool: + """Like Path.exists(), but account for input arguments that might be too long (#11394).""" + try: + return p.exists() + except (ValueError, OSError): + # ValueError: stat: path too long for Windows + # OSError: [WinError 123] The filename, directory name, or volume label syntax is incorrect + return False diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/py.typed b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/pytester.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/pytester.py new file mode 100644 index 000000000..cdfc2c04a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/pytester.py @@ -0,0 +1,1789 @@ +"""(Disabled by default) support for testing pytest and pytest plugins. + +PYTEST_DONT_REWRITE +""" +import collections.abc +import contextlib +import gc +import importlib +import locale +import os +import platform +import re +import shutil +import subprocess +import sys +import traceback +from fnmatch import fnmatch +from io import StringIO +from pathlib import Path +from typing import Any +from typing import Callable +from typing import Dict +from typing import Generator +from typing import IO +from typing import Iterable +from typing import List +from typing import Optional +from typing import overload +from typing import Sequence +from typing import TextIO +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import Union +from weakref import WeakKeyDictionary + +from iniconfig import IniConfig +from iniconfig import SectionWrapper + +from _pytest import timing +from _pytest._code import Source +from _pytest.capture import _get_multicapture +from _pytest.compat import final +from _pytest.compat import NOTSET +from _pytest.compat import NotSetType +from _pytest.config import _PluggyPlugin +from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config import hookimpl +from _pytest.config import main +from _pytest.config import PytestPluginManager +from _pytest.config.argparsing import Parser +from _pytest.deprecated import check_ispytest +from _pytest.fixtures import fixture +from _pytest.fixtures import FixtureRequest +from _pytest.main import Session +from _pytest.monkeypatch import MonkeyPatch +from _pytest.nodes import Collector +from _pytest.nodes import Item +from _pytest.outcomes import fail +from _pytest.outcomes import importorskip +from _pytest.outcomes import skip +from _pytest.pathlib import bestrelpath +from _pytest.pathlib import copytree +from _pytest.pathlib import make_numbered_dir +from _pytest.reports import CollectReport +from _pytest.reports import TestReport +from _pytest.tmpdir import TempPathFactory +from _pytest.warning_types import PytestWarning + + +if TYPE_CHECKING: + from typing_extensions import Final + from typing_extensions import Literal + + import pexpect + + +pytest_plugins = ["pytester_assertions"] + + +IGNORE_PAM = [ # filenames added when obtaining details about the current user + "/var/lib/sss/mc/passwd" +] + + +def pytest_addoption(parser: Parser) -> None: + parser.addoption( + "--lsof", + action="store_true", + dest="lsof", + default=False, + help="Run FD checks if lsof is available", + ) + + parser.addoption( + "--runpytest", + default="inprocess", + dest="runpytest", + choices=("inprocess", "subprocess"), + help=( + "Run pytest sub runs in tests using an 'inprocess' " + "or 'subprocess' (python -m main) method" + ), + ) + + parser.addini( + "pytester_example_dir", help="Directory to take the pytester example files from" + ) + + +def pytest_configure(config: Config) -> None: + if config.getvalue("lsof"): + checker = LsofFdLeakChecker() + if checker.matching_platform(): + config.pluginmanager.register(checker) + + config.addinivalue_line( + "markers", + "pytester_example_path(*path_segments): join the given path " + "segments to `pytester_example_dir` for this test.", + ) + + +class LsofFdLeakChecker: + def get_open_files(self) -> List[Tuple[str, str]]: + out = subprocess.run( + ("lsof", "-Ffn0", "-p", str(os.getpid())), + stdout=subprocess.PIPE, + stderr=subprocess.DEVNULL, + check=True, + text=True, + encoding=locale.getpreferredencoding(False), + ).stdout + + def isopen(line: str) -> bool: + return line.startswith("f") and ( + "deleted" not in line + and "mem" not in line + and "txt" not in line + and "cwd" not in line + ) + + open_files = [] + + for line in out.split("\n"): + if isopen(line): + fields = line.split("\0") + fd = fields[0][1:] + filename = fields[1][1:] + if filename in IGNORE_PAM: + continue + if filename.startswith("/"): + open_files.append((fd, filename)) + + return open_files + + def matching_platform(self) -> bool: + try: + subprocess.run(("lsof", "-v"), check=True) + except (OSError, subprocess.CalledProcessError): + return False + else: + return True + + @hookimpl(hookwrapper=True, tryfirst=True) + def pytest_runtest_protocol(self, item: Item) -> Generator[None, None, None]: + lines1 = self.get_open_files() + yield + if hasattr(sys, "pypy_version_info"): + gc.collect() + lines2 = self.get_open_files() + + new_fds = {t[0] for t in lines2} - {t[0] for t in lines1} + leaked_files = [t for t in lines2 if t[0] in new_fds] + if leaked_files: + error = [ + "***** %s FD leakage detected" % len(leaked_files), + *(str(f) for f in leaked_files), + "*** Before:", + *(str(f) for f in lines1), + "*** After:", + *(str(f) for f in lines2), + "***** %s FD leakage detected" % len(leaked_files), + "*** function %s:%s: %s " % item.location, + "See issue #2366", + ] + item.warn(PytestWarning("\n".join(error))) + + +# used at least by pytest-xdist plugin + + +@fixture +def _pytest(request: FixtureRequest) -> "PytestArg": + """Return a helper which offers a gethookrecorder(hook) method which + returns a HookRecorder instance which helps to make assertions about called + hooks.""" + return PytestArg(request) + + +class PytestArg: + def __init__(self, request: FixtureRequest) -> None: + self._request = request + + def gethookrecorder(self, hook) -> "HookRecorder": + hookrecorder = HookRecorder(hook._pm) + self._request.addfinalizer(hookrecorder.finish_recording) + return hookrecorder + + +def get_public_names(values: Iterable[str]) -> List[str]: + """Only return names from iterator values without a leading underscore.""" + return [x for x in values if x[0] != "_"] + + +@final +class RecordedHookCall: + """A recorded call to a hook. + + The arguments to the hook call are set as attributes. + For example: + + .. code-block:: python + + calls = hook_recorder.getcalls("pytest_runtest_setup") + # Suppose pytest_runtest_setup was called once with `item=an_item`. + assert calls[0].item is an_item + """ + + def __init__(self, name: str, kwargs) -> None: + self.__dict__.update(kwargs) + self._name = name + + def __repr__(self) -> str: + d = self.__dict__.copy() + del d["_name"] + return f"" + + if TYPE_CHECKING: + # The class has undetermined attributes, this tells mypy about it. + def __getattr__(self, key: str): + ... + + +@final +class HookRecorder: + """Record all hooks called in a plugin manager. + + Hook recorders are created by :class:`Pytester`. + + This wraps all the hook calls in the plugin manager, recording each call + before propagating the normal calls. + """ + + def __init__( + self, pluginmanager: PytestPluginManager, *, _ispytest: bool = False + ) -> None: + check_ispytest(_ispytest) + + self._pluginmanager = pluginmanager + self.calls: List[RecordedHookCall] = [] + self.ret: Optional[Union[int, ExitCode]] = None + + def before(hook_name: str, hook_impls, kwargs) -> None: + self.calls.append(RecordedHookCall(hook_name, kwargs)) + + def after(outcome, hook_name: str, hook_impls, kwargs) -> None: + pass + + self._undo_wrapping = pluginmanager.add_hookcall_monitoring(before, after) + + def finish_recording(self) -> None: + self._undo_wrapping() + + def getcalls(self, names: Union[str, Iterable[str]]) -> List[RecordedHookCall]: + """Get all recorded calls to hooks with the given names (or name).""" + if isinstance(names, str): + names = names.split() + return [call for call in self.calls if call._name in names] + + def assert_contains(self, entries: Sequence[Tuple[str, str]]) -> None: + __tracebackhide__ = True + i = 0 + entries = list(entries) + backlocals = sys._getframe(1).f_locals + while entries: + name, check = entries.pop(0) + for ind, call in enumerate(self.calls[i:]): + if call._name == name: + print("NAMEMATCH", name, call) + if eval(check, backlocals, call.__dict__): + print("CHECKERMATCH", repr(check), "->", call) + else: + print("NOCHECKERMATCH", repr(check), "-", call) + continue + i += ind + 1 + break + print("NONAMEMATCH", name, "with", call) + else: + fail(f"could not find {name!r} check {check!r}") + + def popcall(self, name: str) -> RecordedHookCall: + __tracebackhide__ = True + for i, call in enumerate(self.calls): + if call._name == name: + del self.calls[i] + return call + lines = [f"could not find call {name!r}, in:"] + lines.extend([" %s" % x for x in self.calls]) + fail("\n".join(lines)) + + def getcall(self, name: str) -> RecordedHookCall: + values = self.getcalls(name) + assert len(values) == 1, (name, values) + return values[0] + + # functionality for test reports + + @overload + def getreports( + self, + names: "Literal['pytest_collectreport']", + ) -> Sequence[CollectReport]: + ... + + @overload + def getreports( + self, + names: "Literal['pytest_runtest_logreport']", + ) -> Sequence[TestReport]: + ... + + @overload + def getreports( + self, + names: Union[str, Iterable[str]] = ( + "pytest_collectreport", + "pytest_runtest_logreport", + ), + ) -> Sequence[Union[CollectReport, TestReport]]: + ... + + def getreports( + self, + names: Union[str, Iterable[str]] = ( + "pytest_collectreport", + "pytest_runtest_logreport", + ), + ) -> Sequence[Union[CollectReport, TestReport]]: + return [x.report for x in self.getcalls(names)] + + def matchreport( + self, + inamepart: str = "", + names: Union[str, Iterable[str]] = ( + "pytest_runtest_logreport", + "pytest_collectreport", + ), + when: Optional[str] = None, + ) -> Union[CollectReport, TestReport]: + """Return a testreport whose dotted import path matches.""" + values = [] + for rep in self.getreports(names=names): + if not when and rep.when != "call" and rep.passed: + # setup/teardown passing reports - let's ignore those + continue + if when and rep.when != when: + continue + if not inamepart or inamepart in rep.nodeid.split("::"): + values.append(rep) + if not values: + raise ValueError( + "could not find test report matching %r: " + "no test reports at all!" % (inamepart,) + ) + if len(values) > 1: + raise ValueError( + "found 2 or more testreports matching {!r}: {}".format( + inamepart, values + ) + ) + return values[0] + + @overload + def getfailures( + self, + names: "Literal['pytest_collectreport']", + ) -> Sequence[CollectReport]: + ... + + @overload + def getfailures( + self, + names: "Literal['pytest_runtest_logreport']", + ) -> Sequence[TestReport]: + ... + + @overload + def getfailures( + self, + names: Union[str, Iterable[str]] = ( + "pytest_collectreport", + "pytest_runtest_logreport", + ), + ) -> Sequence[Union[CollectReport, TestReport]]: + ... + + def getfailures( + self, + names: Union[str, Iterable[str]] = ( + "pytest_collectreport", + "pytest_runtest_logreport", + ), + ) -> Sequence[Union[CollectReport, TestReport]]: + return [rep for rep in self.getreports(names) if rep.failed] + + def getfailedcollections(self) -> Sequence[CollectReport]: + return self.getfailures("pytest_collectreport") + + def listoutcomes( + self, + ) -> Tuple[ + Sequence[TestReport], + Sequence[Union[CollectReport, TestReport]], + Sequence[Union[CollectReport, TestReport]], + ]: + passed = [] + skipped = [] + failed = [] + for rep in self.getreports( + ("pytest_collectreport", "pytest_runtest_logreport") + ): + if rep.passed: + if rep.when == "call": + assert isinstance(rep, TestReport) + passed.append(rep) + elif rep.skipped: + skipped.append(rep) + else: + assert rep.failed, f"Unexpected outcome: {rep!r}" + failed.append(rep) + return passed, skipped, failed + + def countoutcomes(self) -> List[int]: + return [len(x) for x in self.listoutcomes()] + + def assertoutcome(self, passed: int = 0, skipped: int = 0, failed: int = 0) -> None: + __tracebackhide__ = True + from _pytest.pytester_assertions import assertoutcome + + outcomes = self.listoutcomes() + assertoutcome( + outcomes, + passed=passed, + skipped=skipped, + failed=failed, + ) + + def clear(self) -> None: + self.calls[:] = [] + + +@fixture +def linecomp() -> "LineComp": + """A :class: `LineComp` instance for checking that an input linearly + contains a sequence of strings.""" + return LineComp() + + +@fixture(name="LineMatcher") +def LineMatcher_fixture(request: FixtureRequest) -> Type["LineMatcher"]: + """A reference to the :class: `LineMatcher`. + + This is instantiable with a list of lines (without their trailing newlines). + This is useful for testing large texts, such as the output of commands. + """ + return LineMatcher + + +@fixture +def pytester( + request: FixtureRequest, tmp_path_factory: TempPathFactory, monkeypatch: MonkeyPatch +) -> "Pytester": + """ + Facilities to write tests/configuration files, execute pytest in isolation, and match + against expected output, perfect for black-box testing of pytest plugins. + + It attempts to isolate the test run from external factors as much as possible, modifying + the current working directory to ``path`` and environment variables during initialization. + + It is particularly useful for testing plugins. It is similar to the :fixture:`tmp_path` + fixture but provides methods which aid in testing pytest itself. + """ + return Pytester(request, tmp_path_factory, monkeypatch, _ispytest=True) + + +@fixture +def _sys_snapshot() -> Generator[None, None, None]: + snappaths = SysPathsSnapshot() + snapmods = SysModulesSnapshot() + yield + snapmods.restore() + snappaths.restore() + + +@fixture +def _config_for_test() -> Generator[Config, None, None]: + from _pytest.config import get_config + + config = get_config() + yield config + config._ensure_unconfigure() # cleanup, e.g. capman closing tmpfiles. + + +# Regex to match the session duration string in the summary: "74.34s". +rex_session_duration = re.compile(r"\d+\.\d\ds") +# Regex to match all the counts and phrases in the summary line: "34 passed, 111 skipped". +rex_outcome = re.compile(r"(\d+) (\w+)") + + +@final +class RunResult: + """The result of running a command from :class:`~pytest.Pytester`.""" + + def __init__( + self, + ret: Union[int, ExitCode], + outlines: List[str], + errlines: List[str], + duration: float, + ) -> None: + try: + self.ret: Union[int, ExitCode] = ExitCode(ret) + """The return value.""" + except ValueError: + self.ret = ret + self.outlines = outlines + """List of lines captured from stdout.""" + self.errlines = errlines + """List of lines captured from stderr.""" + self.stdout = LineMatcher(outlines) + """:class:`~pytest.LineMatcher` of stdout. + + Use e.g. :func:`str(stdout) ` to reconstruct stdout, or the commonly used + :func:`stdout.fnmatch_lines() ` method. + """ + self.stderr = LineMatcher(errlines) + """:class:`~pytest.LineMatcher` of stderr.""" + self.duration = duration + """Duration in seconds.""" + + def __repr__(self) -> str: + return ( + "" + % (self.ret, len(self.stdout.lines), len(self.stderr.lines), self.duration) + ) + + def parseoutcomes(self) -> Dict[str, int]: + """Return a dictionary of outcome noun -> count from parsing the terminal + output that the test process produced. + + The returned nouns will always be in plural form:: + + ======= 1 failed, 1 passed, 1 warning, 1 error in 0.13s ==== + + Will return ``{"failed": 1, "passed": 1, "warnings": 1, "errors": 1}``. + """ + return self.parse_summary_nouns(self.outlines) + + @classmethod + def parse_summary_nouns(cls, lines) -> Dict[str, int]: + """Extract the nouns from a pytest terminal summary line. + + It always returns the plural noun for consistency:: + + ======= 1 failed, 1 passed, 1 warning, 1 error in 0.13s ==== + + Will return ``{"failed": 1, "passed": 1, "warnings": 1, "errors": 1}``. + """ + for line in reversed(lines): + if rex_session_duration.search(line): + outcomes = rex_outcome.findall(line) + ret = {noun: int(count) for (count, noun) in outcomes} + break + else: + raise ValueError("Pytest terminal summary report not found") + + to_plural = { + "warning": "warnings", + "error": "errors", + } + return {to_plural.get(k, k): v for k, v in ret.items()} + + def assert_outcomes( + self, + passed: int = 0, + skipped: int = 0, + failed: int = 0, + errors: int = 0, + xpassed: int = 0, + xfailed: int = 0, + warnings: Optional[int] = None, + deselected: Optional[int] = None, + ) -> None: + """ + Assert that the specified outcomes appear with the respective + numbers (0 means it didn't occur) in the text output from a test run. + + ``warnings`` and ``deselected`` are only checked if not None. + """ + __tracebackhide__ = True + from _pytest.pytester_assertions import assert_outcomes + + outcomes = self.parseoutcomes() + assert_outcomes( + outcomes, + passed=passed, + skipped=skipped, + failed=failed, + errors=errors, + xpassed=xpassed, + xfailed=xfailed, + warnings=warnings, + deselected=deselected, + ) + + +class CwdSnapshot: + def __init__(self) -> None: + self.__saved = os.getcwd() + + def restore(self) -> None: + os.chdir(self.__saved) + + +class SysModulesSnapshot: + def __init__(self, preserve: Optional[Callable[[str], bool]] = None) -> None: + self.__preserve = preserve + self.__saved = dict(sys.modules) + + def restore(self) -> None: + if self.__preserve: + self.__saved.update( + (k, m) for k, m in sys.modules.items() if self.__preserve(k) + ) + sys.modules.clear() + sys.modules.update(self.__saved) + + +class SysPathsSnapshot: + def __init__(self) -> None: + self.__saved = list(sys.path), list(sys.meta_path) + + def restore(self) -> None: + sys.path[:], sys.meta_path[:] = self.__saved + + +@final +class Pytester: + """ + Facilities to write tests/configuration files, execute pytest in isolation, and match + against expected output, perfect for black-box testing of pytest plugins. + + It attempts to isolate the test run from external factors as much as possible, modifying + the current working directory to :attr:`path` and environment variables during initialization. + """ + + __test__ = False + + CLOSE_STDIN: "Final" = NOTSET + + class TimeoutExpired(Exception): + pass + + def __init__( + self, + request: FixtureRequest, + tmp_path_factory: TempPathFactory, + monkeypatch: MonkeyPatch, + *, + _ispytest: bool = False, + ) -> None: + check_ispytest(_ispytest) + self._request = request + self._mod_collections: WeakKeyDictionary[ + Collector, List[Union[Item, Collector]] + ] = WeakKeyDictionary() + if request.function: + name: str = request.function.__name__ + else: + name = request.node.name + self._name = name + self._path: Path = tmp_path_factory.mktemp(name, numbered=True) + #: A list of plugins to use with :py:meth:`parseconfig` and + #: :py:meth:`runpytest`. Initially this is an empty list but plugins can + #: be added to the list. The type of items to add to the list depends on + #: the method using them so refer to them for details. + self.plugins: List[Union[str, _PluggyPlugin]] = [] + self._cwd_snapshot = CwdSnapshot() + self._sys_path_snapshot = SysPathsSnapshot() + self._sys_modules_snapshot = self.__take_sys_modules_snapshot() + self.chdir() + self._request.addfinalizer(self._finalize) + self._method = self._request.config.getoption("--runpytest") + self._test_tmproot = tmp_path_factory.mktemp(f"tmp-{name}", numbered=True) + + self._monkeypatch = mp = monkeypatch + mp.setenv("PYTEST_DEBUG_TEMPROOT", str(self._test_tmproot)) + # Ensure no unexpected caching via tox. + mp.delenv("TOX_ENV_DIR", raising=False) + # Discard outer pytest options. + mp.delenv("PYTEST_ADDOPTS", raising=False) + # Ensure no user config is used. + tmphome = str(self.path) + mp.setenv("HOME", tmphome) + mp.setenv("USERPROFILE", tmphome) + # Do not use colors for inner runs by default. + mp.setenv("PY_COLORS", "0") + + @property + def path(self) -> Path: + """Temporary directory path used to create files/run tests from, etc.""" + return self._path + + def __repr__(self) -> str: + return f"" + + def _finalize(self) -> None: + """ + Clean up global state artifacts. + + Some methods modify the global interpreter state and this tries to + clean this up. It does not remove the temporary directory however so + it can be looked at after the test run has finished. + """ + self._sys_modules_snapshot.restore() + self._sys_path_snapshot.restore() + self._cwd_snapshot.restore() + + def __take_sys_modules_snapshot(self) -> SysModulesSnapshot: + # Some zope modules used by twisted-related tests keep internal state + # and can't be deleted; we had some trouble in the past with + # `zope.interface` for example. + # + # Preserve readline due to https://bugs.python.org/issue41033. + # pexpect issues a SIGWINCH. + def preserve_module(name): + return name.startswith(("zope", "readline")) + + return SysModulesSnapshot(preserve=preserve_module) + + def make_hook_recorder(self, pluginmanager: PytestPluginManager) -> HookRecorder: + """Create a new :class:`HookRecorder` for a :class:`PytestPluginManager`.""" + pluginmanager.reprec = reprec = HookRecorder(pluginmanager, _ispytest=True) # type: ignore[attr-defined] + self._request.addfinalizer(reprec.finish_recording) + return reprec + + def chdir(self) -> None: + """Cd into the temporary directory. + + This is done automatically upon instantiation. + """ + os.chdir(self.path) + + def _makefile( + self, + ext: str, + lines: Sequence[Union[Any, bytes]], + files: Dict[str, str], + encoding: str = "utf-8", + ) -> Path: + items = list(files.items()) + + if ext and not ext.startswith("."): + raise ValueError( + f"pytester.makefile expects a file extension, try .{ext} instead of {ext}" + ) + + def to_text(s: Union[Any, bytes]) -> str: + return s.decode(encoding) if isinstance(s, bytes) else str(s) + + if lines: + source = "\n".join(to_text(x) for x in lines) + basename = self._name + items.insert(0, (basename, source)) + + ret = None + for basename, value in items: + p = self.path.joinpath(basename).with_suffix(ext) + p.parent.mkdir(parents=True, exist_ok=True) + source_ = Source(value) + source = "\n".join(to_text(line) for line in source_.lines) + p.write_text(source.strip(), encoding=encoding) + if ret is None: + ret = p + assert ret is not None + return ret + + def makefile(self, ext: str, *args: str, **kwargs: str) -> Path: + r"""Create new text file(s) in the test directory. + + :param ext: + The extension the file(s) should use, including the dot, e.g. `.py`. + :param args: + All args are treated as strings and joined using newlines. + The result is written as contents to the file. The name of the + file is based on the test function requesting this fixture. + :param kwargs: + Each keyword is the name of a file, while the value of it will + be written as contents of the file. + :returns: + The first created file. + + Examples: + + .. code-block:: python + + pytester.makefile(".txt", "line1", "line2") + + pytester.makefile(".ini", pytest="[pytest]\naddopts=-rs\n") + + To create binary files, use :meth:`pathlib.Path.write_bytes` directly: + + .. code-block:: python + + filename = pytester.path.joinpath("foo.bin") + filename.write_bytes(b"...") + """ + return self._makefile(ext, args, kwargs) + + def makeconftest(self, source: str) -> Path: + """Write a contest.py file. + + :param source: The contents. + :returns: The conftest.py file. + """ + return self.makepyfile(conftest=source) + + def makeini(self, source: str) -> Path: + """Write a tox.ini file. + + :param source: The contents. + :returns: The tox.ini file. + """ + return self.makefile(".ini", tox=source) + + def getinicfg(self, source: str) -> SectionWrapper: + """Return the pytest section from the tox.ini config file.""" + p = self.makeini(source) + return IniConfig(str(p))["pytest"] + + def makepyprojecttoml(self, source: str) -> Path: + """Write a pyproject.toml file. + + :param source: The contents. + :returns: The pyproject.ini file. + + .. versionadded:: 6.0 + """ + return self.makefile(".toml", pyproject=source) + + def makepyfile(self, *args, **kwargs) -> Path: + r"""Shortcut for .makefile() with a .py extension. + + Defaults to the test name with a '.py' extension, e.g test_foobar.py, overwriting + existing files. + + Examples: + + .. code-block:: python + + def test_something(pytester): + # Initial file is created test_something.py. + pytester.makepyfile("foobar") + # To create multiple files, pass kwargs accordingly. + pytester.makepyfile(custom="foobar") + # At this point, both 'test_something.py' & 'custom.py' exist in the test directory. + + """ + return self._makefile(".py", args, kwargs) + + def maketxtfile(self, *args, **kwargs) -> Path: + r"""Shortcut for .makefile() with a .txt extension. + + Defaults to the test name with a '.txt' extension, e.g test_foobar.txt, overwriting + existing files. + + Examples: + + .. code-block:: python + + def test_something(pytester): + # Initial file is created test_something.txt. + pytester.maketxtfile("foobar") + # To create multiple files, pass kwargs accordingly. + pytester.maketxtfile(custom="foobar") + # At this point, both 'test_something.txt' & 'custom.txt' exist in the test directory. + + """ + return self._makefile(".txt", args, kwargs) + + def syspathinsert( + self, path: Optional[Union[str, "os.PathLike[str]"]] = None + ) -> None: + """Prepend a directory to sys.path, defaults to :attr:`path`. + + This is undone automatically when this object dies at the end of each + test. + + :param path: + The path. + """ + if path is None: + path = self.path + + self._monkeypatch.syspath_prepend(str(path)) + + def mkdir(self, name: Union[str, "os.PathLike[str]"]) -> Path: + """Create a new (sub)directory. + + :param name: + The name of the directory, relative to the pytester path. + :returns: + The created directory. + """ + p = self.path / name + p.mkdir() + return p + + def mkpydir(self, name: Union[str, "os.PathLike[str]"]) -> Path: + """Create a new python package. + + This creates a (sub)directory with an empty ``__init__.py`` file so it + gets recognised as a Python package. + """ + p = self.path / name + p.mkdir() + p.joinpath("__init__.py").touch() + return p + + def copy_example(self, name: Optional[str] = None) -> Path: + """Copy file from project's directory into the testdir. + + :param name: + The name of the file to copy. + :return: + Path to the copied directory (inside ``self.path``). + """ + example_dir_ = self._request.config.getini("pytester_example_dir") + if example_dir_ is None: + raise ValueError("pytester_example_dir is unset, can't copy examples") + example_dir: Path = self._request.config.rootpath / example_dir_ + + for extra_element in self._request.node.iter_markers("pytester_example_path"): + assert extra_element.args + example_dir = example_dir.joinpath(*extra_element.args) + + if name is None: + func_name = self._name + maybe_dir = example_dir / func_name + maybe_file = example_dir / (func_name + ".py") + + if maybe_dir.is_dir(): + example_path = maybe_dir + elif maybe_file.is_file(): + example_path = maybe_file + else: + raise LookupError( + f"{func_name} can't be found as module or package in {example_dir}" + ) + else: + example_path = example_dir.joinpath(name) + + if example_path.is_dir() and not example_path.joinpath("__init__.py").is_file(): + copytree(example_path, self.path) + return self.path + elif example_path.is_file(): + result = self.path.joinpath(example_path.name) + shutil.copy(example_path, result) + return result + else: + raise LookupError( + f'example "{example_path}" is not found as a file or directory' + ) + + def getnode( + self, config: Config, arg: Union[str, "os.PathLike[str]"] + ) -> Union[Collector, Item]: + """Get the collection node of a file. + + :param config: + A pytest config. + See :py:meth:`parseconfig` and :py:meth:`parseconfigure` for creating it. + :param arg: + Path to the file. + :returns: + The node. + """ + session = Session.from_config(config) + assert "::" not in str(arg) + p = Path(os.path.abspath(arg)) + config.hook.pytest_sessionstart(session=session) + res = session.perform_collect([str(p)], genitems=False)[0] + config.hook.pytest_sessionfinish(session=session, exitstatus=ExitCode.OK) + return res + + def getpathnode( + self, path: Union[str, "os.PathLike[str]"] + ) -> Union[Collector, Item]: + """Return the collection node of a file. + + This is like :py:meth:`getnode` but uses :py:meth:`parseconfigure` to + create the (configured) pytest Config instance. + + :param path: + Path to the file. + :returns: + The node. + """ + path = Path(path) + config = self.parseconfigure(path) + session = Session.from_config(config) + x = bestrelpath(session.path, path) + config.hook.pytest_sessionstart(session=session) + res = session.perform_collect([x], genitems=False)[0] + config.hook.pytest_sessionfinish(session=session, exitstatus=ExitCode.OK) + return res + + def genitems(self, colitems: Sequence[Union[Item, Collector]]) -> List[Item]: + """Generate all test items from a collection node. + + This recurses into the collection node and returns a list of all the + test items contained within. + + :param colitems: + The collection nodes. + :returns: + The collected items. + """ + session = colitems[0].session + result: List[Item] = [] + for colitem in colitems: + result.extend(session.genitems(colitem)) + return result + + def runitem(self, source: str) -> Any: + """Run the "test_func" Item. + + The calling test instance (class containing the test method) must + provide a ``.getrunner()`` method which should return a runner which + can run the test protocol for a single item, e.g. + :py:func:`_pytest.runner.runtestprotocol`. + """ + # used from runner functional tests + item = self.getitem(source) + # the test class where we are called from wants to provide the runner + testclassinstance = self._request.instance + runner = testclassinstance.getrunner() + return runner(item) + + def inline_runsource(self, source: str, *cmdlineargs) -> HookRecorder: + """Run a test module in process using ``pytest.main()``. + + This run writes "source" into a temporary file and runs + ``pytest.main()`` on it, returning a :py:class:`HookRecorder` instance + for the result. + + :param source: The source code of the test module. + :param cmdlineargs: Any extra command line arguments to use. + """ + p = self.makepyfile(source) + values = list(cmdlineargs) + [p] + return self.inline_run(*values) + + def inline_genitems(self, *args) -> Tuple[List[Item], HookRecorder]: + """Run ``pytest.main(['--collectonly'])`` in-process. + + Runs the :py:func:`pytest.main` function to run all of pytest inside + the test process itself like :py:meth:`inline_run`, but returns a + tuple of the collected items and a :py:class:`HookRecorder` instance. + """ + rec = self.inline_run("--collect-only", *args) + items = [x.item for x in rec.getcalls("pytest_itemcollected")] + return items, rec + + def inline_run( + self, + *args: Union[str, "os.PathLike[str]"], + plugins=(), + no_reraise_ctrlc: bool = False, + ) -> HookRecorder: + """Run ``pytest.main()`` in-process, returning a HookRecorder. + + Runs the :py:func:`pytest.main` function to run all of pytest inside + the test process itself. This means it can return a + :py:class:`HookRecorder` instance which gives more detailed results + from that run than can be done by matching stdout/stderr from + :py:meth:`runpytest`. + + :param args: + Command line arguments to pass to :py:func:`pytest.main`. + :param plugins: + Extra plugin instances the ``pytest.main()`` instance should use. + :param no_reraise_ctrlc: + Typically we reraise keyboard interrupts from the child run. If + True, the KeyboardInterrupt exception is captured. + """ + # (maybe a cpython bug?) the importlib cache sometimes isn't updated + # properly between file creation and inline_run (especially if imports + # are interspersed with file creation) + importlib.invalidate_caches() + + plugins = list(plugins) + finalizers = [] + try: + # Any sys.module or sys.path changes done while running pytest + # inline should be reverted after the test run completes to avoid + # clashing with later inline tests run within the same pytest test, + # e.g. just because they use matching test module names. + finalizers.append(self.__take_sys_modules_snapshot().restore) + finalizers.append(SysPathsSnapshot().restore) + + # Important note: + # - our tests should not leave any other references/registrations + # laying around other than possibly loaded test modules + # referenced from sys.modules, as nothing will clean those up + # automatically + + rec = [] + + class Collect: + def pytest_configure(x, config: Config) -> None: + rec.append(self.make_hook_recorder(config.pluginmanager)) + + plugins.append(Collect()) + ret = main([str(x) for x in args], plugins=plugins) + if len(rec) == 1: + reprec = rec.pop() + else: + + class reprec: # type: ignore + pass + + reprec.ret = ret + + # Typically we reraise keyboard interrupts from the child run + # because it's our user requesting interruption of the testing. + if ret == ExitCode.INTERRUPTED and not no_reraise_ctrlc: + calls = reprec.getcalls("pytest_keyboard_interrupt") + if calls and calls[-1].excinfo.type == KeyboardInterrupt: + raise KeyboardInterrupt() + return reprec + finally: + for finalizer in finalizers: + finalizer() + + def runpytest_inprocess( + self, *args: Union[str, "os.PathLike[str]"], **kwargs: Any + ) -> RunResult: + """Return result of running pytest in-process, providing a similar + interface to what self.runpytest() provides.""" + syspathinsert = kwargs.pop("syspathinsert", False) + + if syspathinsert: + self.syspathinsert() + now = timing.time() + capture = _get_multicapture("sys") + capture.start_capturing() + try: + try: + reprec = self.inline_run(*args, **kwargs) + except SystemExit as e: + ret = e.args[0] + try: + ret = ExitCode(e.args[0]) + except ValueError: + pass + + class reprec: # type: ignore + ret = ret + + except Exception: + traceback.print_exc() + + class reprec: # type: ignore + ret = ExitCode(3) + + finally: + out, err = capture.readouterr() + capture.stop_capturing() + sys.stdout.write(out) + sys.stderr.write(err) + + assert reprec.ret is not None + res = RunResult( + reprec.ret, out.splitlines(), err.splitlines(), timing.time() - now + ) + res.reprec = reprec # type: ignore + return res + + def runpytest( + self, *args: Union[str, "os.PathLike[str]"], **kwargs: Any + ) -> RunResult: + """Run pytest inline or in a subprocess, depending on the command line + option "--runpytest" and return a :py:class:`~pytest.RunResult`.""" + new_args = self._ensure_basetemp(args) + if self._method == "inprocess": + return self.runpytest_inprocess(*new_args, **kwargs) + elif self._method == "subprocess": + return self.runpytest_subprocess(*new_args, **kwargs) + raise RuntimeError(f"Unrecognized runpytest option: {self._method}") + + def _ensure_basetemp( + self, args: Sequence[Union[str, "os.PathLike[str]"]] + ) -> List[Union[str, "os.PathLike[str]"]]: + new_args = list(args) + for x in new_args: + if str(x).startswith("--basetemp"): + break + else: + new_args.append("--basetemp=%s" % self.path.parent.joinpath("basetemp")) + return new_args + + def parseconfig(self, *args: Union[str, "os.PathLike[str]"]) -> Config: + """Return a new pytest :class:`pytest.Config` instance from given + commandline args. + + This invokes the pytest bootstrapping code in _pytest.config to create a + new :py:class:`pytest.PytestPluginManager` and call the + :hook:`pytest_cmdline_parse` hook to create a new :class:`pytest.Config` + instance. + + If :attr:`plugins` has been populated they should be plugin modules + to be registered with the plugin manager. + """ + import _pytest.config + + new_args = self._ensure_basetemp(args) + new_args = [str(x) for x in new_args] + + config = _pytest.config._prepareconfig(new_args, self.plugins) # type: ignore[arg-type] + # we don't know what the test will do with this half-setup config + # object and thus we make sure it gets unconfigured properly in any + # case (otherwise capturing could still be active, for example) + self._request.addfinalizer(config._ensure_unconfigure) + return config + + def parseconfigure(self, *args: Union[str, "os.PathLike[str]"]) -> Config: + """Return a new pytest configured Config instance. + + Returns a new :py:class:`pytest.Config` instance like + :py:meth:`parseconfig`, but also calls the :hook:`pytest_configure` + hook. + """ + config = self.parseconfig(*args) + config._do_configure() + return config + + def getitem( + self, source: Union[str, "os.PathLike[str]"], funcname: str = "test_func" + ) -> Item: + """Return the test item for a test function. + + Writes the source to a python file and runs pytest's collection on + the resulting module, returning the test item for the requested + function name. + + :param source: + The module source. + :param funcname: + The name of the test function for which to return a test item. + :returns: + The test item. + """ + items = self.getitems(source) + for item in items: + if item.name == funcname: + return item + assert 0, "{!r} item not found in module:\n{}\nitems: {}".format( + funcname, source, items + ) + + def getitems(self, source: Union[str, "os.PathLike[str]"]) -> List[Item]: + """Return all test items collected from the module. + + Writes the source to a Python file and runs pytest's collection on + the resulting module, returning all test items contained within. + """ + modcol = self.getmodulecol(source) + return self.genitems([modcol]) + + def getmodulecol( + self, + source: Union[str, "os.PathLike[str]"], + configargs=(), + *, + withinit: bool = False, + ): + """Return the module collection node for ``source``. + + Writes ``source`` to a file using :py:meth:`makepyfile` and then + runs the pytest collection on it, returning the collection node for the + test module. + + :param source: + The source code of the module to collect. + + :param configargs: + Any extra arguments to pass to :py:meth:`parseconfigure`. + + :param withinit: + Whether to also write an ``__init__.py`` file to the same + directory to ensure it is a package. + """ + if isinstance(source, os.PathLike): + path = self.path.joinpath(source) + assert not withinit, "not supported for paths" + else: + kw = {self._name: str(source)} + path = self.makepyfile(**kw) + if withinit: + self.makepyfile(__init__="#") + self.config = config = self.parseconfigure(path, *configargs) + return self.getnode(config, path) + + def collect_by_name( + self, modcol: Collector, name: str + ) -> Optional[Union[Item, Collector]]: + """Return the collection node for name from the module collection. + + Searches a module collection node for a collection node matching the + given name. + + :param modcol: A module collection node; see :py:meth:`getmodulecol`. + :param name: The name of the node to return. + """ + if modcol not in self._mod_collections: + self._mod_collections[modcol] = list(modcol.collect()) + for colitem in self._mod_collections[modcol]: + if colitem.name == name: + return colitem + return None + + def popen( + self, + cmdargs: Sequence[Union[str, "os.PathLike[str]"]], + stdout: Union[int, TextIO] = subprocess.PIPE, + stderr: Union[int, TextIO] = subprocess.PIPE, + stdin: Union[NotSetType, bytes, IO[Any], int] = CLOSE_STDIN, + **kw, + ): + """Invoke :py:class:`subprocess.Popen`. + + Calls :py:class:`subprocess.Popen` making sure the current working + directory is in ``PYTHONPATH``. + + You probably want to use :py:meth:`run` instead. + """ + env = os.environ.copy() + env["PYTHONPATH"] = os.pathsep.join( + filter(None, [os.getcwd(), env.get("PYTHONPATH", "")]) + ) + kw["env"] = env + + if stdin is self.CLOSE_STDIN: + kw["stdin"] = subprocess.PIPE + elif isinstance(stdin, bytes): + kw["stdin"] = subprocess.PIPE + else: + kw["stdin"] = stdin + + popen = subprocess.Popen(cmdargs, stdout=stdout, stderr=stderr, **kw) + if stdin is self.CLOSE_STDIN: + assert popen.stdin is not None + popen.stdin.close() + elif isinstance(stdin, bytes): + assert popen.stdin is not None + popen.stdin.write(stdin) + + return popen + + def run( + self, + *cmdargs: Union[str, "os.PathLike[str]"], + timeout: Optional[float] = None, + stdin: Union[NotSetType, bytes, IO[Any], int] = CLOSE_STDIN, + ) -> RunResult: + """Run a command with arguments. + + Run a process using :py:class:`subprocess.Popen` saving the stdout and + stderr. + + :param cmdargs: + The sequence of arguments to pass to :py:class:`subprocess.Popen`, + with path-like objects being converted to :py:class:`str` + automatically. + :param timeout: + The period in seconds after which to timeout and raise + :py:class:`Pytester.TimeoutExpired`. + :param stdin: + Optional standard input. + + - If it is :py:attr:`CLOSE_STDIN` (Default), then this method calls + :py:class:`subprocess.Popen` with ``stdin=subprocess.PIPE``, and + the standard input is closed immediately after the new command is + started. + + - If it is of type :py:class:`bytes`, these bytes are sent to the + standard input of the command. + + - Otherwise, it is passed through to :py:class:`subprocess.Popen`. + For further information in this case, consult the document of the + ``stdin`` parameter in :py:class:`subprocess.Popen`. + :returns: + The result. + """ + __tracebackhide__ = True + + cmdargs = tuple(os.fspath(arg) for arg in cmdargs) + p1 = self.path.joinpath("stdout") + p2 = self.path.joinpath("stderr") + print("running:", *cmdargs) + print(" in:", Path.cwd()) + + with p1.open("w", encoding="utf8") as f1, p2.open("w", encoding="utf8") as f2: + now = timing.time() + popen = self.popen( + cmdargs, + stdin=stdin, + stdout=f1, + stderr=f2, + close_fds=(sys.platform != "win32"), + ) + if popen.stdin is not None: + popen.stdin.close() + + def handle_timeout() -> None: + __tracebackhide__ = True + + timeout_message = ( + "{seconds} second timeout expired running:" + " {command}".format(seconds=timeout, command=cmdargs) + ) + + popen.kill() + popen.wait() + raise self.TimeoutExpired(timeout_message) + + if timeout is None: + ret = popen.wait() + else: + try: + ret = popen.wait(timeout) + except subprocess.TimeoutExpired: + handle_timeout() + + with p1.open(encoding="utf8") as f1, p2.open(encoding="utf8") as f2: + out = f1.read().splitlines() + err = f2.read().splitlines() + + self._dump_lines(out, sys.stdout) + self._dump_lines(err, sys.stderr) + + with contextlib.suppress(ValueError): + ret = ExitCode(ret) + return RunResult(ret, out, err, timing.time() - now) + + def _dump_lines(self, lines, fp): + try: + for line in lines: + print(line, file=fp) + except UnicodeEncodeError: + print(f"couldn't print to {fp} because of encoding") + + def _getpytestargs(self) -> Tuple[str, ...]: + return sys.executable, "-mpytest" + + def runpython(self, script: "os.PathLike[str]") -> RunResult: + """Run a python script using sys.executable as interpreter.""" + return self.run(sys.executable, script) + + def runpython_c(self, command: str) -> RunResult: + """Run ``python -c "command"``.""" + return self.run(sys.executable, "-c", command) + + def runpytest_subprocess( + self, *args: Union[str, "os.PathLike[str]"], timeout: Optional[float] = None + ) -> RunResult: + """Run pytest as a subprocess with given arguments. + + Any plugins added to the :py:attr:`plugins` list will be added using the + ``-p`` command line option. Additionally ``--basetemp`` is used to put + any temporary files and directories in a numbered directory prefixed + with "runpytest-" to not conflict with the normal numbered pytest + location for temporary files and directories. + + :param args: + The sequence of arguments to pass to the pytest subprocess. + :param timeout: + The period in seconds after which to timeout and raise + :py:class:`Pytester.TimeoutExpired`. + :returns: + The result. + """ + __tracebackhide__ = True + p = make_numbered_dir(root=self.path, prefix="runpytest-", mode=0o700) + args = ("--basetemp=%s" % p,) + args + plugins = [x for x in self.plugins if isinstance(x, str)] + if plugins: + args = ("-p", plugins[0]) + args + args = self._getpytestargs() + args + return self.run(*args, timeout=timeout) + + def spawn_pytest( + self, string: str, expect_timeout: float = 10.0 + ) -> "pexpect.spawn": + """Run pytest using pexpect. + + This makes sure to use the right pytest and sets up the temporary + directory locations. + + The pexpect child is returned. + """ + basetemp = self.path / "temp-pexpect" + basetemp.mkdir(mode=0o700) + invoke = " ".join(map(str, self._getpytestargs())) + cmd = f"{invoke} --basetemp={basetemp} {string}" + return self.spawn(cmd, expect_timeout=expect_timeout) + + def spawn(self, cmd: str, expect_timeout: float = 10.0) -> "pexpect.spawn": + """Run a command using pexpect. + + The pexpect child is returned. + """ + pexpect = importorskip("pexpect", "3.0") + if hasattr(sys, "pypy_version_info") and "64" in platform.machine(): + skip("pypy-64 bit not supported") + if not hasattr(pexpect, "spawn"): + skip("pexpect.spawn not available") + logfile = self.path.joinpath("spawn.out").open("wb") + + child = pexpect.spawn(cmd, logfile=logfile, timeout=expect_timeout) + self._request.addfinalizer(logfile.close) + return child + + +class LineComp: + def __init__(self) -> None: + self.stringio = StringIO() + """:class:`python:io.StringIO()` instance used for input.""" + + def assert_contains_lines(self, lines2: Sequence[str]) -> None: + """Assert that ``lines2`` are contained (linearly) in :attr:`stringio`'s value. + + Lines are matched using :func:`LineMatcher.fnmatch_lines `. + """ + __tracebackhide__ = True + val = self.stringio.getvalue() + self.stringio.truncate(0) + self.stringio.seek(0) + lines1 = val.split("\n") + LineMatcher(lines1).fnmatch_lines(lines2) + + +class LineMatcher: + """Flexible matching of text. + + This is a convenience class to test large texts like the output of + commands. + + The constructor takes a list of lines without their trailing newlines, i.e. + ``text.splitlines()``. + """ + + def __init__(self, lines: List[str]) -> None: + self.lines = lines + self._log_output: List[str] = [] + + def __str__(self) -> str: + """Return the entire original text. + + .. versionadded:: 6.2 + You can use :meth:`str` in older versions. + """ + return "\n".join(self.lines) + + def _getlines(self, lines2: Union[str, Sequence[str], Source]) -> Sequence[str]: + if isinstance(lines2, str): + lines2 = Source(lines2) + if isinstance(lines2, Source): + lines2 = lines2.strip().lines + return lines2 + + def fnmatch_lines_random(self, lines2: Sequence[str]) -> None: + """Check lines exist in the output in any order (using :func:`python:fnmatch.fnmatch`).""" + __tracebackhide__ = True + self._match_lines_random(lines2, fnmatch) + + def re_match_lines_random(self, lines2: Sequence[str]) -> None: + """Check lines exist in the output in any order (using :func:`python:re.match`).""" + __tracebackhide__ = True + self._match_lines_random(lines2, lambda name, pat: bool(re.match(pat, name))) + + def _match_lines_random( + self, lines2: Sequence[str], match_func: Callable[[str, str], bool] + ) -> None: + __tracebackhide__ = True + lines2 = self._getlines(lines2) + for line in lines2: + for x in self.lines: + if line == x or match_func(x, line): + self._log("matched: ", repr(line)) + break + else: + msg = "line %r not found in output" % line + self._log(msg) + self._fail(msg) + + def get_lines_after(self, fnline: str) -> Sequence[str]: + """Return all lines following the given line in the text. + + The given line can contain glob wildcards. + """ + for i, line in enumerate(self.lines): + if fnline == line or fnmatch(line, fnline): + return self.lines[i + 1 :] + raise ValueError("line %r not found in output" % fnline) + + def _log(self, *args) -> None: + self._log_output.append(" ".join(str(x) for x in args)) + + @property + def _log_text(self) -> str: + return "\n".join(self._log_output) + + def fnmatch_lines( + self, lines2: Sequence[str], *, consecutive: bool = False + ) -> None: + """Check lines exist in the output (using :func:`python:fnmatch.fnmatch`). + + The argument is a list of lines which have to match and can use glob + wildcards. If they do not match a pytest.fail() is called. The + matches and non-matches are also shown as part of the error message. + + :param lines2: String patterns to match. + :param consecutive: Match lines consecutively? + """ + __tracebackhide__ = True + self._match_lines(lines2, fnmatch, "fnmatch", consecutive=consecutive) + + def re_match_lines( + self, lines2: Sequence[str], *, consecutive: bool = False + ) -> None: + """Check lines exist in the output (using :func:`python:re.match`). + + The argument is a list of lines which have to match using ``re.match``. + If they do not match a pytest.fail() is called. + + The matches and non-matches are also shown as part of the error message. + + :param lines2: string patterns to match. + :param consecutive: match lines consecutively? + """ + __tracebackhide__ = True + self._match_lines( + lines2, + lambda name, pat: bool(re.match(pat, name)), + "re.match", + consecutive=consecutive, + ) + + def _match_lines( + self, + lines2: Sequence[str], + match_func: Callable[[str, str], bool], + match_nickname: str, + *, + consecutive: bool = False, + ) -> None: + """Underlying implementation of ``fnmatch_lines`` and ``re_match_lines``. + + :param Sequence[str] lines2: + List of string patterns to match. The actual format depends on + ``match_func``. + :param match_func: + A callable ``match_func(line, pattern)`` where line is the + captured line from stdout/stderr and pattern is the matching + pattern. + :param str match_nickname: + The nickname for the match function that will be logged to stdout + when a match occurs. + :param consecutive: + Match lines consecutively? + """ + if not isinstance(lines2, collections.abc.Sequence): + raise TypeError(f"invalid type for lines2: {type(lines2).__name__}") + lines2 = self._getlines(lines2) + lines1 = self.lines[:] + extralines = [] + __tracebackhide__ = True + wnick = len(match_nickname) + 1 + started = False + for line in lines2: + nomatchprinted = False + while lines1: + nextline = lines1.pop(0) + if line == nextline: + self._log("exact match:", repr(line)) + started = True + break + elif match_func(nextline, line): + self._log("%s:" % match_nickname, repr(line)) + self._log( + "{:>{width}}".format("with:", width=wnick), repr(nextline) + ) + started = True + break + else: + if consecutive and started: + msg = f"no consecutive match: {line!r}" + self._log(msg) + self._log( + "{:>{width}}".format("with:", width=wnick), repr(nextline) + ) + self._fail(msg) + if not nomatchprinted: + self._log( + "{:>{width}}".format("nomatch:", width=wnick), repr(line) + ) + nomatchprinted = True + self._log("{:>{width}}".format("and:", width=wnick), repr(nextline)) + extralines.append(nextline) + else: + msg = f"remains unmatched: {line!r}" + self._log(msg) + self._fail(msg) + self._log_output = [] + + def no_fnmatch_line(self, pat: str) -> None: + """Ensure captured lines do not match the given pattern, using ``fnmatch.fnmatch``. + + :param str pat: The pattern to match lines. + """ + __tracebackhide__ = True + self._no_match_line(pat, fnmatch, "fnmatch") + + def no_re_match_line(self, pat: str) -> None: + """Ensure captured lines do not match the given pattern, using ``re.match``. + + :param str pat: The regular expression to match lines. + """ + __tracebackhide__ = True + self._no_match_line( + pat, lambda name, pat: bool(re.match(pat, name)), "re.match" + ) + + def _no_match_line( + self, pat: str, match_func: Callable[[str, str], bool], match_nickname: str + ) -> None: + """Ensure captured lines does not have a the given pattern, using ``fnmatch.fnmatch``. + + :param str pat: The pattern to match lines. + """ + __tracebackhide__ = True + nomatch_printed = False + wnick = len(match_nickname) + 1 + for line in self.lines: + if match_func(line, pat): + msg = f"{match_nickname}: {pat!r}" + self._log(msg) + self._log("{:>{width}}".format("with:", width=wnick), repr(line)) + self._fail(msg) + else: + if not nomatch_printed: + self._log("{:>{width}}".format("nomatch:", width=wnick), repr(pat)) + nomatch_printed = True + self._log("{:>{width}}".format("and:", width=wnick), repr(line)) + self._log_output = [] + + def _fail(self, msg: str) -> None: + __tracebackhide__ = True + log_text = self._log_text + self._log_output = [] + fail(log_text) + + def str(self) -> str: + """Return the entire original text.""" + return str(self) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/pytester_assertions.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/pytester_assertions.py new file mode 100644 index 000000000..657e4db5f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/pytester_assertions.py @@ -0,0 +1,75 @@ +"""Helper plugin for pytester; should not be loaded on its own.""" +# This plugin contains assertions used by pytester. pytester cannot +# contain them itself, since it is imported by the `pytest` module, +# hence cannot be subject to assertion rewriting, which requires a +# module to not be already imported. +from typing import Dict +from typing import Optional +from typing import Sequence +from typing import Tuple +from typing import Union + +from _pytest.reports import CollectReport +from _pytest.reports import TestReport + + +def assertoutcome( + outcomes: Tuple[ + Sequence[TestReport], + Sequence[Union[CollectReport, TestReport]], + Sequence[Union[CollectReport, TestReport]], + ], + passed: int = 0, + skipped: int = 0, + failed: int = 0, +) -> None: + __tracebackhide__ = True + + realpassed, realskipped, realfailed = outcomes + obtained = { + "passed": len(realpassed), + "skipped": len(realskipped), + "failed": len(realfailed), + } + expected = {"passed": passed, "skipped": skipped, "failed": failed} + assert obtained == expected, outcomes + + +def assert_outcomes( + outcomes: Dict[str, int], + passed: int = 0, + skipped: int = 0, + failed: int = 0, + errors: int = 0, + xpassed: int = 0, + xfailed: int = 0, + warnings: Optional[int] = None, + deselected: Optional[int] = None, +) -> None: + """Assert that the specified outcomes appear with the respective + numbers (0 means it didn't occur) in the text output from a test run.""" + __tracebackhide__ = True + + obtained = { + "passed": outcomes.get("passed", 0), + "skipped": outcomes.get("skipped", 0), + "failed": outcomes.get("failed", 0), + "errors": outcomes.get("errors", 0), + "xpassed": outcomes.get("xpassed", 0), + "xfailed": outcomes.get("xfailed", 0), + } + expected = { + "passed": passed, + "skipped": skipped, + "failed": failed, + "errors": errors, + "xpassed": xpassed, + "xfailed": xfailed, + } + if warnings is not None: + obtained["warnings"] = outcomes.get("warnings", 0) + expected["warnings"] = warnings + if deselected is not None: + obtained["deselected"] = outcomes.get("deselected", 0) + expected["deselected"] = deselected + assert obtained == expected diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/python.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/python.py new file mode 100644 index 000000000..5f8be5d9b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/python.py @@ -0,0 +1,1843 @@ +"""Python test discovery, setup and run of test functions.""" +import dataclasses +import enum +import fnmatch +import inspect +import itertools +import os +import sys +import types +import warnings +from collections import Counter +from collections import defaultdict +from functools import partial +from pathlib import Path +from typing import Any +from typing import Callable +from typing import Dict +from typing import Generator +from typing import Iterable +from typing import Iterator +from typing import List +from typing import Mapping +from typing import Optional +from typing import Pattern +from typing import Sequence +from typing import Set +from typing import Tuple +from typing import TYPE_CHECKING +from typing import Union + +import _pytest +from _pytest import fixtures +from _pytest import nodes +from _pytest._code import filter_traceback +from _pytest._code import getfslineno +from _pytest._code.code import ExceptionInfo +from _pytest._code.code import TerminalRepr +from _pytest._code.code import Traceback +from _pytest._io import TerminalWriter +from _pytest._io.saferepr import saferepr +from _pytest.compat import ascii_escaped +from _pytest.compat import assert_never +from _pytest.compat import final +from _pytest.compat import get_default_arg_names +from _pytest.compat import get_real_func +from _pytest.compat import getimfunc +from _pytest.compat import getlocation +from _pytest.compat import is_async_function +from _pytest.compat import is_generator +from _pytest.compat import LEGACY_PATH +from _pytest.compat import NOTSET +from _pytest.compat import safe_getattr +from _pytest.compat import safe_isclass +from _pytest.compat import STRING_TYPES +from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config import hookimpl +from _pytest.config.argparsing import Parser +from _pytest.deprecated import check_ispytest +from _pytest.deprecated import INSTANCE_COLLECTOR +from _pytest.deprecated import NOSE_SUPPORT_METHOD +from _pytest.fixtures import FuncFixtureInfo +from _pytest.main import Session +from _pytest.mark import MARK_GEN +from _pytest.mark import ParameterSet +from _pytest.mark.structures import get_unpacked_marks +from _pytest.mark.structures import Mark +from _pytest.mark.structures import MarkDecorator +from _pytest.mark.structures import normalize_mark_list +from _pytest.outcomes import fail +from _pytest.outcomes import skip +from _pytest.pathlib import bestrelpath +from _pytest.pathlib import fnmatch_ex +from _pytest.pathlib import import_path +from _pytest.pathlib import ImportPathMismatchError +from _pytest.pathlib import parts +from _pytest.pathlib import visit +from _pytest.scope import Scope +from _pytest.warning_types import PytestCollectionWarning +from _pytest.warning_types import PytestReturnNotNoneWarning +from _pytest.warning_types import PytestUnhandledCoroutineWarning + +if TYPE_CHECKING: + from typing_extensions import Literal + + from _pytest.scope import _ScopeName + + +_PYTEST_DIR = Path(_pytest.__file__).parent + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("general") + group.addoption( + "--fixtures", + "--funcargs", + action="store_true", + dest="showfixtures", + default=False, + help="Show available fixtures, sorted by plugin appearance " + "(fixtures with leading '_' are only shown with '-v')", + ) + group.addoption( + "--fixtures-per-test", + action="store_true", + dest="show_fixtures_per_test", + default=False, + help="Show fixtures per test", + ) + parser.addini( + "python_files", + type="args", + # NOTE: default is also used in AssertionRewritingHook. + default=["test_*.py", "*_test.py"], + help="Glob-style file patterns for Python test module discovery", + ) + parser.addini( + "python_classes", + type="args", + default=["Test"], + help="Prefixes or glob names for Python test class discovery", + ) + parser.addini( + "python_functions", + type="args", + default=["test"], + help="Prefixes or glob names for Python test function and method discovery", + ) + parser.addini( + "disable_test_id_escaping_and_forfeit_all_rights_to_community_support", + type="bool", + default=False, + help="Disable string escape non-ASCII characters, might cause unwanted " + "side effects(use at your own risk)", + ) + + +def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]: + if config.option.showfixtures: + showfixtures(config) + return 0 + if config.option.show_fixtures_per_test: + show_fixtures_per_test(config) + return 0 + return None + + +def pytest_generate_tests(metafunc: "Metafunc") -> None: + for marker in metafunc.definition.iter_markers(name="parametrize"): + metafunc.parametrize(*marker.args, **marker.kwargs, _param_mark=marker) + + +def pytest_configure(config: Config) -> None: + config.addinivalue_line( + "markers", + "parametrize(argnames, argvalues): call a test function multiple " + "times passing in different arguments in turn. argvalues generally " + "needs to be a list of values if argnames specifies only one name " + "or a list of tuples of values if argnames specifies multiple names. " + "Example: @parametrize('arg1', [1,2]) would lead to two calls of the " + "decorated test function, one with arg1=1 and another with arg1=2." + "see https://docs.pytest.org/en/stable/how-to/parametrize.html for more info " + "and examples.", + ) + config.addinivalue_line( + "markers", + "usefixtures(fixturename1, fixturename2, ...): mark tests as needing " + "all of the specified fixtures. see " + "https://docs.pytest.org/en/stable/explanation/fixtures.html#usefixtures ", + ) + + +def async_warn_and_skip(nodeid: str) -> None: + msg = "async def functions are not natively supported and have been skipped.\n" + msg += ( + "You need to install a suitable plugin for your async framework, for example:\n" + ) + msg += " - anyio\n" + msg += " - pytest-asyncio\n" + msg += " - pytest-tornasync\n" + msg += " - pytest-trio\n" + msg += " - pytest-twisted" + warnings.warn(PytestUnhandledCoroutineWarning(msg.format(nodeid))) + skip(reason="async def function and no async plugin installed (see warnings)") + + +@hookimpl(trylast=True) +def pytest_pyfunc_call(pyfuncitem: "Function") -> Optional[object]: + testfunction = pyfuncitem.obj + if is_async_function(testfunction): + async_warn_and_skip(pyfuncitem.nodeid) + funcargs = pyfuncitem.funcargs + testargs = {arg: funcargs[arg] for arg in pyfuncitem._fixtureinfo.argnames} + result = testfunction(**testargs) + if hasattr(result, "__await__") or hasattr(result, "__aiter__"): + async_warn_and_skip(pyfuncitem.nodeid) + elif result is not None: + warnings.warn( + PytestReturnNotNoneWarning( + f"Expected None, but {pyfuncitem.nodeid} returned {result!r}, which will be an error in a " + "future version of pytest. Did you mean to use `assert` instead of `return`?" + ) + ) + return True + + +def pytest_collect_file(file_path: Path, parent: nodes.Collector) -> Optional["Module"]: + if file_path.suffix == ".py": + if not parent.session.isinitpath(file_path): + if not path_matches_patterns( + file_path, parent.config.getini("python_files") + ["__init__.py"] + ): + return None + ihook = parent.session.gethookproxy(file_path) + module: Module = ihook.pytest_pycollect_makemodule( + module_path=file_path, parent=parent + ) + return module + return None + + +def path_matches_patterns(path: Path, patterns: Iterable[str]) -> bool: + """Return whether path matches any of the patterns in the list of globs given.""" + return any(fnmatch_ex(pattern, path) for pattern in patterns) + + +def pytest_pycollect_makemodule(module_path: Path, parent) -> "Module": + if module_path.name == "__init__.py": + pkg: Package = Package.from_parent(parent, path=module_path) + return pkg + mod: Module = Module.from_parent(parent, path=module_path) + return mod + + +@hookimpl(trylast=True) +def pytest_pycollect_makeitem( + collector: Union["Module", "Class"], name: str, obj: object +) -> Union[None, nodes.Item, nodes.Collector, List[Union[nodes.Item, nodes.Collector]]]: + assert isinstance(collector, (Class, Module)), type(collector) + # Nothing was collected elsewhere, let's do it here. + if safe_isclass(obj): + if collector.istestclass(obj, name): + klass: Class = Class.from_parent(collector, name=name, obj=obj) + return klass + elif collector.istestfunction(obj, name): + # mock seems to store unbound methods (issue473), normalize it. + obj = getattr(obj, "__func__", obj) + # We need to try and unwrap the function if it's a functools.partial + # or a functools.wrapped. + # We mustn't if it's been wrapped with mock.patch (python 2 only). + if not (inspect.isfunction(obj) or inspect.isfunction(get_real_func(obj))): + filename, lineno = getfslineno(obj) + warnings.warn_explicit( + message=PytestCollectionWarning( + "cannot collect %r because it is not a function." % name + ), + category=None, + filename=str(filename), + lineno=lineno + 1, + ) + elif getattr(obj, "__test__", True): + if is_generator(obj): + res: Function = Function.from_parent(collector, name=name) + reason = "yield tests were removed in pytest 4.0 - {name} will be ignored".format( + name=name + ) + res.add_marker(MARK_GEN.xfail(run=False, reason=reason)) + res.warn(PytestCollectionWarning(reason)) + return res + else: + return list(collector._genfunctions(name, obj)) + return None + + +class PyobjMixin(nodes.Node): + """this mix-in inherits from Node to carry over the typing information + + as its intended to always mix in before a node + its position in the mro is unaffected""" + + _ALLOW_MARKERS = True + + @property + def module(self): + """Python module object this node was collected from (can be None).""" + node = self.getparent(Module) + return node.obj if node is not None else None + + @property + def cls(self): + """Python class object this node was collected from (can be None).""" + node = self.getparent(Class) + return node.obj if node is not None else None + + @property + def instance(self): + """Python instance object the function is bound to. + + Returns None if not a test method, e.g. for a standalone test function, + a staticmethod, a class or a module. + """ + node = self.getparent(Function) + return getattr(node.obj, "__self__", None) if node is not None else None + + @property + def obj(self): + """Underlying Python object.""" + obj = getattr(self, "_obj", None) + if obj is None: + self._obj = obj = self._getobj() + # XXX evil hack + # used to avoid Function marker duplication + if self._ALLOW_MARKERS: + self.own_markers.extend(get_unpacked_marks(self.obj)) + # This assumes that `obj` is called before there is a chance + # to add custom keys to `self.keywords`, so no fear of overriding. + self.keywords.update((mark.name, mark) for mark in self.own_markers) + return obj + + @obj.setter + def obj(self, value): + self._obj = value + + def _getobj(self): + """Get the underlying Python object. May be overwritten by subclasses.""" + # TODO: Improve the type of `parent` such that assert/ignore aren't needed. + assert self.parent is not None + obj = self.parent.obj # type: ignore[attr-defined] + return getattr(obj, self.name) + + def getmodpath(self, stopatmodule: bool = True, includemodule: bool = False) -> str: + """Return Python path relative to the containing module.""" + chain = self.listchain() + chain.reverse() + parts = [] + for node in chain: + name = node.name + if isinstance(node, Module): + name = os.path.splitext(name)[0] + if stopatmodule: + if includemodule: + parts.append(name) + break + parts.append(name) + parts.reverse() + return ".".join(parts) + + def reportinfo(self) -> Tuple[Union["os.PathLike[str]", str], Optional[int], str]: + # XXX caching? + obj = self.obj + compat_co_firstlineno = getattr(obj, "compat_co_firstlineno", None) + if isinstance(compat_co_firstlineno, int): + # nose compatibility + file_path = sys.modules[obj.__module__].__file__ + assert file_path is not None + if file_path.endswith(".pyc"): + file_path = file_path[:-1] + path: Union["os.PathLike[str]", str] = file_path + lineno = compat_co_firstlineno + else: + path, lineno = getfslineno(obj) + modpath = self.getmodpath() + assert isinstance(lineno, int) + return path, lineno, modpath + + +# As an optimization, these builtin attribute names are pre-ignored when +# iterating over an object during collection -- the pytest_pycollect_makeitem +# hook is not called for them. +# fmt: off +class _EmptyClass: pass # noqa: E701 +IGNORED_ATTRIBUTES = frozenset.union( # noqa: E305 + frozenset(), + # Module. + dir(types.ModuleType("empty_module")), + # Some extra module attributes the above doesn't catch. + {"__builtins__", "__file__", "__cached__"}, + # Class. + dir(_EmptyClass), + # Instance. + dir(_EmptyClass()), +) +del _EmptyClass +# fmt: on + + +class PyCollector(PyobjMixin, nodes.Collector): + def funcnamefilter(self, name: str) -> bool: + return self._matches_prefix_or_glob_option("python_functions", name) + + def isnosetest(self, obj: object) -> bool: + """Look for the __test__ attribute, which is applied by the + @nose.tools.istest decorator. + """ + # We explicitly check for "is True" here to not mistakenly treat + # classes with a custom __getattr__ returning something truthy (like a + # function) as test classes. + return safe_getattr(obj, "__test__", False) is True + + def classnamefilter(self, name: str) -> bool: + return self._matches_prefix_or_glob_option("python_classes", name) + + def istestfunction(self, obj: object, name: str) -> bool: + if self.funcnamefilter(name) or self.isnosetest(obj): + if isinstance(obj, (staticmethod, classmethod)): + # staticmethods and classmethods need to be unwrapped. + obj = safe_getattr(obj, "__func__", False) + return callable(obj) and fixtures.getfixturemarker(obj) is None + else: + return False + + def istestclass(self, obj: object, name: str) -> bool: + return self.classnamefilter(name) or self.isnosetest(obj) + + def _matches_prefix_or_glob_option(self, option_name: str, name: str) -> bool: + """Check if the given name matches the prefix or glob-pattern defined + in ini configuration.""" + for option in self.config.getini(option_name): + if name.startswith(option): + return True + # Check that name looks like a glob-string before calling fnmatch + # because this is called for every name in each collected module, + # and fnmatch is somewhat expensive to call. + elif ("*" in option or "?" in option or "[" in option) and fnmatch.fnmatch( + name, option + ): + return True + return False + + def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]: + if not getattr(self.obj, "__test__", True): + return [] + + # Avoid random getattrs and peek in the __dict__ instead. + dicts = [getattr(self.obj, "__dict__", {})] + if isinstance(self.obj, type): + for basecls in self.obj.__mro__: + dicts.append(basecls.__dict__) + + # In each class, nodes should be definition ordered. + # __dict__ is definition ordered. + seen: Set[str] = set() + dict_values: List[List[Union[nodes.Item, nodes.Collector]]] = [] + ihook = self.ihook + for dic in dicts: + values: List[Union[nodes.Item, nodes.Collector]] = [] + # Note: seems like the dict can change during iteration - + # be careful not to remove the list() without consideration. + for name, obj in list(dic.items()): + if name in IGNORED_ATTRIBUTES: + continue + if name in seen: + continue + seen.add(name) + res = ihook.pytest_pycollect_makeitem( + collector=self, name=name, obj=obj + ) + if res is None: + continue + elif isinstance(res, list): + values.extend(res) + else: + values.append(res) + dict_values.append(values) + + # Between classes in the class hierarchy, reverse-MRO order -- nodes + # inherited from base classes should come before subclasses. + result = [] + for values in reversed(dict_values): + result.extend(values) + return result + + def _genfunctions(self, name: str, funcobj) -> Iterator["Function"]: + modulecol = self.getparent(Module) + assert modulecol is not None + module = modulecol.obj + clscol = self.getparent(Class) + cls = clscol and clscol.obj or None + + definition = FunctionDefinition.from_parent(self, name=name, callobj=funcobj) + fixtureinfo = definition._fixtureinfo + + # pytest_generate_tests impls call metafunc.parametrize() which fills + # metafunc._calls, the outcome of the hook. + metafunc = Metafunc( + definition=definition, + fixtureinfo=fixtureinfo, + config=self.config, + cls=cls, + module=module, + _ispytest=True, + ) + methods = [] + if hasattr(module, "pytest_generate_tests"): + methods.append(module.pytest_generate_tests) + if cls is not None and hasattr(cls, "pytest_generate_tests"): + methods.append(cls().pytest_generate_tests) + self.ihook.pytest_generate_tests.call_extra(methods, dict(metafunc=metafunc)) + + if not metafunc._calls: + yield Function.from_parent(self, name=name, fixtureinfo=fixtureinfo) + else: + # Add funcargs() as fixturedefs to fixtureinfo.arg2fixturedefs. + fm = self.session._fixturemanager + fixtures.add_funcarg_pseudo_fixture_def(self, metafunc, fm) + + # Add_funcarg_pseudo_fixture_def may have shadowed some fixtures + # with direct parametrization, so make sure we update what the + # function really needs. + fixtureinfo.prune_dependency_tree() + + for callspec in metafunc._calls: + subname = f"{name}[{callspec.id}]" + yield Function.from_parent( + self, + name=subname, + callspec=callspec, + fixtureinfo=fixtureinfo, + keywords={callspec.id: True}, + originalname=name, + ) + + +class Module(nodes.File, PyCollector): + """Collector for test classes and functions in a Python module.""" + + def _getobj(self): + return self._importtestmodule() + + def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]: + self._inject_setup_module_fixture() + self._inject_setup_function_fixture() + self.session._fixturemanager.parsefactories(self) + return super().collect() + + def _inject_setup_module_fixture(self) -> None: + """Inject a hidden autouse, module scoped fixture into the collected module object + that invokes setUpModule/tearDownModule if either or both are available. + + Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with + other fixtures (#517). + """ + has_nose = self.config.pluginmanager.has_plugin("nose") + setup_module = _get_first_non_fixture_func( + self.obj, ("setUpModule", "setup_module") + ) + if setup_module is None and has_nose: + # The name "setup" is too common - only treat as fixture if callable. + setup_module = _get_first_non_fixture_func(self.obj, ("setup",)) + if not callable(setup_module): + setup_module = None + teardown_module = _get_first_non_fixture_func( + self.obj, ("tearDownModule", "teardown_module") + ) + if teardown_module is None and has_nose: + teardown_module = _get_first_non_fixture_func(self.obj, ("teardown",)) + # Same as "setup" above - only treat as fixture if callable. + if not callable(teardown_module): + teardown_module = None + + if setup_module is None and teardown_module is None: + return + + @fixtures.fixture( + autouse=True, + scope="module", + # Use a unique name to speed up lookup. + name=f"_xunit_setup_module_fixture_{self.obj.__name__}", + ) + def xunit_setup_module_fixture(request) -> Generator[None, None, None]: + if setup_module is not None: + _call_with_optional_argument(setup_module, request.module) + yield + if teardown_module is not None: + _call_with_optional_argument(teardown_module, request.module) + + self.obj.__pytest_setup_module = xunit_setup_module_fixture + + def _inject_setup_function_fixture(self) -> None: + """Inject a hidden autouse, function scoped fixture into the collected module object + that invokes setup_function/teardown_function if either or both are available. + + Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with + other fixtures (#517). + """ + setup_function = _get_first_non_fixture_func(self.obj, ("setup_function",)) + teardown_function = _get_first_non_fixture_func( + self.obj, ("teardown_function",) + ) + if setup_function is None and teardown_function is None: + return + + @fixtures.fixture( + autouse=True, + scope="function", + # Use a unique name to speed up lookup. + name=f"_xunit_setup_function_fixture_{self.obj.__name__}", + ) + def xunit_setup_function_fixture(request) -> Generator[None, None, None]: + if request.instance is not None: + # in this case we are bound to an instance, so we need to let + # setup_method handle this + yield + return + if setup_function is not None: + _call_with_optional_argument(setup_function, request.function) + yield + if teardown_function is not None: + _call_with_optional_argument(teardown_function, request.function) + + self.obj.__pytest_setup_function = xunit_setup_function_fixture + + def _importtestmodule(self): + # We assume we are only called once per module. + importmode = self.config.getoption("--import-mode") + try: + mod = import_path(self.path, mode=importmode, root=self.config.rootpath) + except SyntaxError as e: + raise self.CollectError( + ExceptionInfo.from_current().getrepr(style="short") + ) from e + except ImportPathMismatchError as e: + raise self.CollectError( + "import file mismatch:\n" + "imported module %r has this __file__ attribute:\n" + " %s\n" + "which is not the same as the test file we want to collect:\n" + " %s\n" + "HINT: remove __pycache__ / .pyc files and/or use a " + "unique basename for your test file modules" % e.args + ) from e + except ImportError as e: + exc_info = ExceptionInfo.from_current() + if self.config.getoption("verbose") < 2: + exc_info.traceback = exc_info.traceback.filter(filter_traceback) + exc_repr = ( + exc_info.getrepr(style="short") + if exc_info.traceback + else exc_info.exconly() + ) + formatted_tb = str(exc_repr) + raise self.CollectError( + "ImportError while importing test module '{path}'.\n" + "Hint: make sure your test modules/packages have valid Python names.\n" + "Traceback:\n" + "{traceback}".format(path=self.path, traceback=formatted_tb) + ) from e + except skip.Exception as e: + if e.allow_module_level: + raise + raise self.CollectError( + "Using pytest.skip outside of a test will skip the entire module. " + "If that's your intention, pass `allow_module_level=True`. " + "If you want to skip a specific test or an entire class, " + "use the @pytest.mark.skip or @pytest.mark.skipif decorators." + ) from e + self.config.pluginmanager.consider_module(mod) + return mod + + +class Package(Module): + """Collector for files and directories in a Python packages -- directories + with an `__init__.py` file.""" + + def __init__( + self, + fspath: Optional[LEGACY_PATH], + parent: nodes.Collector, + # NOTE: following args are unused: + config=None, + session=None, + nodeid=None, + path: Optional[Path] = None, + ) -> None: + # NOTE: Could be just the following, but kept as-is for compat. + # nodes.FSCollector.__init__(self, fspath, parent=parent) + session = parent.session + nodes.FSCollector.__init__( + self, + fspath=fspath, + path=path, + parent=parent, + config=config, + session=session, + nodeid=nodeid, + ) + self.name = self.path.parent.name + + def setup(self) -> None: + # Not using fixtures to call setup_module here because autouse fixtures + # from packages are not called automatically (#4085). + setup_module = _get_first_non_fixture_func( + self.obj, ("setUpModule", "setup_module") + ) + if setup_module is not None: + _call_with_optional_argument(setup_module, self.obj) + + teardown_module = _get_first_non_fixture_func( + self.obj, ("tearDownModule", "teardown_module") + ) + if teardown_module is not None: + func = partial(_call_with_optional_argument, teardown_module, self.obj) + self.addfinalizer(func) + + def _recurse(self, direntry: "os.DirEntry[str]") -> bool: + if direntry.name == "__pycache__": + return False + fspath = Path(direntry.path) + ihook = self.session.gethookproxy(fspath.parent) + if ihook.pytest_ignore_collect(collection_path=fspath, config=self.config): + return False + return True + + def _collectfile( + self, fspath: Path, handle_dupes: bool = True + ) -> Sequence[nodes.Collector]: + assert ( + fspath.is_file() + ), "{!r} is not a file (isdir={!r}, exists={!r}, islink={!r})".format( + fspath, fspath.is_dir(), fspath.exists(), fspath.is_symlink() + ) + ihook = self.session.gethookproxy(fspath) + if not self.session.isinitpath(fspath): + if ihook.pytest_ignore_collect(collection_path=fspath, config=self.config): + return () + + if handle_dupes: + keepduplicates = self.config.getoption("keepduplicates") + if not keepduplicates: + duplicate_paths = self.config.pluginmanager._duplicatepaths + if fspath in duplicate_paths: + return () + else: + duplicate_paths.add(fspath) + + return ihook.pytest_collect_file(file_path=fspath, parent=self) # type: ignore[no-any-return] + + def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]: + this_path = self.path.parent + + # Always collect the __init__ first. + if path_matches_patterns(self.path, self.config.getini("python_files")): + yield Module.from_parent(self, path=self.path) + + pkg_prefixes: Set[Path] = set() + for direntry in visit(str(this_path), recurse=self._recurse): + path = Path(direntry.path) + + # We will visit our own __init__.py file, in which case we skip it. + if direntry.is_file(): + if direntry.name == "__init__.py" and path.parent == this_path: + continue + + parts_ = parts(direntry.path) + if any( + str(pkg_prefix) in parts_ and pkg_prefix / "__init__.py" != path + for pkg_prefix in pkg_prefixes + ): + continue + + if direntry.is_file(): + yield from self._collectfile(path) + elif not direntry.is_dir(): + # Broken symlink or invalid/missing file. + continue + elif path.joinpath("__init__.py").is_file(): + pkg_prefixes.add(path) + + +def _call_with_optional_argument(func, arg) -> None: + """Call the given function with the given argument if func accepts one argument, otherwise + calls func without arguments.""" + arg_count = func.__code__.co_argcount + if inspect.ismethod(func): + arg_count -= 1 + if arg_count: + func(arg) + else: + func() + + +def _get_first_non_fixture_func(obj: object, names: Iterable[str]) -> Optional[object]: + """Return the attribute from the given object to be used as a setup/teardown + xunit-style function, but only if not marked as a fixture to avoid calling it twice. + """ + for name in names: + meth: Optional[object] = getattr(obj, name, None) + if meth is not None and fixtures.getfixturemarker(meth) is None: + return meth + return None + + +class Class(PyCollector): + """Collector for test methods (and nested classes) in a Python class.""" + + @classmethod + def from_parent(cls, parent, *, name, obj=None, **kw): + """The public constructor.""" + return super().from_parent(name=name, parent=parent, **kw) + + def newinstance(self): + return self.obj() + + def collect(self) -> Iterable[Union[nodes.Item, nodes.Collector]]: + if not safe_getattr(self.obj, "__test__", True): + return [] + if hasinit(self.obj): + assert self.parent is not None + self.warn( + PytestCollectionWarning( + "cannot collect test class %r because it has a " + "__init__ constructor (from: %s)" + % (self.obj.__name__, self.parent.nodeid) + ) + ) + return [] + elif hasnew(self.obj): + assert self.parent is not None + self.warn( + PytestCollectionWarning( + "cannot collect test class %r because it has a " + "__new__ constructor (from: %s)" + % (self.obj.__name__, self.parent.nodeid) + ) + ) + return [] + + self._inject_setup_class_fixture() + self._inject_setup_method_fixture() + + self.session._fixturemanager.parsefactories(self.newinstance(), self.nodeid) + + return super().collect() + + def _inject_setup_class_fixture(self) -> None: + """Inject a hidden autouse, class scoped fixture into the collected class object + that invokes setup_class/teardown_class if either or both are available. + + Using a fixture to invoke this methods ensures we play nicely and unsurprisingly with + other fixtures (#517). + """ + setup_class = _get_first_non_fixture_func(self.obj, ("setup_class",)) + teardown_class = _get_first_non_fixture_func(self.obj, ("teardown_class",)) + if setup_class is None and teardown_class is None: + return + + @fixtures.fixture( + autouse=True, + scope="class", + # Use a unique name to speed up lookup. + name=f"_xunit_setup_class_fixture_{self.obj.__qualname__}", + ) + def xunit_setup_class_fixture(cls) -> Generator[None, None, None]: + if setup_class is not None: + func = getimfunc(setup_class) + _call_with_optional_argument(func, self.obj) + yield + if teardown_class is not None: + func = getimfunc(teardown_class) + _call_with_optional_argument(func, self.obj) + + self.obj.__pytest_setup_class = xunit_setup_class_fixture + + def _inject_setup_method_fixture(self) -> None: + """Inject a hidden autouse, function scoped fixture into the collected class object + that invokes setup_method/teardown_method if either or both are available. + + Using a fixture to invoke these methods ensures we play nicely and unsurprisingly with + other fixtures (#517). + """ + has_nose = self.config.pluginmanager.has_plugin("nose") + setup_name = "setup_method" + setup_method = _get_first_non_fixture_func(self.obj, (setup_name,)) + emit_nose_setup_warning = False + if setup_method is None and has_nose: + setup_name = "setup" + emit_nose_setup_warning = True + setup_method = _get_first_non_fixture_func(self.obj, (setup_name,)) + teardown_name = "teardown_method" + teardown_method = _get_first_non_fixture_func(self.obj, (teardown_name,)) + emit_nose_teardown_warning = False + if teardown_method is None and has_nose: + teardown_name = "teardown" + emit_nose_teardown_warning = True + teardown_method = _get_first_non_fixture_func(self.obj, (teardown_name,)) + if setup_method is None and teardown_method is None: + return + + @fixtures.fixture( + autouse=True, + scope="function", + # Use a unique name to speed up lookup. + name=f"_xunit_setup_method_fixture_{self.obj.__qualname__}", + ) + def xunit_setup_method_fixture(self, request) -> Generator[None, None, None]: + method = request.function + if setup_method is not None: + func = getattr(self, setup_name) + _call_with_optional_argument(func, method) + if emit_nose_setup_warning: + warnings.warn( + NOSE_SUPPORT_METHOD.format( + nodeid=request.node.nodeid, method="setup" + ), + stacklevel=2, + ) + yield + if teardown_method is not None: + func = getattr(self, teardown_name) + _call_with_optional_argument(func, method) + if emit_nose_teardown_warning: + warnings.warn( + NOSE_SUPPORT_METHOD.format( + nodeid=request.node.nodeid, method="teardown" + ), + stacklevel=2, + ) + + self.obj.__pytest_setup_method = xunit_setup_method_fixture + + +class InstanceDummy: + """Instance used to be a node type between Class and Function. It has been + removed in pytest 7.0. Some plugins exist which reference `pytest.Instance` + only to ignore it; this dummy class keeps them working. This will be removed + in pytest 8.""" + + +def __getattr__(name: str) -> object: + if name == "Instance": + warnings.warn(INSTANCE_COLLECTOR, 2) + return InstanceDummy + raise AttributeError(f"module {__name__} has no attribute {name}") + + +def hasinit(obj: object) -> bool: + init: object = getattr(obj, "__init__", None) + if init: + return init != object.__init__ + return False + + +def hasnew(obj: object) -> bool: + new: object = getattr(obj, "__new__", None) + if new: + return new != object.__new__ + return False + + +@final +@dataclasses.dataclass(frozen=True) +class IdMaker: + """Make IDs for a parametrization.""" + + __slots__ = ( + "argnames", + "parametersets", + "idfn", + "ids", + "config", + "nodeid", + "func_name", + ) + + # The argnames of the parametrization. + argnames: Sequence[str] + # The ParameterSets of the parametrization. + parametersets: Sequence[ParameterSet] + # Optionally, a user-provided callable to make IDs for parameters in a + # ParameterSet. + idfn: Optional[Callable[[Any], Optional[object]]] + # Optionally, explicit IDs for ParameterSets by index. + ids: Optional[Sequence[Optional[object]]] + # Optionally, the pytest config. + # Used for controlling ASCII escaping, and for calling the + # :hook:`pytest_make_parametrize_id` hook. + config: Optional[Config] + # Optionally, the ID of the node being parametrized. + # Used only for clearer error messages. + nodeid: Optional[str] + # Optionally, the ID of the function being parametrized. + # Used only for clearer error messages. + func_name: Optional[str] + + def make_unique_parameterset_ids(self) -> List[str]: + """Make a unique identifier for each ParameterSet, that may be used to + identify the parametrization in a node ID. + + Format is -...-[counter], where prm_x_token is + - user-provided id, if given + - else an id derived from the value, applicable for certain types + - else + The counter suffix is appended only in case a string wouldn't be unique + otherwise. + """ + resolved_ids = list(self._resolve_ids()) + # All IDs must be unique! + if len(resolved_ids) != len(set(resolved_ids)): + # Record the number of occurrences of each ID. + id_counts = Counter(resolved_ids) + # Map the ID to its next suffix. + id_suffixes: Dict[str, int] = defaultdict(int) + # Suffix non-unique IDs to make them unique. + for index, id in enumerate(resolved_ids): + if id_counts[id] > 1: + resolved_ids[index] = f"{id}{id_suffixes[id]}" + id_suffixes[id] += 1 + return resolved_ids + + def _resolve_ids(self) -> Iterable[str]: + """Resolve IDs for all ParameterSets (may contain duplicates).""" + for idx, parameterset in enumerate(self.parametersets): + if parameterset.id is not None: + # ID provided directly - pytest.param(..., id="...") + yield parameterset.id + elif self.ids and idx < len(self.ids) and self.ids[idx] is not None: + # ID provided in the IDs list - parametrize(..., ids=[...]). + yield self._idval_from_value_required(self.ids[idx], idx) + else: + # ID not provided - generate it. + yield "-".join( + self._idval(val, argname, idx) + for val, argname in zip(parameterset.values, self.argnames) + ) + + def _idval(self, val: object, argname: str, idx: int) -> str: + """Make an ID for a parameter in a ParameterSet.""" + idval = self._idval_from_function(val, argname, idx) + if idval is not None: + return idval + idval = self._idval_from_hook(val, argname) + if idval is not None: + return idval + idval = self._idval_from_value(val) + if idval is not None: + return idval + return self._idval_from_argname(argname, idx) + + def _idval_from_function( + self, val: object, argname: str, idx: int + ) -> Optional[str]: + """Try to make an ID for a parameter in a ParameterSet using the + user-provided id callable, if given.""" + if self.idfn is None: + return None + try: + id = self.idfn(val) + except Exception as e: + prefix = f"{self.nodeid}: " if self.nodeid is not None else "" + msg = "error raised while trying to determine id of parameter '{}' at position {}" + msg = prefix + msg.format(argname, idx) + raise ValueError(msg) from e + if id is None: + return None + return self._idval_from_value(id) + + def _idval_from_hook(self, val: object, argname: str) -> Optional[str]: + """Try to make an ID for a parameter in a ParameterSet by calling the + :hook:`pytest_make_parametrize_id` hook.""" + if self.config: + id: Optional[str] = self.config.hook.pytest_make_parametrize_id( + config=self.config, val=val, argname=argname + ) + return id + return None + + def _idval_from_value(self, val: object) -> Optional[str]: + """Try to make an ID for a parameter in a ParameterSet from its value, + if the value type is supported.""" + if isinstance(val, STRING_TYPES): + return _ascii_escaped_by_config(val, self.config) + elif val is None or isinstance(val, (float, int, bool, complex)): + return str(val) + elif isinstance(val, Pattern): + return ascii_escaped(val.pattern) + elif val is NOTSET: + # Fallback to default. Note that NOTSET is an enum.Enum. + pass + elif isinstance(val, enum.Enum): + return str(val) + elif isinstance(getattr(val, "__name__", None), str): + # Name of a class, function, module, etc. + name: str = getattr(val, "__name__") + return name + return None + + def _idval_from_value_required(self, val: object, idx: int) -> str: + """Like _idval_from_value(), but fails if the type is not supported.""" + id = self._idval_from_value(val) + if id is not None: + return id + + # Fail. + if self.func_name is not None: + prefix = f"In {self.func_name}: " + elif self.nodeid is not None: + prefix = f"In {self.nodeid}: " + else: + prefix = "" + msg = ( + f"{prefix}ids contains unsupported value {saferepr(val)} (type: {type(val)!r}) at index {idx}. " + "Supported types are: str, bytes, int, float, complex, bool, enum, regex or anything with a __name__." + ) + fail(msg, pytrace=False) + + @staticmethod + def _idval_from_argname(argname: str, idx: int) -> str: + """Make an ID for a parameter in a ParameterSet from the argument name + and the index of the ParameterSet.""" + return str(argname) + str(idx) + + +@final +@dataclasses.dataclass(frozen=True) +class CallSpec2: + """A planned parameterized invocation of a test function. + + Calculated during collection for a given test function's Metafunc. + Once collection is over, each callspec is turned into a single Item + and stored in item.callspec. + """ + + # arg name -> arg value which will be passed to the parametrized test + # function (direct parameterization). + funcargs: Dict[str, object] = dataclasses.field(default_factory=dict) + # arg name -> arg value which will be passed to a fixture of the same name + # (indirect parametrization). + params: Dict[str, object] = dataclasses.field(default_factory=dict) + # arg name -> arg index. + indices: Dict[str, int] = dataclasses.field(default_factory=dict) + # Used for sorting parametrized resources. + _arg2scope: Dict[str, Scope] = dataclasses.field(default_factory=dict) + # Parts which will be added to the item's name in `[..]` separated by "-". + _idlist: List[str] = dataclasses.field(default_factory=list) + # Marks which will be applied to the item. + marks: List[Mark] = dataclasses.field(default_factory=list) + + def setmulti( + self, + *, + valtypes: Mapping[str, "Literal['params', 'funcargs']"], + argnames: Iterable[str], + valset: Iterable[object], + id: str, + marks: Iterable[Union[Mark, MarkDecorator]], + scope: Scope, + param_index: int, + ) -> "CallSpec2": + funcargs = self.funcargs.copy() + params = self.params.copy() + indices = self.indices.copy() + arg2scope = self._arg2scope.copy() + for arg, val in zip(argnames, valset): + if arg in params or arg in funcargs: + raise ValueError(f"duplicate parametrization of {arg!r}") + valtype_for_arg = valtypes[arg] + if valtype_for_arg == "params": + params[arg] = val + elif valtype_for_arg == "funcargs": + funcargs[arg] = val + else: + assert_never(valtype_for_arg) + indices[arg] = param_index + arg2scope[arg] = scope + return CallSpec2( + funcargs=funcargs, + params=params, + indices=indices, + _arg2scope=arg2scope, + _idlist=[*self._idlist, id], + marks=[*self.marks, *normalize_mark_list(marks)], + ) + + def getparam(self, name: str) -> object: + try: + return self.params[name] + except KeyError as e: + raise ValueError(name) from e + + @property + def id(self) -> str: + return "-".join(self._idlist) + + +@final +class Metafunc: + """Objects passed to the :hook:`pytest_generate_tests` hook. + + They help to inspect a test function and to generate tests according to + test configuration or values specified in the class or module where a + test function is defined. + """ + + def __init__( + self, + definition: "FunctionDefinition", + fixtureinfo: fixtures.FuncFixtureInfo, + config: Config, + cls=None, + module=None, + *, + _ispytest: bool = False, + ) -> None: + check_ispytest(_ispytest) + + #: Access to the underlying :class:`_pytest.python.FunctionDefinition`. + self.definition = definition + + #: Access to the :class:`pytest.Config` object for the test session. + self.config = config + + #: The module object where the test function is defined in. + self.module = module + + #: Underlying Python test function. + self.function = definition.obj + + #: Set of fixture names required by the test function. + self.fixturenames = fixtureinfo.names_closure + + #: Class object where the test function is defined in or ``None``. + self.cls = cls + + self._arg2fixturedefs = fixtureinfo.name2fixturedefs + + # Result of parametrize(). + self._calls: List[CallSpec2] = [] + + def parametrize( + self, + argnames: Union[str, Sequence[str]], + argvalues: Iterable[Union[ParameterSet, Sequence[object], object]], + indirect: Union[bool, Sequence[str]] = False, + ids: Optional[ + Union[Iterable[Optional[object]], Callable[[Any], Optional[object]]] + ] = None, + scope: "Optional[_ScopeName]" = None, + *, + _param_mark: Optional[Mark] = None, + ) -> None: + """Add new invocations to the underlying test function using the list + of argvalues for the given argnames. Parametrization is performed + during the collection phase. If you need to setup expensive resources + see about setting indirect to do it rather than at test setup time. + + Can be called multiple times per test function (but only on different + argument names), in which case each call parametrizes all previous + parametrizations, e.g. + + :: + + unparametrized: t + parametrize ["x", "y"]: t[x], t[y] + parametrize [1, 2]: t[x-1], t[x-2], t[y-1], t[y-2] + + :param argnames: + A comma-separated string denoting one or more argument names, or + a list/tuple of argument strings. + + :param argvalues: + The list of argvalues determines how often a test is invoked with + different argument values. + + If only one argname was specified argvalues is a list of values. + If N argnames were specified, argvalues must be a list of + N-tuples, where each tuple-element specifies a value for its + respective argname. + + :param indirect: + A list of arguments' names (subset of argnames) or a boolean. + If True the list contains all names from the argnames. Each + argvalue corresponding to an argname in this list will + be passed as request.param to its respective argname fixture + function so that it can perform more expensive setups during the + setup phase of a test rather than at collection time. + + :param ids: + Sequence of (or generator for) ids for ``argvalues``, + or a callable to return part of the id for each argvalue. + + With sequences (and generators like ``itertools.count()``) the + returned ids should be of type ``string``, ``int``, ``float``, + ``bool``, or ``None``. + They are mapped to the corresponding index in ``argvalues``. + ``None`` means to use the auto-generated id. + + If it is a callable it will be called for each entry in + ``argvalues``, and the return value is used as part of the + auto-generated id for the whole set (where parts are joined with + dashes ("-")). + This is useful to provide more specific ids for certain items, e.g. + dates. Returning ``None`` will use an auto-generated id. + + If no ids are provided they will be generated automatically from + the argvalues. + + :param scope: + If specified it denotes the scope of the parameters. + The scope is used for grouping tests by parameter instances. + It will also override any fixture-function defined scope, allowing + to set a dynamic scope using test context or configuration. + """ + argnames, parametersets = ParameterSet._for_parametrize( + argnames, + argvalues, + self.function, + self.config, + nodeid=self.definition.nodeid, + ) + del argvalues + + if "request" in argnames: + fail( + "'request' is a reserved name and cannot be used in @pytest.mark.parametrize", + pytrace=False, + ) + + if scope is not None: + scope_ = Scope.from_user( + scope, descr=f"parametrize() call in {self.function.__name__}" + ) + else: + scope_ = _find_parametrized_scope(argnames, self._arg2fixturedefs, indirect) + + self._validate_if_using_arg_names(argnames, indirect) + + arg_values_types = self._resolve_arg_value_types(argnames, indirect) + + # Use any already (possibly) generated ids with parametrize Marks. + if _param_mark and _param_mark._param_ids_from: + generated_ids = _param_mark._param_ids_from._param_ids_generated + if generated_ids is not None: + ids = generated_ids + + ids = self._resolve_parameter_set_ids( + argnames, ids, parametersets, nodeid=self.definition.nodeid + ) + + # Store used (possibly generated) ids with parametrize Marks. + if _param_mark and _param_mark._param_ids_from and generated_ids is None: + object.__setattr__(_param_mark._param_ids_from, "_param_ids_generated", ids) + + # Create the new calls: if we are parametrize() multiple times (by applying the decorator + # more than once) then we accumulate those calls generating the cartesian product + # of all calls. + newcalls = [] + for callspec in self._calls or [CallSpec2()]: + for param_index, (param_id, param_set) in enumerate( + zip(ids, parametersets) + ): + newcallspec = callspec.setmulti( + valtypes=arg_values_types, + argnames=argnames, + valset=param_set.values, + id=param_id, + marks=param_set.marks, + scope=scope_, + param_index=param_index, + ) + newcalls.append(newcallspec) + self._calls = newcalls + + def _resolve_parameter_set_ids( + self, + argnames: Sequence[str], + ids: Optional[ + Union[Iterable[Optional[object]], Callable[[Any], Optional[object]]] + ], + parametersets: Sequence[ParameterSet], + nodeid: str, + ) -> List[str]: + """Resolve the actual ids for the given parameter sets. + + :param argnames: + Argument names passed to ``parametrize()``. + :param ids: + The `ids` parameter of the ``parametrize()`` call (see docs). + :param parametersets: + The parameter sets, each containing a set of values corresponding + to ``argnames``. + :param nodeid str: + The nodeid of the definition item that generated this + parametrization. + :returns: + List with ids for each parameter set given. + """ + if ids is None: + idfn = None + ids_ = None + elif callable(ids): + idfn = ids + ids_ = None + else: + idfn = None + ids_ = self._validate_ids(ids, parametersets, self.function.__name__) + id_maker = IdMaker( + argnames, + parametersets, + idfn, + ids_, + self.config, + nodeid=nodeid, + func_name=self.function.__name__, + ) + return id_maker.make_unique_parameterset_ids() + + def _validate_ids( + self, + ids: Iterable[Optional[object]], + parametersets: Sequence[ParameterSet], + func_name: str, + ) -> List[Optional[object]]: + try: + num_ids = len(ids) # type: ignore[arg-type] + except TypeError: + try: + iter(ids) + except TypeError as e: + raise TypeError("ids must be a callable or an iterable") from e + num_ids = len(parametersets) + + # num_ids == 0 is a special case: https://github.com/pytest-dev/pytest/issues/1849 + if num_ids != len(parametersets) and num_ids != 0: + msg = "In {}: {} parameter sets specified, with different number of ids: {}" + fail(msg.format(func_name, len(parametersets), num_ids), pytrace=False) + + return list(itertools.islice(ids, num_ids)) + + def _resolve_arg_value_types( + self, + argnames: Sequence[str], + indirect: Union[bool, Sequence[str]], + ) -> Dict[str, "Literal['params', 'funcargs']"]: + """Resolve if each parametrized argument must be considered a + parameter to a fixture or a "funcarg" to the function, based on the + ``indirect`` parameter of the parametrized() call. + + :param List[str] argnames: List of argument names passed to ``parametrize()``. + :param indirect: Same as the ``indirect`` parameter of ``parametrize()``. + :rtype: Dict[str, str] + A dict mapping each arg name to either: + * "params" if the argname should be the parameter of a fixture of the same name. + * "funcargs" if the argname should be a parameter to the parametrized test function. + """ + if isinstance(indirect, bool): + valtypes: Dict[str, Literal["params", "funcargs"]] = dict.fromkeys( + argnames, "params" if indirect else "funcargs" + ) + elif isinstance(indirect, Sequence): + valtypes = dict.fromkeys(argnames, "funcargs") + for arg in indirect: + if arg not in argnames: + fail( + "In {}: indirect fixture '{}' doesn't exist".format( + self.function.__name__, arg + ), + pytrace=False, + ) + valtypes[arg] = "params" + else: + fail( + "In {func}: expected Sequence or boolean for indirect, got {type}".format( + type=type(indirect).__name__, func=self.function.__name__ + ), + pytrace=False, + ) + return valtypes + + def _validate_if_using_arg_names( + self, + argnames: Sequence[str], + indirect: Union[bool, Sequence[str]], + ) -> None: + """Check if all argnames are being used, by default values, or directly/indirectly. + + :param List[str] argnames: List of argument names passed to ``parametrize()``. + :param indirect: Same as the ``indirect`` parameter of ``parametrize()``. + :raises ValueError: If validation fails. + """ + default_arg_names = set(get_default_arg_names(self.function)) + func_name = self.function.__name__ + for arg in argnames: + if arg not in self.fixturenames: + if arg in default_arg_names: + fail( + "In {}: function already takes an argument '{}' with a default value".format( + func_name, arg + ), + pytrace=False, + ) + else: + if isinstance(indirect, Sequence): + name = "fixture" if arg in indirect else "argument" + else: + name = "fixture" if indirect else "argument" + fail( + f"In {func_name}: function uses no {name} '{arg}'", + pytrace=False, + ) + + +def _find_parametrized_scope( + argnames: Sequence[str], + arg2fixturedefs: Mapping[str, Sequence[fixtures.FixtureDef[object]]], + indirect: Union[bool, Sequence[str]], +) -> Scope: + """Find the most appropriate scope for a parametrized call based on its arguments. + + When there's at least one direct argument, always use "function" scope. + + When a test function is parametrized and all its arguments are indirect + (e.g. fixtures), return the most narrow scope based on the fixtures used. + + Related to issue #1832, based on code posted by @Kingdread. + """ + if isinstance(indirect, Sequence): + all_arguments_are_fixtures = len(indirect) == len(argnames) + else: + all_arguments_are_fixtures = bool(indirect) + + if all_arguments_are_fixtures: + fixturedefs = arg2fixturedefs or {} + used_scopes = [ + fixturedef[0]._scope + for name, fixturedef in fixturedefs.items() + if name in argnames + ] + # Takes the most narrow scope from used fixtures. + return min(used_scopes, default=Scope.Function) + + return Scope.Function + + +def _ascii_escaped_by_config(val: Union[str, bytes], config: Optional[Config]) -> str: + if config is None: + escape_option = False + else: + escape_option = config.getini( + "disable_test_id_escaping_and_forfeit_all_rights_to_community_support" + ) + # TODO: If escaping is turned off and the user passes bytes, + # will return a bytes. For now we ignore this but the + # code *probably* doesn't handle this case. + return val if escape_option else ascii_escaped(val) # type: ignore + + +def _pretty_fixture_path(func) -> str: + cwd = Path.cwd() + loc = Path(getlocation(func, str(cwd))) + prefix = Path("...", "_pytest") + try: + return str(prefix / loc.relative_to(_PYTEST_DIR)) + except ValueError: + return bestrelpath(cwd, loc) + + +def show_fixtures_per_test(config): + from _pytest.main import wrap_session + + return wrap_session(config, _show_fixtures_per_test) + + +def _show_fixtures_per_test(config: Config, session: Session) -> None: + import _pytest.config + + session.perform_collect() + curdir = Path.cwd() + tw = _pytest.config.create_terminal_writer(config) + verbose = config.getvalue("verbose") + + def get_best_relpath(func) -> str: + loc = getlocation(func, str(curdir)) + return bestrelpath(curdir, Path(loc)) + + def write_fixture(fixture_def: fixtures.FixtureDef[object]) -> None: + argname = fixture_def.argname + if verbose <= 0 and argname.startswith("_"): + return + prettypath = _pretty_fixture_path(fixture_def.func) + tw.write(f"{argname}", green=True) + tw.write(f" -- {prettypath}", yellow=True) + tw.write("\n") + fixture_doc = inspect.getdoc(fixture_def.func) + if fixture_doc: + write_docstring( + tw, fixture_doc.split("\n\n")[0] if verbose <= 0 else fixture_doc + ) + else: + tw.line(" no docstring available", red=True) + + def write_item(item: nodes.Item) -> None: + # Not all items have _fixtureinfo attribute. + info: Optional[FuncFixtureInfo] = getattr(item, "_fixtureinfo", None) + if info is None or not info.name2fixturedefs: + # This test item does not use any fixtures. + return + tw.line() + tw.sep("-", f"fixtures used by {item.name}") + # TODO: Fix this type ignore. + tw.sep("-", f"({get_best_relpath(item.function)})") # type: ignore[attr-defined] + # dict key not used in loop but needed for sorting. + for _, fixturedefs in sorted(info.name2fixturedefs.items()): + assert fixturedefs is not None + if not fixturedefs: + continue + # Last item is expected to be the one used by the test item. + write_fixture(fixturedefs[-1]) + + for session_item in session.items: + write_item(session_item) + + +def showfixtures(config: Config) -> Union[int, ExitCode]: + from _pytest.main import wrap_session + + return wrap_session(config, _showfixtures_main) + + +def _showfixtures_main(config: Config, session: Session) -> None: + import _pytest.config + + session.perform_collect() + curdir = Path.cwd() + tw = _pytest.config.create_terminal_writer(config) + verbose = config.getvalue("verbose") + + fm = session._fixturemanager + + available = [] + seen: Set[Tuple[str, str]] = set() + + for argname, fixturedefs in fm._arg2fixturedefs.items(): + assert fixturedefs is not None + if not fixturedefs: + continue + for fixturedef in fixturedefs: + loc = getlocation(fixturedef.func, str(curdir)) + if (fixturedef.argname, loc) in seen: + continue + seen.add((fixturedef.argname, loc)) + available.append( + ( + len(fixturedef.baseid), + fixturedef.func.__module__, + _pretty_fixture_path(fixturedef.func), + fixturedef.argname, + fixturedef, + ) + ) + + available.sort() + currentmodule = None + for baseid, module, prettypath, argname, fixturedef in available: + if currentmodule != module: + if not module.startswith("_pytest."): + tw.line() + tw.sep("-", f"fixtures defined from {module}") + currentmodule = module + if verbose <= 0 and argname.startswith("_"): + continue + tw.write(f"{argname}", green=True) + if fixturedef.scope != "function": + tw.write(" [%s scope]" % fixturedef.scope, cyan=True) + tw.write(f" -- {prettypath}", yellow=True) + tw.write("\n") + doc = inspect.getdoc(fixturedef.func) + if doc: + write_docstring(tw, doc.split("\n\n")[0] if verbose <= 0 else doc) + else: + tw.line(" no docstring available", red=True) + tw.line() + + +def write_docstring(tw: TerminalWriter, doc: str, indent: str = " ") -> None: + for line in doc.split("\n"): + tw.line(indent + line) + + +class Function(PyobjMixin, nodes.Item): + """Item responsible for setting up and executing a Python test function. + + :param name: + The full function name, including any decorations like those + added by parametrization (``my_func[my_param]``). + :param parent: + The parent Node. + :param config: + The pytest Config object. + :param callspec: + If given, this is function has been parametrized and the callspec contains + meta information about the parametrization. + :param callobj: + If given, the object which will be called when the Function is invoked, + otherwise the callobj will be obtained from ``parent`` using ``originalname``. + :param keywords: + Keywords bound to the function object for "-k" matching. + :param session: + The pytest Session object. + :param fixtureinfo: + Fixture information already resolved at this fixture node.. + :param originalname: + The attribute name to use for accessing the underlying function object. + Defaults to ``name``. Set this if name is different from the original name, + for example when it contains decorations like those added by parametrization + (``my_func[my_param]``). + """ + + # Disable since functions handle it themselves. + _ALLOW_MARKERS = False + + def __init__( + self, + name: str, + parent, + config: Optional[Config] = None, + callspec: Optional[CallSpec2] = None, + callobj=NOTSET, + keywords: Optional[Mapping[str, Any]] = None, + session: Optional[Session] = None, + fixtureinfo: Optional[FuncFixtureInfo] = None, + originalname: Optional[str] = None, + ) -> None: + super().__init__(name, parent, config=config, session=session) + + if callobj is not NOTSET: + self.obj = callobj + + #: Original function name, without any decorations (for example + #: parametrization adds a ``"[...]"`` suffix to function names), used to access + #: the underlying function object from ``parent`` (in case ``callobj`` is not given + #: explicitly). + #: + #: .. versionadded:: 3.0 + self.originalname = originalname or name + + # Note: when FunctionDefinition is introduced, we should change ``originalname`` + # to a readonly property that returns FunctionDefinition.name. + + self.own_markers.extend(get_unpacked_marks(self.obj)) + if callspec: + self.callspec = callspec + self.own_markers.extend(callspec.marks) + + # todo: this is a hell of a hack + # https://github.com/pytest-dev/pytest/issues/4569 + # Note: the order of the updates is important here; indicates what + # takes priority (ctor argument over function attributes over markers). + # Take own_markers only; NodeKeywords handles parent traversal on its own. + self.keywords.update((mark.name, mark) for mark in self.own_markers) + self.keywords.update(self.obj.__dict__) + if keywords: + self.keywords.update(keywords) + + if fixtureinfo is None: + fixtureinfo = self.session._fixturemanager.getfixtureinfo( + self, self.obj, self.cls, funcargs=True + ) + self._fixtureinfo: FuncFixtureInfo = fixtureinfo + self.fixturenames = fixtureinfo.names_closure + self._initrequest() + + @classmethod + def from_parent(cls, parent, **kw): # todo: determine sound type limitations + """The public constructor.""" + return super().from_parent(parent=parent, **kw) + + def _initrequest(self) -> None: + self.funcargs: Dict[str, object] = {} + self._request = fixtures.FixtureRequest(self, _ispytest=True) + + @property + def function(self): + """Underlying python 'function' object.""" + return getimfunc(self.obj) + + def _getobj(self): + assert self.parent is not None + if isinstance(self.parent, Class): + # Each Function gets a fresh class instance. + parent_obj = self.parent.newinstance() + else: + parent_obj = self.parent.obj # type: ignore[attr-defined] + return getattr(parent_obj, self.originalname) + + @property + def _pyfuncitem(self): + """(compatonly) for code expecting pytest-2.2 style request objects.""" + return self + + def runtest(self) -> None: + """Execute the underlying test function.""" + self.ihook.pytest_pyfunc_call(pyfuncitem=self) + + def setup(self) -> None: + self._request._fillfixtures() + + def _traceback_filter(self, excinfo: ExceptionInfo[BaseException]) -> Traceback: + if hasattr(self, "_obj") and not self.config.getoption("fulltrace", False): + code = _pytest._code.Code.from_function(get_real_func(self.obj)) + path, firstlineno = code.path, code.firstlineno + traceback = excinfo.traceback + ntraceback = traceback.cut(path=path, firstlineno=firstlineno) + if ntraceback == traceback: + ntraceback = ntraceback.cut(path=path) + if ntraceback == traceback: + ntraceback = ntraceback.filter(filter_traceback) + if not ntraceback: + ntraceback = traceback + ntraceback = ntraceback.filter(excinfo) + + # issue364: mark all but first and last frames to + # only show a single-line message for each frame. + if self.config.getoption("tbstyle", "auto") == "auto": + if len(ntraceback) > 2: + ntraceback = Traceback( + entry + if i == 0 or i == len(ntraceback) - 1 + else entry.with_repr_style("short") + for i, entry in enumerate(ntraceback) + ) + + return ntraceback + return excinfo.traceback + + # TODO: Type ignored -- breaks Liskov Substitution. + def repr_failure( # type: ignore[override] + self, + excinfo: ExceptionInfo[BaseException], + ) -> Union[str, TerminalRepr]: + style = self.config.getoption("tbstyle", "auto") + if style == "auto": + style = "long" + return self._repr_failure_py(excinfo, style=style) + + +class FunctionDefinition(Function): + """This class is a stop gap solution until we evolve to have actual function + definition nodes and manage to get rid of ``metafunc``.""" + + def runtest(self) -> None: + raise RuntimeError("function definitions are not supposed to be run as tests") + + setup = runtest diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/python_api.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/python_api.py new file mode 100644 index 000000000..183356100 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/python_api.py @@ -0,0 +1,996 @@ +import math +import pprint +from collections.abc import Collection +from collections.abc import Sized +from decimal import Decimal +from numbers import Complex +from types import TracebackType +from typing import Any +from typing import Callable +from typing import cast +from typing import ContextManager +from typing import List +from typing import Mapping +from typing import Optional +from typing import Pattern +from typing import Sequence +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import TypeVar +from typing import Union + +if TYPE_CHECKING: + from numpy import ndarray + + +import _pytest._code +from _pytest.compat import final +from _pytest.compat import STRING_TYPES +from _pytest.compat import overload +from _pytest.outcomes import fail + + +def _non_numeric_type_error(value, at: Optional[str]) -> TypeError: + at_str = f" at {at}" if at else "" + return TypeError( + "cannot make approximate comparisons to non-numeric values: {!r} {}".format( + value, at_str + ) + ) + + +def _compare_approx( + full_object: object, + message_data: Sequence[Tuple[str, str, str]], + number_of_elements: int, + different_ids: Sequence[object], + max_abs_diff: float, + max_rel_diff: float, +) -> List[str]: + message_list = list(message_data) + message_list.insert(0, ("Index", "Obtained", "Expected")) + max_sizes = [0, 0, 0] + for index, obtained, expected in message_list: + max_sizes[0] = max(max_sizes[0], len(index)) + max_sizes[1] = max(max_sizes[1], len(obtained)) + max_sizes[2] = max(max_sizes[2], len(expected)) + explanation = [ + f"comparison failed. Mismatched elements: {len(different_ids)} / {number_of_elements}:", + f"Max absolute difference: {max_abs_diff}", + f"Max relative difference: {max_rel_diff}", + ] + [ + f"{indexes:<{max_sizes[0]}} | {obtained:<{max_sizes[1]}} | {expected:<{max_sizes[2]}}" + for indexes, obtained, expected in message_list + ] + return explanation + + +# builtin pytest.approx helper + + +class ApproxBase: + """Provide shared utilities for making approximate comparisons between + numbers or sequences of numbers.""" + + # Tell numpy to use our `__eq__` operator instead of its. + __array_ufunc__ = None + __array_priority__ = 100 + + def __init__(self, expected, rel=None, abs=None, nan_ok: bool = False) -> None: + __tracebackhide__ = True + self.expected = expected + self.abs = abs + self.rel = rel + self.nan_ok = nan_ok + self._check_type() + + def __repr__(self) -> str: + raise NotImplementedError + + def _repr_compare(self, other_side: Any) -> List[str]: + return [ + "comparison failed", + f"Obtained: {other_side}", + f"Expected: {self}", + ] + + def __eq__(self, actual) -> bool: + return all( + a == self._approx_scalar(x) for a, x in self._yield_comparisons(actual) + ) + + def __bool__(self): + __tracebackhide__ = True + raise AssertionError( + "approx() is not supported in a boolean context.\nDid you mean: `assert a == approx(b)`?" + ) + + # Ignore type because of https://github.com/python/mypy/issues/4266. + __hash__ = None # type: ignore + + def __ne__(self, actual) -> bool: + return not (actual == self) + + def _approx_scalar(self, x) -> "ApproxScalar": + if isinstance(x, Decimal): + return ApproxDecimal(x, rel=self.rel, abs=self.abs, nan_ok=self.nan_ok) + return ApproxScalar(x, rel=self.rel, abs=self.abs, nan_ok=self.nan_ok) + + def _yield_comparisons(self, actual): + """Yield all the pairs of numbers to be compared. + + This is used to implement the `__eq__` method. + """ + raise NotImplementedError + + def _check_type(self) -> None: + """Raise a TypeError if the expected value is not a valid type.""" + # This is only a concern if the expected value is a sequence. In every + # other case, the approx() function ensures that the expected value has + # a numeric type. For this reason, the default is to do nothing. The + # classes that deal with sequences should reimplement this method to + # raise if there are any non-numeric elements in the sequence. + + +def _recursive_sequence_map(f, x): + """Recursively map a function over a sequence of arbitrary depth""" + if isinstance(x, (list, tuple)): + seq_type = type(x) + return seq_type(_recursive_sequence_map(f, xi) for xi in x) + else: + return f(x) + + +class ApproxNumpy(ApproxBase): + """Perform approximate comparisons where the expected value is numpy array.""" + + def __repr__(self) -> str: + list_scalars = _recursive_sequence_map( + self._approx_scalar, self.expected.tolist() + ) + return f"approx({list_scalars!r})" + + def _repr_compare(self, other_side: "ndarray") -> List[str]: + import itertools + import math + + def get_value_from_nested_list( + nested_list: List[Any], nd_index: Tuple[Any, ...] + ) -> Any: + """ + Helper function to get the value out of a nested list, given an n-dimensional index. + This mimics numpy's indexing, but for raw nested python lists. + """ + value: Any = nested_list + for i in nd_index: + value = value[i] + return value + + np_array_shape = self.expected.shape + approx_side_as_seq = _recursive_sequence_map( + self._approx_scalar, self.expected.tolist() + ) + + if np_array_shape != other_side.shape: + return [ + "Impossible to compare arrays with different shapes.", + f"Shapes: {np_array_shape} and {other_side.shape}", + ] + + number_of_elements = self.expected.size + max_abs_diff = -math.inf + max_rel_diff = -math.inf + different_ids = [] + for index in itertools.product(*(range(i) for i in np_array_shape)): + approx_value = get_value_from_nested_list(approx_side_as_seq, index) + other_value = get_value_from_nested_list(other_side, index) + if approx_value != other_value: + abs_diff = abs(approx_value.expected - other_value) + max_abs_diff = max(max_abs_diff, abs_diff) + if other_value == 0.0: + max_rel_diff = math.inf + else: + max_rel_diff = max(max_rel_diff, abs_diff / abs(other_value)) + different_ids.append(index) + + message_data = [ + ( + str(index), + str(get_value_from_nested_list(other_side, index)), + str(get_value_from_nested_list(approx_side_as_seq, index)), + ) + for index in different_ids + ] + return _compare_approx( + self.expected, + message_data, + number_of_elements, + different_ids, + max_abs_diff, + max_rel_diff, + ) + + def __eq__(self, actual) -> bool: + import numpy as np + + # self.expected is supposed to always be an array here. + + if not np.isscalar(actual): + try: + actual = np.asarray(actual) + except Exception as e: + raise TypeError(f"cannot compare '{actual}' to numpy.ndarray") from e + + if not np.isscalar(actual) and actual.shape != self.expected.shape: + return False + + return super().__eq__(actual) + + def _yield_comparisons(self, actual): + import numpy as np + + # `actual` can either be a numpy array or a scalar, it is treated in + # `__eq__` before being passed to `ApproxBase.__eq__`, which is the + # only method that calls this one. + + if np.isscalar(actual): + for i in np.ndindex(self.expected.shape): + yield actual, self.expected[i].item() + else: + for i in np.ndindex(self.expected.shape): + yield actual[i].item(), self.expected[i].item() + + +class ApproxMapping(ApproxBase): + """Perform approximate comparisons where the expected value is a mapping + with numeric values (the keys can be anything).""" + + def __repr__(self) -> str: + return "approx({!r})".format( + {k: self._approx_scalar(v) for k, v in self.expected.items()} + ) + + def _repr_compare(self, other_side: Mapping[object, float]) -> List[str]: + import math + + approx_side_as_map = { + k: self._approx_scalar(v) for k, v in self.expected.items() + } + + number_of_elements = len(approx_side_as_map) + max_abs_diff = -math.inf + max_rel_diff = -math.inf + different_ids = [] + for (approx_key, approx_value), other_value in zip( + approx_side_as_map.items(), other_side.values() + ): + if approx_value != other_value: + if approx_value.expected is not None and other_value is not None: + max_abs_diff = max( + max_abs_diff, abs(approx_value.expected - other_value) + ) + if approx_value.expected == 0.0: + max_rel_diff = math.inf + else: + max_rel_diff = max( + max_rel_diff, + abs( + (approx_value.expected - other_value) + / approx_value.expected + ), + ) + different_ids.append(approx_key) + + message_data = [ + (str(key), str(other_side[key]), str(approx_side_as_map[key])) + for key in different_ids + ] + + return _compare_approx( + self.expected, + message_data, + number_of_elements, + different_ids, + max_abs_diff, + max_rel_diff, + ) + + def __eq__(self, actual) -> bool: + try: + if set(actual.keys()) != set(self.expected.keys()): + return False + except AttributeError: + return False + + return super().__eq__(actual) + + def _yield_comparisons(self, actual): + for k in self.expected.keys(): + yield actual[k], self.expected[k] + + def _check_type(self) -> None: + __tracebackhide__ = True + for key, value in self.expected.items(): + if isinstance(value, type(self.expected)): + msg = "pytest.approx() does not support nested dictionaries: key={!r} value={!r}\n full mapping={}" + raise TypeError(msg.format(key, value, pprint.pformat(self.expected))) + + +class ApproxSequenceLike(ApproxBase): + """Perform approximate comparisons where the expected value is a sequence of numbers.""" + + def __repr__(self) -> str: + seq_type = type(self.expected) + if seq_type not in (tuple, list): + seq_type = list + return "approx({!r})".format( + seq_type(self._approx_scalar(x) for x in self.expected) + ) + + def _repr_compare(self, other_side: Sequence[float]) -> List[str]: + import math + + if len(self.expected) != len(other_side): + return [ + "Impossible to compare lists with different sizes.", + f"Lengths: {len(self.expected)} and {len(other_side)}", + ] + + approx_side_as_map = _recursive_sequence_map(self._approx_scalar, self.expected) + + number_of_elements = len(approx_side_as_map) + max_abs_diff = -math.inf + max_rel_diff = -math.inf + different_ids = [] + for i, (approx_value, other_value) in enumerate( + zip(approx_side_as_map, other_side) + ): + if approx_value != other_value: + abs_diff = abs(approx_value.expected - other_value) + max_abs_diff = max(max_abs_diff, abs_diff) + if other_value == 0.0: + max_rel_diff = math.inf + else: + max_rel_diff = max(max_rel_diff, abs_diff / abs(other_value)) + different_ids.append(i) + + message_data = [ + (str(i), str(other_side[i]), str(approx_side_as_map[i])) + for i in different_ids + ] + + return _compare_approx( + self.expected, + message_data, + number_of_elements, + different_ids, + max_abs_diff, + max_rel_diff, + ) + + def __eq__(self, actual) -> bool: + try: + if len(actual) != len(self.expected): + return False + except TypeError: + return False + return super().__eq__(actual) + + def _yield_comparisons(self, actual): + return zip(actual, self.expected) + + def _check_type(self) -> None: + __tracebackhide__ = True + for index, x in enumerate(self.expected): + if isinstance(x, type(self.expected)): + msg = "pytest.approx() does not support nested data structures: {!r} at index {}\n full sequence: {}" + raise TypeError(msg.format(x, index, pprint.pformat(self.expected))) + + +class ApproxScalar(ApproxBase): + """Perform approximate comparisons where the expected value is a single number.""" + + # Using Real should be better than this Union, but not possible yet: + # https://github.com/python/typeshed/pull/3108 + DEFAULT_ABSOLUTE_TOLERANCE: Union[float, Decimal] = 1e-12 + DEFAULT_RELATIVE_TOLERANCE: Union[float, Decimal] = 1e-6 + + def __repr__(self) -> str: + """Return a string communicating both the expected value and the + tolerance for the comparison being made. + + For example, ``1.0 ± 1e-6``, ``(3+4j) ± 5e-6 ∠ ±180°``. + """ + # Don't show a tolerance for values that aren't compared using + # tolerances, i.e. non-numerics and infinities. Need to call abs to + # handle complex numbers, e.g. (inf + 1j). + if (not isinstance(self.expected, (Complex, Decimal))) or math.isinf( + abs(self.expected) # type: ignore[arg-type] + ): + return str(self.expected) + + # If a sensible tolerance can't be calculated, self.tolerance will + # raise a ValueError. In this case, display '???'. + try: + vetted_tolerance = f"{self.tolerance:.1e}" + if ( + isinstance(self.expected, Complex) + and self.expected.imag + and not math.isinf(self.tolerance) + ): + vetted_tolerance += " ∠ ±180°" + except ValueError: + vetted_tolerance = "???" + + return f"{self.expected} ± {vetted_tolerance}" + + def __eq__(self, actual) -> bool: + """Return whether the given value is equal to the expected value + within the pre-specified tolerance.""" + asarray = _as_numpy_array(actual) + if asarray is not None: + # Call ``__eq__()`` manually to prevent infinite-recursion with + # numpy<1.13. See #3748. + return all(self.__eq__(a) for a in asarray.flat) + + # Short-circuit exact equality. + if actual == self.expected: + return True + + # If either type is non-numeric, fall back to strict equality. + # NB: we need Complex, rather than just Number, to ensure that __abs__, + # __sub__, and __float__ are defined. + if not ( + isinstance(self.expected, (Complex, Decimal)) + and isinstance(actual, (Complex, Decimal)) + ): + return False + + # Allow the user to control whether NaNs are considered equal to each + # other or not. The abs() calls are for compatibility with complex + # numbers. + if math.isnan(abs(self.expected)): # type: ignore[arg-type] + return self.nan_ok and math.isnan(abs(actual)) # type: ignore[arg-type] + + # Infinity shouldn't be approximately equal to anything but itself, but + # if there's a relative tolerance, it will be infinite and infinity + # will seem approximately equal to everything. The equal-to-itself + # case would have been short circuited above, so here we can just + # return false if the expected value is infinite. The abs() call is + # for compatibility with complex numbers. + if math.isinf(abs(self.expected)): # type: ignore[arg-type] + return False + + # Return true if the two numbers are within the tolerance. + result: bool = abs(self.expected - actual) <= self.tolerance + return result + + # Ignore type because of https://github.com/python/mypy/issues/4266. + __hash__ = None # type: ignore + + @property + def tolerance(self): + """Return the tolerance for the comparison. + + This could be either an absolute tolerance or a relative tolerance, + depending on what the user specified or which would be larger. + """ + + def set_default(x, default): + return x if x is not None else default + + # Figure out what the absolute tolerance should be. ``self.abs`` is + # either None or a value specified by the user. + absolute_tolerance = set_default(self.abs, self.DEFAULT_ABSOLUTE_TOLERANCE) + + if absolute_tolerance < 0: + raise ValueError( + f"absolute tolerance can't be negative: {absolute_tolerance}" + ) + if math.isnan(absolute_tolerance): + raise ValueError("absolute tolerance can't be NaN.") + + # If the user specified an absolute tolerance but not a relative one, + # just return the absolute tolerance. + if self.rel is None: + if self.abs is not None: + return absolute_tolerance + + # Figure out what the relative tolerance should be. ``self.rel`` is + # either None or a value specified by the user. This is done after + # we've made sure the user didn't ask for an absolute tolerance only, + # because we don't want to raise errors about the relative tolerance if + # we aren't even going to use it. + relative_tolerance = set_default( + self.rel, self.DEFAULT_RELATIVE_TOLERANCE + ) * abs(self.expected) + + if relative_tolerance < 0: + raise ValueError( + f"relative tolerance can't be negative: {relative_tolerance}" + ) + if math.isnan(relative_tolerance): + raise ValueError("relative tolerance can't be NaN.") + + # Return the larger of the relative and absolute tolerances. + return max(relative_tolerance, absolute_tolerance) + + +class ApproxDecimal(ApproxScalar): + """Perform approximate comparisons where the expected value is a Decimal.""" + + DEFAULT_ABSOLUTE_TOLERANCE = Decimal("1e-12") + DEFAULT_RELATIVE_TOLERANCE = Decimal("1e-6") + + +def approx(expected, rel=None, abs=None, nan_ok: bool = False) -> ApproxBase: + """Assert that two numbers (or two ordered sequences of numbers) are equal to each other + within some tolerance. + + Due to the :doc:`python:tutorial/floatingpoint`, numbers that we + would intuitively expect to be equal are not always so:: + + >>> 0.1 + 0.2 == 0.3 + False + + This problem is commonly encountered when writing tests, e.g. when making + sure that floating-point values are what you expect them to be. One way to + deal with this problem is to assert that two floating-point numbers are + equal to within some appropriate tolerance:: + + >>> abs((0.1 + 0.2) - 0.3) < 1e-6 + True + + However, comparisons like this are tedious to write and difficult to + understand. Furthermore, absolute comparisons like the one above are + usually discouraged because there's no tolerance that works well for all + situations. ``1e-6`` is good for numbers around ``1``, but too small for + very big numbers and too big for very small ones. It's better to express + the tolerance as a fraction of the expected value, but relative comparisons + like that are even more difficult to write correctly and concisely. + + The ``approx`` class performs floating-point comparisons using a syntax + that's as intuitive as possible:: + + >>> from pytest import approx + >>> 0.1 + 0.2 == approx(0.3) + True + + The same syntax also works for ordered sequences of numbers:: + + >>> (0.1 + 0.2, 0.2 + 0.4) == approx((0.3, 0.6)) + True + + ``numpy`` arrays:: + + >>> import numpy as np # doctest: +SKIP + >>> np.array([0.1, 0.2]) + np.array([0.2, 0.4]) == approx(np.array([0.3, 0.6])) # doctest: +SKIP + True + + And for a ``numpy`` array against a scalar:: + + >>> import numpy as np # doctest: +SKIP + >>> np.array([0.1, 0.2]) + np.array([0.2, 0.1]) == approx(0.3) # doctest: +SKIP + True + + Only ordered sequences are supported, because ``approx`` needs + to infer the relative position of the sequences without ambiguity. This means + ``sets`` and other unordered sequences are not supported. + + Finally, dictionary *values* can also be compared:: + + >>> {'a': 0.1 + 0.2, 'b': 0.2 + 0.4} == approx({'a': 0.3, 'b': 0.6}) + True + + The comparison will be true if both mappings have the same keys and their + respective values match the expected tolerances. + + **Tolerances** + + By default, ``approx`` considers numbers within a relative tolerance of + ``1e-6`` (i.e. one part in a million) of its expected value to be equal. + This treatment would lead to surprising results if the expected value was + ``0.0``, because nothing but ``0.0`` itself is relatively close to ``0.0``. + To handle this case less surprisingly, ``approx`` also considers numbers + within an absolute tolerance of ``1e-12`` of its expected value to be + equal. Infinity and NaN are special cases. Infinity is only considered + equal to itself, regardless of the relative tolerance. NaN is not + considered equal to anything by default, but you can make it be equal to + itself by setting the ``nan_ok`` argument to True. (This is meant to + facilitate comparing arrays that use NaN to mean "no data".) + + Both the relative and absolute tolerances can be changed by passing + arguments to the ``approx`` constructor:: + + >>> 1.0001 == approx(1) + False + >>> 1.0001 == approx(1, rel=1e-3) + True + >>> 1.0001 == approx(1, abs=1e-3) + True + + If you specify ``abs`` but not ``rel``, the comparison will not consider + the relative tolerance at all. In other words, two numbers that are within + the default relative tolerance of ``1e-6`` will still be considered unequal + if they exceed the specified absolute tolerance. If you specify both + ``abs`` and ``rel``, the numbers will be considered equal if either + tolerance is met:: + + >>> 1 + 1e-8 == approx(1) + True + >>> 1 + 1e-8 == approx(1, abs=1e-12) + False + >>> 1 + 1e-8 == approx(1, rel=1e-6, abs=1e-12) + True + + You can also use ``approx`` to compare nonnumeric types, or dicts and + sequences containing nonnumeric types, in which case it falls back to + strict equality. This can be useful for comparing dicts and sequences that + can contain optional values:: + + >>> {"required": 1.0000005, "optional": None} == approx({"required": 1, "optional": None}) + True + >>> [None, 1.0000005] == approx([None,1]) + True + >>> ["foo", 1.0000005] == approx([None,1]) + False + + If you're thinking about using ``approx``, then you might want to know how + it compares to other good ways of comparing floating-point numbers. All of + these algorithms are based on relative and absolute tolerances and should + agree for the most part, but they do have meaningful differences: + + - ``math.isclose(a, b, rel_tol=1e-9, abs_tol=0.0)``: True if the relative + tolerance is met w.r.t. either ``a`` or ``b`` or if the absolute + tolerance is met. Because the relative tolerance is calculated w.r.t. + both ``a`` and ``b``, this test is symmetric (i.e. neither ``a`` nor + ``b`` is a "reference value"). You have to specify an absolute tolerance + if you want to compare to ``0.0`` because there is no tolerance by + default. More information: :py:func:`math.isclose`. + + - ``numpy.isclose(a, b, rtol=1e-5, atol=1e-8)``: True if the difference + between ``a`` and ``b`` is less that the sum of the relative tolerance + w.r.t. ``b`` and the absolute tolerance. Because the relative tolerance + is only calculated w.r.t. ``b``, this test is asymmetric and you can + think of ``b`` as the reference value. Support for comparing sequences + is provided by :py:func:`numpy.allclose`. More information: + :std:doc:`numpy:reference/generated/numpy.isclose`. + + - ``unittest.TestCase.assertAlmostEqual(a, b)``: True if ``a`` and ``b`` + are within an absolute tolerance of ``1e-7``. No relative tolerance is + considered , so this function is not appropriate for very large or very + small numbers. Also, it's only available in subclasses of ``unittest.TestCase`` + and it's ugly because it doesn't follow PEP8. More information: + :py:meth:`unittest.TestCase.assertAlmostEqual`. + + - ``a == pytest.approx(b, rel=1e-6, abs=1e-12)``: True if the relative + tolerance is met w.r.t. ``b`` or if the absolute tolerance is met. + Because the relative tolerance is only calculated w.r.t. ``b``, this test + is asymmetric and you can think of ``b`` as the reference value. In the + special case that you explicitly specify an absolute tolerance but not a + relative tolerance, only the absolute tolerance is considered. + + .. note:: + + ``approx`` can handle numpy arrays, but we recommend the + specialised test helpers in :std:doc:`numpy:reference/routines.testing` + if you need support for comparisons, NaNs, or ULP-based tolerances. + + To match strings using regex, you can use + `Matches `_ + from the + `re_assert package `_. + + .. warning:: + + .. versionchanged:: 3.2 + + In order to avoid inconsistent behavior, :py:exc:`TypeError` is + raised for ``>``, ``>=``, ``<`` and ``<=`` comparisons. + The example below illustrates the problem:: + + assert approx(0.1) > 0.1 + 1e-10 # calls approx(0.1).__gt__(0.1 + 1e-10) + assert 0.1 + 1e-10 > approx(0.1) # calls approx(0.1).__lt__(0.1 + 1e-10) + + In the second example one expects ``approx(0.1).__le__(0.1 + 1e-10)`` + to be called. But instead, ``approx(0.1).__lt__(0.1 + 1e-10)`` is used to + comparison. This is because the call hierarchy of rich comparisons + follows a fixed behavior. More information: :py:meth:`object.__ge__` + + .. versionchanged:: 3.7.1 + ``approx`` raises ``TypeError`` when it encounters a dict value or + sequence element of nonnumeric type. + + .. versionchanged:: 6.1.0 + ``approx`` falls back to strict equality for nonnumeric types instead + of raising ``TypeError``. + """ + + # Delegate the comparison to a class that knows how to deal with the type + # of the expected value (e.g. int, float, list, dict, numpy.array, etc). + # + # The primary responsibility of these classes is to implement ``__eq__()`` + # and ``__repr__()``. The former is used to actually check if some + # "actual" value is equivalent to the given expected value within the + # allowed tolerance. The latter is used to show the user the expected + # value and tolerance, in the case that a test failed. + # + # The actual logic for making approximate comparisons can be found in + # ApproxScalar, which is used to compare individual numbers. All of the + # other Approx classes eventually delegate to this class. The ApproxBase + # class provides some convenient methods and overloads, but isn't really + # essential. + + __tracebackhide__ = True + + if isinstance(expected, Decimal): + cls: Type[ApproxBase] = ApproxDecimal + elif isinstance(expected, Mapping): + cls = ApproxMapping + elif _is_numpy_array(expected): + expected = _as_numpy_array(expected) + cls = ApproxNumpy + elif ( + hasattr(expected, "__getitem__") + and isinstance(expected, Sized) + # Type ignored because the error is wrong -- not unreachable. + and not isinstance(expected, STRING_TYPES) # type: ignore[unreachable] + ): + cls = ApproxSequenceLike + elif ( + isinstance(expected, Collection) + # Type ignored because the error is wrong -- not unreachable. + and not isinstance(expected, STRING_TYPES) # type: ignore[unreachable] + ): + msg = f"pytest.approx() only supports ordered sequences, but got: {repr(expected)}" + raise TypeError(msg) + else: + cls = ApproxScalar + + return cls(expected, rel, abs, nan_ok) + + +def _is_numpy_array(obj: object) -> bool: + """ + Return true if the given object is implicitly convertible to ndarray, + and numpy is already imported. + """ + return _as_numpy_array(obj) is not None + + +def _as_numpy_array(obj: object) -> Optional["ndarray"]: + """ + Return an ndarray if the given object is implicitly convertible to ndarray, + and numpy is already imported, otherwise None. + """ + import sys + + np: Any = sys.modules.get("numpy") + if np is not None: + # avoid infinite recursion on numpy scalars, which have __array__ + if np.isscalar(obj): + return None + elif isinstance(obj, np.ndarray): + return obj + elif hasattr(obj, "__array__") or hasattr("obj", "__array_interface__"): + return np.asarray(obj) + return None + + +# builtin pytest.raises helper + +E = TypeVar("E", bound=BaseException) + + +@overload +def raises( + expected_exception: Union[Type[E], Tuple[Type[E], ...]], + *, + match: Optional[Union[str, Pattern[str]]] = ..., +) -> "RaisesContext[E]": + ... + + +@overload +def raises( # noqa: F811 + expected_exception: Union[Type[E], Tuple[Type[E], ...]], + func: Callable[..., Any], + *args: Any, + **kwargs: Any, +) -> _pytest._code.ExceptionInfo[E]: + ... + + +def raises( # noqa: F811 + expected_exception: Union[Type[E], Tuple[Type[E], ...]], *args: Any, **kwargs: Any +) -> Union["RaisesContext[E]", _pytest._code.ExceptionInfo[E]]: + r"""Assert that a code block/function call raises an exception. + + :param typing.Type[E] | typing.Tuple[typing.Type[E], ...] expected_exception: + The expected exception type, or a tuple if one of multiple possible + exception types are expected. + :kwparam str | typing.Pattern[str] | None match: + If specified, a string containing a regular expression, + or a regular expression object, that is tested against the string + representation of the exception using :func:`re.search`. + + To match a literal string that may contain :ref:`special characters + `, the pattern can first be escaped with :func:`re.escape`. + + (This is only used when :py:func:`pytest.raises` is used as a context manager, + and passed through to the function otherwise. + When using :py:func:`pytest.raises` as a function, you can use: + ``pytest.raises(Exc, func, match="passed on").match("my pattern")``.) + + .. currentmodule:: _pytest._code + + Use ``pytest.raises`` as a context manager, which will capture the exception of the given + type:: + + >>> import pytest + >>> with pytest.raises(ZeroDivisionError): + ... 1/0 + + If the code block does not raise the expected exception (``ZeroDivisionError`` in the example + above), or no exception at all, the check will fail instead. + + You can also use the keyword argument ``match`` to assert that the + exception matches a text or regex:: + + >>> with pytest.raises(ValueError, match='must be 0 or None'): + ... raise ValueError("value must be 0 or None") + + >>> with pytest.raises(ValueError, match=r'must be \d+$'): + ... raise ValueError("value must be 42") + + The context manager produces an :class:`ExceptionInfo` object which can be used to inspect the + details of the captured exception:: + + >>> with pytest.raises(ValueError) as exc_info: + ... raise ValueError("value must be 42") + >>> assert exc_info.type is ValueError + >>> assert exc_info.value.args[0] == "value must be 42" + + .. note:: + + When using ``pytest.raises`` as a context manager, it's worthwhile to + note that normal context manager rules apply and that the exception + raised *must* be the final line in the scope of the context manager. + Lines of code after that, within the scope of the context manager will + not be executed. For example:: + + >>> value = 15 + >>> with pytest.raises(ValueError) as exc_info: + ... if value > 10: + ... raise ValueError("value must be <= 10") + ... assert exc_info.type is ValueError # this will not execute + + Instead, the following approach must be taken (note the difference in + scope):: + + >>> with pytest.raises(ValueError) as exc_info: + ... if value > 10: + ... raise ValueError("value must be <= 10") + ... + >>> assert exc_info.type is ValueError + + **Using with** ``pytest.mark.parametrize`` + + When using :ref:`pytest.mark.parametrize ref` + it is possible to parametrize tests such that + some runs raise an exception and others do not. + + See :ref:`parametrizing_conditional_raising` for an example. + + **Legacy form** + + It is possible to specify a callable by passing a to-be-called lambda:: + + >>> raises(ZeroDivisionError, lambda: 1/0) + + + or you can specify an arbitrary callable with arguments:: + + >>> def f(x): return 1/x + ... + >>> raises(ZeroDivisionError, f, 0) + + >>> raises(ZeroDivisionError, f, x=0) + + + The form above is fully supported but discouraged for new code because the + context manager form is regarded as more readable and less error-prone. + + .. note:: + Similar to caught exception objects in Python, explicitly clearing + local references to returned ``ExceptionInfo`` objects can + help the Python interpreter speed up its garbage collection. + + Clearing those references breaks a reference cycle + (``ExceptionInfo`` --> caught exception --> frame stack raising + the exception --> current frame stack --> local variables --> + ``ExceptionInfo``) which makes Python keep all objects referenced + from that cycle (including all local variables in the current + frame) alive until the next cyclic garbage collection run. + More detailed information can be found in the official Python + documentation for :ref:`the try statement `. + """ + __tracebackhide__ = True + + if not expected_exception: + raise ValueError( + f"Expected an exception type or a tuple of exception types, but got `{expected_exception!r}`. " + f"Raising exceptions is already understood as failing the test, so you don't need " + f"any special code to say 'this should never raise an exception'." + ) + if isinstance(expected_exception, type): + expected_exceptions: Tuple[Type[E], ...] = (expected_exception,) + else: + expected_exceptions = expected_exception + for exc in expected_exceptions: + if not isinstance(exc, type) or not issubclass(exc, BaseException): + msg = "expected exception must be a BaseException type, not {}" # type: ignore[unreachable] + not_a = exc.__name__ if isinstance(exc, type) else type(exc).__name__ + raise TypeError(msg.format(not_a)) + + message = f"DID NOT RAISE {expected_exception}" + + if not args: + match: Optional[Union[str, Pattern[str]]] = kwargs.pop("match", None) + if kwargs: + msg = "Unexpected keyword arguments passed to pytest.raises: " + msg += ", ".join(sorted(kwargs)) + msg += "\nUse context-manager form instead?" + raise TypeError(msg) + return RaisesContext(expected_exception, message, match) + else: + func = args[0] + if not callable(func): + raise TypeError(f"{func!r} object (type: {type(func)}) must be callable") + try: + func(*args[1:], **kwargs) + except expected_exception as e: + return _pytest._code.ExceptionInfo.from_exception(e) + fail(message) + + +# This doesn't work with mypy for now. Use fail.Exception instead. +raises.Exception = fail.Exception # type: ignore + + +@final +class RaisesContext(ContextManager[_pytest._code.ExceptionInfo[E]]): + def __init__( + self, + expected_exception: Union[Type[E], Tuple[Type[E], ...]], + message: str, + match_expr: Optional[Union[str, Pattern[str]]] = None, + ) -> None: + self.expected_exception = expected_exception + self.message = message + self.match_expr = match_expr + self.excinfo: Optional[_pytest._code.ExceptionInfo[E]] = None + + def __enter__(self) -> _pytest._code.ExceptionInfo[E]: + self.excinfo = _pytest._code.ExceptionInfo.for_later() + return self.excinfo + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> bool: + __tracebackhide__ = True + if exc_type is None: + fail(self.message) + assert self.excinfo is not None + if not issubclass(exc_type, self.expected_exception): + return False + # Cast to narrow the exception type now that it's verified. + exc_info = cast(Tuple[Type[E], E, TracebackType], (exc_type, exc_val, exc_tb)) + self.excinfo.fill_unfilled(exc_info) + if self.match_expr is not None: + self.excinfo.match(self.match_expr) + return True diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/python_path.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/python_path.py new file mode 100644 index 000000000..cceabbca1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/python_path.py @@ -0,0 +1,24 @@ +import sys + +import pytest +from pytest import Config +from pytest import Parser + + +def pytest_addoption(parser: Parser) -> None: + parser.addini("pythonpath", type="paths", help="Add paths to sys.path", default=[]) + + +@pytest.hookimpl(tryfirst=True) +def pytest_load_initial_conftests(early_config: Config) -> None: + # `pythonpath = a b` will set `sys.path` to `[a, b, x, y, z, ...]` + for path in reversed(early_config.getini("pythonpath")): + sys.path.insert(0, str(path)) + + +@pytest.hookimpl(trylast=True) +def pytest_unconfigure(config: Config) -> None: + for path in config.getini("pythonpath"): + path_str = str(path) + if path_str in sys.path: + sys.path.remove(path_str) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/recwarn.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/recwarn.py new file mode 100644 index 000000000..d76ea020f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/recwarn.py @@ -0,0 +1,313 @@ +"""Record warnings during test function execution.""" +import re +import warnings +from pprint import pformat +from types import TracebackType +from typing import Any +from typing import Callable +from typing import Generator +from typing import Iterator +from typing import List +from typing import Optional +from typing import Pattern +from typing import Tuple +from typing import Type +from typing import TypeVar +from typing import Union + +from _pytest.compat import final +from _pytest.compat import overload +from _pytest.deprecated import check_ispytest +from _pytest.deprecated import WARNS_NONE_ARG +from _pytest.fixtures import fixture +from _pytest.outcomes import fail + + +T = TypeVar("T") + + +@fixture +def recwarn() -> Generator["WarningsRecorder", None, None]: + """Return a :class:`WarningsRecorder` instance that records all warnings emitted by test functions. + + See https://docs.pytest.org/en/latest/how-to/capture-warnings.html for information + on warning categories. + """ + wrec = WarningsRecorder(_ispytest=True) + with wrec: + warnings.simplefilter("default") + yield wrec + + +@overload +def deprecated_call( + *, match: Optional[Union[str, Pattern[str]]] = ... +) -> "WarningsRecorder": + ... + + +@overload +def deprecated_call( # noqa: F811 + func: Callable[..., T], *args: Any, **kwargs: Any +) -> T: + ... + + +def deprecated_call( # noqa: F811 + func: Optional[Callable[..., Any]] = None, *args: Any, **kwargs: Any +) -> Union["WarningsRecorder", Any]: + """Assert that code produces a ``DeprecationWarning`` or ``PendingDeprecationWarning``. + + This function can be used as a context manager:: + + >>> import warnings + >>> def api_call_v2(): + ... warnings.warn('use v3 of this api', DeprecationWarning) + ... return 200 + + >>> import pytest + >>> with pytest.deprecated_call(): + ... assert api_call_v2() == 200 + + It can also be used by passing a function and ``*args`` and ``**kwargs``, + in which case it will ensure calling ``func(*args, **kwargs)`` produces one of + the warnings types above. The return value is the return value of the function. + + In the context manager form you may use the keyword argument ``match`` to assert + that the warning matches a text or regex. + + The context manager produces a list of :class:`warnings.WarningMessage` objects, + one for each warning raised. + """ + __tracebackhide__ = True + if func is not None: + args = (func,) + args + return warns((DeprecationWarning, PendingDeprecationWarning), *args, **kwargs) + + +@overload +def warns( + expected_warning: Union[Type[Warning], Tuple[Type[Warning], ...]] = ..., + *, + match: Optional[Union[str, Pattern[str]]] = ..., +) -> "WarningsChecker": + ... + + +@overload +def warns( # noqa: F811 + expected_warning: Union[Type[Warning], Tuple[Type[Warning], ...]], + func: Callable[..., T], + *args: Any, + **kwargs: Any, +) -> T: + ... + + +def warns( # noqa: F811 + expected_warning: Union[Type[Warning], Tuple[Type[Warning], ...]] = Warning, + *args: Any, + match: Optional[Union[str, Pattern[str]]] = None, + **kwargs: Any, +) -> Union["WarningsChecker", Any]: + r"""Assert that code raises a particular class of warning. + + Specifically, the parameter ``expected_warning`` can be a warning class or sequence + of warning classes, and the code inside the ``with`` block must issue at least one + warning of that class or classes. + + This helper produces a list of :class:`warnings.WarningMessage` objects, one for + each warning raised (regardless of whether it is an ``expected_warning`` or not). + + This function can be used as a context manager, which will capture all the raised + warnings inside it:: + + >>> import pytest + >>> with pytest.warns(RuntimeWarning): + ... warnings.warn("my warning", RuntimeWarning) + + In the context manager form you may use the keyword argument ``match`` to assert + that the warning matches a text or regex:: + + >>> with pytest.warns(UserWarning, match='must be 0 or None'): + ... warnings.warn("value must be 0 or None", UserWarning) + + >>> with pytest.warns(UserWarning, match=r'must be \d+$'): + ... warnings.warn("value must be 42", UserWarning) + + >>> with pytest.warns(UserWarning, match=r'must be \d+$'): + ... warnings.warn("this is not here", UserWarning) + Traceback (most recent call last): + ... + Failed: DID NOT WARN. No warnings of type ...UserWarning... were emitted... + + **Using with** ``pytest.mark.parametrize`` + + When using :ref:`pytest.mark.parametrize ref` it is possible to parametrize tests + such that some runs raise a warning and others do not. + + This could be achieved in the same way as with exceptions, see + :ref:`parametrizing_conditional_raising` for an example. + + """ + __tracebackhide__ = True + if not args: + if kwargs: + argnames = ", ".join(sorted(kwargs)) + raise TypeError( + f"Unexpected keyword arguments passed to pytest.warns: {argnames}" + "\nUse context-manager form instead?" + ) + return WarningsChecker(expected_warning, match_expr=match, _ispytest=True) + else: + func = args[0] + if not callable(func): + raise TypeError(f"{func!r} object (type: {type(func)}) must be callable") + with WarningsChecker(expected_warning, _ispytest=True): + return func(*args[1:], **kwargs) + + +class WarningsRecorder(warnings.catch_warnings): # type:ignore[type-arg] + """A context manager to record raised warnings. + + Each recorded warning is an instance of :class:`warnings.WarningMessage`. + + Adapted from `warnings.catch_warnings`. + + .. note:: + ``DeprecationWarning`` and ``PendingDeprecationWarning`` are treated + differently; see :ref:`ensuring_function_triggers`. + + """ + + def __init__(self, *, _ispytest: bool = False) -> None: + check_ispytest(_ispytest) + # Type ignored due to the way typeshed handles warnings.catch_warnings. + super().__init__(record=True) # type: ignore[call-arg] + self._entered = False + self._list: List[warnings.WarningMessage] = [] + + @property + def list(self) -> List["warnings.WarningMessage"]: + """The list of recorded warnings.""" + return self._list + + def __getitem__(self, i: int) -> "warnings.WarningMessage": + """Get a recorded warning by index.""" + return self._list[i] + + def __iter__(self) -> Iterator["warnings.WarningMessage"]: + """Iterate through the recorded warnings.""" + return iter(self._list) + + def __len__(self) -> int: + """The number of recorded warnings.""" + return len(self._list) + + def pop(self, cls: Type[Warning] = Warning) -> "warnings.WarningMessage": + """Pop the first recorded warning, raise exception if not exists.""" + for i, w in enumerate(self._list): + if issubclass(w.category, cls): + return self._list.pop(i) + __tracebackhide__ = True + raise AssertionError(f"{cls!r} not found in warning list") + + def clear(self) -> None: + """Clear the list of recorded warnings.""" + self._list[:] = [] + + # Type ignored because it doesn't exactly warnings.catch_warnings.__enter__ + # -- it returns a List but we only emulate one. + def __enter__(self) -> "WarningsRecorder": # type: ignore + if self._entered: + __tracebackhide__ = True + raise RuntimeError(f"Cannot enter {self!r} twice") + _list = super().__enter__() + # record=True means it's None. + assert _list is not None + self._list = _list + warnings.simplefilter("always") + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + if not self._entered: + __tracebackhide__ = True + raise RuntimeError(f"Cannot exit {self!r} without entering first") + + super().__exit__(exc_type, exc_val, exc_tb) + + # Built-in catch_warnings does not reset entered state so we do it + # manually here for this context manager to become reusable. + self._entered = False + + +@final +class WarningsChecker(WarningsRecorder): + def __init__( + self, + expected_warning: Optional[ + Union[Type[Warning], Tuple[Type[Warning], ...]] + ] = Warning, + match_expr: Optional[Union[str, Pattern[str]]] = None, + *, + _ispytest: bool = False, + ) -> None: + check_ispytest(_ispytest) + super().__init__(_ispytest=True) + + msg = "exceptions must be derived from Warning, not %s" + if expected_warning is None: + warnings.warn(WARNS_NONE_ARG, stacklevel=4) + expected_warning_tup = None + elif isinstance(expected_warning, tuple): + for exc in expected_warning: + if not issubclass(exc, Warning): + raise TypeError(msg % type(exc)) + expected_warning_tup = expected_warning + elif issubclass(expected_warning, Warning): + expected_warning_tup = (expected_warning,) + else: + raise TypeError(msg % type(expected_warning)) + + self.expected_warning = expected_warning_tup + self.match_expr = match_expr + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + super().__exit__(exc_type, exc_val, exc_tb) + + __tracebackhide__ = True + + def found_str(): + return pformat([record.message for record in self], indent=2) + + # only check if we're not currently handling an exception + if exc_type is None and exc_val is None and exc_tb is None: + if self.expected_warning is not None: + if not any(issubclass(r.category, self.expected_warning) for r in self): + __tracebackhide__ = True + fail( + f"DID NOT WARN. No warnings of type {self.expected_warning} were emitted.\n" + f"The list of emitted warnings is: {found_str()}." + ) + elif self.match_expr is not None: + for r in self: + if issubclass(r.category, self.expected_warning): + if re.compile(self.match_expr).search(str(r.message)): + break + else: + fail( + f"""\ +DID NOT WARN. No warnings of type {self.expected_warning} matching the regex were emitted. + Regex: {self.match_expr} + Emitted warnings: {found_str()}""" + ) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/reports.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/reports.py new file mode 100644 index 000000000..74e8794b2 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/reports.py @@ -0,0 +1,622 @@ +import dataclasses +import os +from io import StringIO +from pprint import pprint +from typing import Any +from typing import cast +from typing import Dict +from typing import Iterable +from typing import Iterator +from typing import List +from typing import Mapping +from typing import NoReturn +from typing import Optional +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import TypeVar +from typing import Union + +from _pytest._code.code import ExceptionChainRepr +from _pytest._code.code import ExceptionInfo +from _pytest._code.code import ExceptionRepr +from _pytest._code.code import ReprEntry +from _pytest._code.code import ReprEntryNative +from _pytest._code.code import ReprExceptionInfo +from _pytest._code.code import ReprFileLocation +from _pytest._code.code import ReprFuncArgs +from _pytest._code.code import ReprLocals +from _pytest._code.code import ReprTraceback +from _pytest._code.code import TerminalRepr +from _pytest._io import TerminalWriter +from _pytest.compat import final +from _pytest.config import Config +from _pytest.nodes import Collector +from _pytest.nodes import Item +from _pytest.outcomes import skip + +if TYPE_CHECKING: + from typing_extensions import Literal + + from _pytest.runner import CallInfo + + +def getworkerinfoline(node): + try: + return node._workerinfocache + except AttributeError: + d = node.workerinfo + ver = "%s.%s.%s" % d["version_info"][:3] + node._workerinfocache = s = "[{}] {} -- Python {} {}".format( + d["id"], d["sysplatform"], ver, d["executable"] + ) + return s + + +_R = TypeVar("_R", bound="BaseReport") + + +class BaseReport: + when: Optional[str] + location: Optional[Tuple[str, Optional[int], str]] + longrepr: Union[ + None, ExceptionInfo[BaseException], Tuple[str, int, str], str, TerminalRepr + ] + sections: List[Tuple[str, str]] + nodeid: str + outcome: "Literal['passed', 'failed', 'skipped']" + + def __init__(self, **kw: Any) -> None: + self.__dict__.update(kw) + + if TYPE_CHECKING: + # Can have arbitrary fields given to __init__(). + def __getattr__(self, key: str) -> Any: + ... + + def toterminal(self, out: TerminalWriter) -> None: + if hasattr(self, "node"): + worker_info = getworkerinfoline(self.node) + if worker_info: + out.line(worker_info) + + longrepr = self.longrepr + if longrepr is None: + return + + if hasattr(longrepr, "toterminal"): + longrepr_terminal = cast(TerminalRepr, longrepr) + longrepr_terminal.toterminal(out) + else: + try: + s = str(longrepr) + except UnicodeEncodeError: + s = "" + out.line(s) + + def get_sections(self, prefix: str) -> Iterator[Tuple[str, str]]: + for name, content in self.sections: + if name.startswith(prefix): + yield prefix, content + + @property + def longreprtext(self) -> str: + """Read-only property that returns the full string representation of + ``longrepr``. + + .. versionadded:: 3.0 + """ + file = StringIO() + tw = TerminalWriter(file) + tw.hasmarkup = False + self.toterminal(tw) + exc = file.getvalue() + return exc.strip() + + @property + def caplog(self) -> str: + """Return captured log lines, if log capturing is enabled. + + .. versionadded:: 3.5 + """ + return "\n".join( + content for (prefix, content) in self.get_sections("Captured log") + ) + + @property + def capstdout(self) -> str: + """Return captured text from stdout, if capturing is enabled. + + .. versionadded:: 3.0 + """ + return "".join( + content for (prefix, content) in self.get_sections("Captured stdout") + ) + + @property + def capstderr(self) -> str: + """Return captured text from stderr, if capturing is enabled. + + .. versionadded:: 3.0 + """ + return "".join( + content for (prefix, content) in self.get_sections("Captured stderr") + ) + + @property + def passed(self) -> bool: + """Whether the outcome is passed.""" + return self.outcome == "passed" + + @property + def failed(self) -> bool: + """Whether the outcome is failed.""" + return self.outcome == "failed" + + @property + def skipped(self) -> bool: + """Whether the outcome is skipped.""" + return self.outcome == "skipped" + + @property + def fspath(self) -> str: + """The path portion of the reported node, as a string.""" + return self.nodeid.split("::")[0] + + @property + def count_towards_summary(self) -> bool: + """**Experimental** Whether this report should be counted towards the + totals shown at the end of the test session: "1 passed, 1 failure, etc". + + .. note:: + + This function is considered **experimental**, so beware that it is subject to changes + even in patch releases. + """ + return True + + @property + def head_line(self) -> Optional[str]: + """**Experimental** The head line shown with longrepr output for this + report, more commonly during traceback representation during + failures:: + + ________ Test.foo ________ + + + In the example above, the head_line is "Test.foo". + + .. note:: + + This function is considered **experimental**, so beware that it is subject to changes + even in patch releases. + """ + if self.location is not None: + fspath, lineno, domain = self.location + return domain + return None + + def _get_verbose_word(self, config: Config): + _category, _short, verbose = config.hook.pytest_report_teststatus( + report=self, config=config + ) + return verbose + + def _to_json(self) -> Dict[str, Any]: + """Return the contents of this report as a dict of builtin entries, + suitable for serialization. + + This was originally the serialize_report() function from xdist (ca03269). + + Experimental method. + """ + return _report_to_json(self) + + @classmethod + def _from_json(cls: Type[_R], reportdict: Dict[str, object]) -> _R: + """Create either a TestReport or CollectReport, depending on the calling class. + + It is the callers responsibility to know which class to pass here. + + This was originally the serialize_report() function from xdist (ca03269). + + Experimental method. + """ + kwargs = _report_kwargs_from_json(reportdict) + return cls(**kwargs) + + +def _report_unserialization_failure( + type_name: str, report_class: Type[BaseReport], reportdict +) -> NoReturn: + url = "https://github.com/pytest-dev/pytest/issues" + stream = StringIO() + pprint("-" * 100, stream=stream) + pprint("INTERNALERROR: Unknown entry type returned: %s" % type_name, stream=stream) + pprint("report_name: %s" % report_class, stream=stream) + pprint(reportdict, stream=stream) + pprint("Please report this bug at %s" % url, stream=stream) + pprint("-" * 100, stream=stream) + raise RuntimeError(stream.getvalue()) + + +@final +class TestReport(BaseReport): + """Basic test report object (also used for setup and teardown calls if + they fail). + + Reports can contain arbitrary extra attributes. + """ + + __test__ = False + + def __init__( + self, + nodeid: str, + location: Tuple[str, Optional[int], str], + keywords: Mapping[str, Any], + outcome: "Literal['passed', 'failed', 'skipped']", + longrepr: Union[ + None, ExceptionInfo[BaseException], Tuple[str, int, str], str, TerminalRepr + ], + when: "Literal['setup', 'call', 'teardown']", + sections: Iterable[Tuple[str, str]] = (), + duration: float = 0, + start: float = 0, + stop: float = 0, + user_properties: Optional[Iterable[Tuple[str, object]]] = None, + **extra, + ) -> None: + #: Normalized collection nodeid. + self.nodeid = nodeid + + #: A (filesystempath, lineno, domaininfo) tuple indicating the + #: actual location of a test item - it might be different from the + #: collected one e.g. if a method is inherited from a different module. + #: The filesystempath may be relative to ``config.rootdir``. + #: The line number is 0-based. + self.location: Tuple[str, Optional[int], str] = location + + #: A name -> value dictionary containing all keywords and + #: markers associated with a test invocation. + self.keywords: Mapping[str, Any] = keywords + + #: Test outcome, always one of "passed", "failed", "skipped". + self.outcome = outcome + + #: None or a failure representation. + self.longrepr = longrepr + + #: One of 'setup', 'call', 'teardown' to indicate runtest phase. + self.when = when + + #: User properties is a list of tuples (name, value) that holds user + #: defined properties of the test. + self.user_properties = list(user_properties or []) + + #: Tuples of str ``(heading, content)`` with extra information + #: for the test report. Used by pytest to add text captured + #: from ``stdout``, ``stderr``, and intercepted logging events. May + #: be used by other plugins to add arbitrary information to reports. + self.sections = list(sections) + + #: Time it took to run just the test. + self.duration: float = duration + + #: The system time when the call started, in seconds since the epoch. + self.start: float = start + #: The system time when the call ended, in seconds since the epoch. + self.stop: float = stop + + self.__dict__.update(extra) + + def __repr__(self) -> str: + return "<{} {!r} when={!r} outcome={!r}>".format( + self.__class__.__name__, self.nodeid, self.when, self.outcome + ) + + @classmethod + def from_item_and_call(cls, item: Item, call: "CallInfo[None]") -> "TestReport": + """Create and fill a TestReport with standard item and call info. + + :param item: The item. + :param call: The call info. + """ + when = call.when + # Remove "collect" from the Literal type -- only for collection calls. + assert when != "collect" + duration = call.duration + start = call.start + stop = call.stop + keywords = {x: 1 for x in item.keywords} + excinfo = call.excinfo + sections = [] + if not call.excinfo: + outcome: Literal["passed", "failed", "skipped"] = "passed" + longrepr: Union[ + None, + ExceptionInfo[BaseException], + Tuple[str, int, str], + str, + TerminalRepr, + ] = None + else: + if not isinstance(excinfo, ExceptionInfo): + outcome = "failed" + longrepr = excinfo + elif isinstance(excinfo.value, skip.Exception): + outcome = "skipped" + r = excinfo._getreprcrash() + assert ( + r is not None + ), "There should always be a traceback entry for skipping a test." + if excinfo.value._use_item_location: + path, line = item.reportinfo()[:2] + assert line is not None + longrepr = os.fspath(path), line + 1, r.message + else: + longrepr = (str(r.path), r.lineno, r.message) + else: + outcome = "failed" + if call.when == "call": + longrepr = item.repr_failure(excinfo) + else: # exception in setup or teardown + longrepr = item._repr_failure_py( + excinfo, style=item.config.getoption("tbstyle", "auto") + ) + for rwhen, key, content in item._report_sections: + sections.append((f"Captured {key} {rwhen}", content)) + return cls( + item.nodeid, + item.location, + keywords, + outcome, + longrepr, + when, + sections, + duration, + start, + stop, + user_properties=item.user_properties, + ) + + +@final +class CollectReport(BaseReport): + """Collection report object. + + Reports can contain arbitrary extra attributes. + """ + + when = "collect" + + def __init__( + self, + nodeid: str, + outcome: "Literal['passed', 'failed', 'skipped']", + longrepr: Union[ + None, ExceptionInfo[BaseException], Tuple[str, int, str], str, TerminalRepr + ], + result: Optional[List[Union[Item, Collector]]], + sections: Iterable[Tuple[str, str]] = (), + **extra, + ) -> None: + #: Normalized collection nodeid. + self.nodeid = nodeid + + #: Test outcome, always one of "passed", "failed", "skipped". + self.outcome = outcome + + #: None or a failure representation. + self.longrepr = longrepr + + #: The collected items and collection nodes. + self.result = result or [] + + #: Tuples of str ``(heading, content)`` with extra information + #: for the test report. Used by pytest to add text captured + #: from ``stdout``, ``stderr``, and intercepted logging events. May + #: be used by other plugins to add arbitrary information to reports. + self.sections = list(sections) + + self.__dict__.update(extra) + + @property + def location( # type:ignore[override] + self, + ) -> Optional[Tuple[str, Optional[int], str]]: + return (self.fspath, None, self.fspath) + + def __repr__(self) -> str: + return "".format( + self.nodeid, len(self.result), self.outcome + ) + + +class CollectErrorRepr(TerminalRepr): + def __init__(self, msg: str) -> None: + self.longrepr = msg + + def toterminal(self, out: TerminalWriter) -> None: + out.line(self.longrepr, red=True) + + +def pytest_report_to_serializable( + report: Union[CollectReport, TestReport] +) -> Optional[Dict[str, Any]]: + if isinstance(report, (TestReport, CollectReport)): + data = report._to_json() + data["$report_type"] = report.__class__.__name__ + return data + # TODO: Check if this is actually reachable. + return None # type: ignore[unreachable] + + +def pytest_report_from_serializable( + data: Dict[str, Any], +) -> Optional[Union[CollectReport, TestReport]]: + if "$report_type" in data: + if data["$report_type"] == "TestReport": + return TestReport._from_json(data) + elif data["$report_type"] == "CollectReport": + return CollectReport._from_json(data) + assert False, "Unknown report_type unserialize data: {}".format( + data["$report_type"] + ) + return None + + +def _report_to_json(report: BaseReport) -> Dict[str, Any]: + """Return the contents of this report as a dict of builtin entries, + suitable for serialization. + + This was originally the serialize_report() function from xdist (ca03269). + """ + + def serialize_repr_entry( + entry: Union[ReprEntry, ReprEntryNative] + ) -> Dict[str, Any]: + data = dataclasses.asdict(entry) + for key, value in data.items(): + if hasattr(value, "__dict__"): + data[key] = dataclasses.asdict(value) + entry_data = {"type": type(entry).__name__, "data": data} + return entry_data + + def serialize_repr_traceback(reprtraceback: ReprTraceback) -> Dict[str, Any]: + result = dataclasses.asdict(reprtraceback) + result["reprentries"] = [ + serialize_repr_entry(x) for x in reprtraceback.reprentries + ] + return result + + def serialize_repr_crash( + reprcrash: Optional[ReprFileLocation], + ) -> Optional[Dict[str, Any]]: + if reprcrash is not None: + return dataclasses.asdict(reprcrash) + else: + return None + + def serialize_exception_longrepr(rep: BaseReport) -> Dict[str, Any]: + assert rep.longrepr is not None + # TODO: Investigate whether the duck typing is really necessary here. + longrepr = cast(ExceptionRepr, rep.longrepr) + result: Dict[str, Any] = { + "reprcrash": serialize_repr_crash(longrepr.reprcrash), + "reprtraceback": serialize_repr_traceback(longrepr.reprtraceback), + "sections": longrepr.sections, + } + if isinstance(longrepr, ExceptionChainRepr): + result["chain"] = [] + for repr_traceback, repr_crash, description in longrepr.chain: + result["chain"].append( + ( + serialize_repr_traceback(repr_traceback), + serialize_repr_crash(repr_crash), + description, + ) + ) + else: + result["chain"] = None + return result + + d = report.__dict__.copy() + if hasattr(report.longrepr, "toterminal"): + if hasattr(report.longrepr, "reprtraceback") and hasattr( + report.longrepr, "reprcrash" + ): + d["longrepr"] = serialize_exception_longrepr(report) + else: + d["longrepr"] = str(report.longrepr) + else: + d["longrepr"] = report.longrepr + for name in d: + if isinstance(d[name], os.PathLike): + d[name] = os.fspath(d[name]) + elif name == "result": + d[name] = None # for now + return d + + +def _report_kwargs_from_json(reportdict: Dict[str, Any]) -> Dict[str, Any]: + """Return **kwargs that can be used to construct a TestReport or + CollectReport instance. + + This was originally the serialize_report() function from xdist (ca03269). + """ + + def deserialize_repr_entry(entry_data): + data = entry_data["data"] + entry_type = entry_data["type"] + if entry_type == "ReprEntry": + reprfuncargs = None + reprfileloc = None + reprlocals = None + if data["reprfuncargs"]: + reprfuncargs = ReprFuncArgs(**data["reprfuncargs"]) + if data["reprfileloc"]: + reprfileloc = ReprFileLocation(**data["reprfileloc"]) + if data["reprlocals"]: + reprlocals = ReprLocals(data["reprlocals"]["lines"]) + + reprentry: Union[ReprEntry, ReprEntryNative] = ReprEntry( + lines=data["lines"], + reprfuncargs=reprfuncargs, + reprlocals=reprlocals, + reprfileloc=reprfileloc, + style=data["style"], + ) + elif entry_type == "ReprEntryNative": + reprentry = ReprEntryNative(data["lines"]) + else: + _report_unserialization_failure(entry_type, TestReport, reportdict) + return reprentry + + def deserialize_repr_traceback(repr_traceback_dict): + repr_traceback_dict["reprentries"] = [ + deserialize_repr_entry(x) for x in repr_traceback_dict["reprentries"] + ] + return ReprTraceback(**repr_traceback_dict) + + def deserialize_repr_crash(repr_crash_dict: Optional[Dict[str, Any]]): + if repr_crash_dict is not None: + return ReprFileLocation(**repr_crash_dict) + else: + return None + + if ( + reportdict["longrepr"] + and "reprcrash" in reportdict["longrepr"] + and "reprtraceback" in reportdict["longrepr"] + ): + reprtraceback = deserialize_repr_traceback( + reportdict["longrepr"]["reprtraceback"] + ) + reprcrash = deserialize_repr_crash(reportdict["longrepr"]["reprcrash"]) + if reportdict["longrepr"]["chain"]: + chain = [] + for repr_traceback_data, repr_crash_data, description in reportdict[ + "longrepr" + ]["chain"]: + chain.append( + ( + deserialize_repr_traceback(repr_traceback_data), + deserialize_repr_crash(repr_crash_data), + description, + ) + ) + exception_info: Union[ + ExceptionChainRepr, ReprExceptionInfo + ] = ExceptionChainRepr(chain) + else: + exception_info = ReprExceptionInfo( + reprtraceback=reprtraceback, + reprcrash=reprcrash, + ) + + for section in reportdict["longrepr"]["sections"]: + exception_info.addsection(*section) + reportdict["longrepr"] = exception_info + + return reportdict diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/runner.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/runner.py new file mode 100644 index 000000000..f861c05a4 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/runner.py @@ -0,0 +1,551 @@ +"""Basic collect and runtest protocol implementations.""" +import bdb +import dataclasses +import os +import sys +from typing import Callable +from typing import cast +from typing import Dict +from typing import Generic +from typing import List +from typing import Optional +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import TypeVar +from typing import Union + +from .reports import BaseReport +from .reports import CollectErrorRepr +from .reports import CollectReport +from .reports import TestReport +from _pytest import timing +from _pytest._code.code import ExceptionChainRepr +from _pytest._code.code import ExceptionInfo +from _pytest._code.code import TerminalRepr +from _pytest.compat import final +from _pytest.config.argparsing import Parser +from _pytest.deprecated import check_ispytest +from _pytest.nodes import Collector +from _pytest.nodes import Item +from _pytest.nodes import Node +from _pytest.outcomes import Exit +from _pytest.outcomes import OutcomeException +from _pytest.outcomes import Skipped +from _pytest.outcomes import TEST_OUTCOME + +if sys.version_info[:2] < (3, 11): + from exceptiongroup import BaseExceptionGroup + +if TYPE_CHECKING: + from typing_extensions import Literal + + from _pytest.main import Session + from _pytest.terminal import TerminalReporter + +# +# pytest plugin hooks. + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("terminal reporting", "Reporting", after="general") + group.addoption( + "--durations", + action="store", + type=int, + default=None, + metavar="N", + help="Show N slowest setup/test durations (N=0 for all)", + ) + group.addoption( + "--durations-min", + action="store", + type=float, + default=0.005, + metavar="N", + help="Minimal duration in seconds for inclusion in slowest list. " + "Default: 0.005.", + ) + + +def pytest_terminal_summary(terminalreporter: "TerminalReporter") -> None: + durations = terminalreporter.config.option.durations + durations_min = terminalreporter.config.option.durations_min + verbose = terminalreporter.config.getvalue("verbose") + if durations is None: + return + tr = terminalreporter + dlist = [] + for replist in tr.stats.values(): + for rep in replist: + if hasattr(rep, "duration"): + dlist.append(rep) + if not dlist: + return + dlist.sort(key=lambda x: x.duration, reverse=True) # type: ignore[no-any-return] + if not durations: + tr.write_sep("=", "slowest durations") + else: + tr.write_sep("=", "slowest %s durations" % durations) + dlist = dlist[:durations] + + for i, rep in enumerate(dlist): + if verbose < 2 and rep.duration < durations_min: + tr.write_line("") + tr.write_line( + "(%s durations < %gs hidden. Use -vv to show these durations.)" + % (len(dlist) - i, durations_min) + ) + break + tr.write_line(f"{rep.duration:02.2f}s {rep.when:<8} {rep.nodeid}") + + +def pytest_sessionstart(session: "Session") -> None: + session._setupstate = SetupState() + + +def pytest_sessionfinish(session: "Session") -> None: + session._setupstate.teardown_exact(None) + + +def pytest_runtest_protocol(item: Item, nextitem: Optional[Item]) -> bool: + ihook = item.ihook + ihook.pytest_runtest_logstart(nodeid=item.nodeid, location=item.location) + runtestprotocol(item, nextitem=nextitem) + ihook.pytest_runtest_logfinish(nodeid=item.nodeid, location=item.location) + return True + + +def runtestprotocol( + item: Item, log: bool = True, nextitem: Optional[Item] = None +) -> List[TestReport]: + hasrequest = hasattr(item, "_request") + if hasrequest and not item._request: # type: ignore[attr-defined] + # This only happens if the item is re-run, as is done by + # pytest-rerunfailures. + item._initrequest() # type: ignore[attr-defined] + rep = call_and_report(item, "setup", log) + reports = [rep] + if rep.passed: + if item.config.getoption("setupshow", False): + show_test_item(item) + if not item.config.getoption("setuponly", False): + reports.append(call_and_report(item, "call", log)) + reports.append(call_and_report(item, "teardown", log, nextitem=nextitem)) + # After all teardown hooks have been called + # want funcargs and request info to go away. + if hasrequest: + item._request = False # type: ignore[attr-defined] + item.funcargs = None # type: ignore[attr-defined] + return reports + + +def show_test_item(item: Item) -> None: + """Show test function, parameters and the fixtures of the test item.""" + tw = item.config.get_terminal_writer() + tw.line() + tw.write(" " * 8) + tw.write(item.nodeid) + used_fixtures = sorted(getattr(item, "fixturenames", [])) + if used_fixtures: + tw.write(" (fixtures used: {})".format(", ".join(used_fixtures))) + tw.flush() + + +def pytest_runtest_setup(item: Item) -> None: + _update_current_test_var(item, "setup") + item.session._setupstate.setup(item) + + +def pytest_runtest_call(item: Item) -> None: + _update_current_test_var(item, "call") + try: + del sys.last_type + del sys.last_value + del sys.last_traceback + except AttributeError: + pass + try: + item.runtest() + except Exception as e: + # Store trace info to allow postmortem debugging + sys.last_type = type(e) + sys.last_value = e + assert e.__traceback__ is not None + # Skip *this* frame + sys.last_traceback = e.__traceback__.tb_next + raise e + + +def pytest_runtest_teardown(item: Item, nextitem: Optional[Item]) -> None: + _update_current_test_var(item, "teardown") + item.session._setupstate.teardown_exact(nextitem) + _update_current_test_var(item, None) + + +def _update_current_test_var( + item: Item, when: Optional["Literal['setup', 'call', 'teardown']"] +) -> None: + """Update :envvar:`PYTEST_CURRENT_TEST` to reflect the current item and stage. + + If ``when`` is None, delete ``PYTEST_CURRENT_TEST`` from the environment. + """ + var_name = "PYTEST_CURRENT_TEST" + if when: + value = f"{item.nodeid} ({when})" + # don't allow null bytes on environment variables (see #2644, #2957) + value = value.replace("\x00", "(null)") + os.environ[var_name] = value + else: + os.environ.pop(var_name) + + +def pytest_report_teststatus(report: BaseReport) -> Optional[Tuple[str, str, str]]: + if report.when in ("setup", "teardown"): + if report.failed: + # category, shortletter, verbose-word + return "error", "E", "ERROR" + elif report.skipped: + return "skipped", "s", "SKIPPED" + else: + return "", "", "" + return None + + +# +# Implementation + + +def call_and_report( + item: Item, when: "Literal['setup', 'call', 'teardown']", log: bool = True, **kwds +) -> TestReport: + call = call_runtest_hook(item, when, **kwds) + hook = item.ihook + report: TestReport = hook.pytest_runtest_makereport(item=item, call=call) + if log: + hook.pytest_runtest_logreport(report=report) + if check_interactive_exception(call, report): + hook.pytest_exception_interact(node=item, call=call, report=report) + return report + + +def check_interactive_exception(call: "CallInfo[object]", report: BaseReport) -> bool: + """Check whether the call raised an exception that should be reported as + interactive.""" + if call.excinfo is None: + # Didn't raise. + return False + if hasattr(report, "wasxfail"): + # Exception was expected. + return False + if isinstance(call.excinfo.value, (Skipped, bdb.BdbQuit)): + # Special control flow exception. + return False + return True + + +def call_runtest_hook( + item: Item, when: "Literal['setup', 'call', 'teardown']", **kwds +) -> "CallInfo[None]": + if when == "setup": + ihook: Callable[..., None] = item.ihook.pytest_runtest_setup + elif when == "call": + ihook = item.ihook.pytest_runtest_call + elif when == "teardown": + ihook = item.ihook.pytest_runtest_teardown + else: + assert False, f"Unhandled runtest hook case: {when}" + reraise: Tuple[Type[BaseException], ...] = (Exit,) + if not item.config.getoption("usepdb", False): + reraise += (KeyboardInterrupt,) + return CallInfo.from_call( + lambda: ihook(item=item, **kwds), when=when, reraise=reraise + ) + + +TResult = TypeVar("TResult", covariant=True) + + +@final +@dataclasses.dataclass +class CallInfo(Generic[TResult]): + """Result/Exception info of a function invocation.""" + + _result: Optional[TResult] + #: The captured exception of the call, if it raised. + excinfo: Optional[ExceptionInfo[BaseException]] + #: The system time when the call started, in seconds since the epoch. + start: float + #: The system time when the call ended, in seconds since the epoch. + stop: float + #: The call duration, in seconds. + duration: float + #: The context of invocation: "collect", "setup", "call" or "teardown". + when: "Literal['collect', 'setup', 'call', 'teardown']" + + def __init__( + self, + result: Optional[TResult], + excinfo: Optional[ExceptionInfo[BaseException]], + start: float, + stop: float, + duration: float, + when: "Literal['collect', 'setup', 'call', 'teardown']", + *, + _ispytest: bool = False, + ) -> None: + check_ispytest(_ispytest) + self._result = result + self.excinfo = excinfo + self.start = start + self.stop = stop + self.duration = duration + self.when = when + + @property + def result(self) -> TResult: + """The return value of the call, if it didn't raise. + + Can only be accessed if excinfo is None. + """ + if self.excinfo is not None: + raise AttributeError(f"{self!r} has no valid result") + # The cast is safe because an exception wasn't raised, hence + # _result has the expected function return type (which may be + # None, that's why a cast and not an assert). + return cast(TResult, self._result) + + @classmethod + def from_call( + cls, + func: "Callable[[], TResult]", + when: "Literal['collect', 'setup', 'call', 'teardown']", + reraise: Optional[ + Union[Type[BaseException], Tuple[Type[BaseException], ...]] + ] = None, + ) -> "CallInfo[TResult]": + """Call func, wrapping the result in a CallInfo. + + :param func: + The function to call. Called without arguments. + :param when: + The phase in which the function is called. + :param reraise: + Exception or exceptions that shall propagate if raised by the + function, instead of being wrapped in the CallInfo. + """ + excinfo = None + start = timing.time() + precise_start = timing.perf_counter() + try: + result: Optional[TResult] = func() + except BaseException: + excinfo = ExceptionInfo.from_current() + if reraise is not None and isinstance(excinfo.value, reraise): + raise + result = None + # use the perf counter + precise_stop = timing.perf_counter() + duration = precise_stop - precise_start + stop = timing.time() + return cls( + start=start, + stop=stop, + duration=duration, + when=when, + result=result, + excinfo=excinfo, + _ispytest=True, + ) + + def __repr__(self) -> str: + if self.excinfo is None: + return f"" + return f"" + + +def pytest_runtest_makereport(item: Item, call: CallInfo[None]) -> TestReport: + return TestReport.from_item_and_call(item, call) + + +def pytest_make_collect_report(collector: Collector) -> CollectReport: + call = CallInfo.from_call(lambda: list(collector.collect()), "collect") + longrepr: Union[None, Tuple[str, int, str], str, TerminalRepr] = None + if not call.excinfo: + outcome: Literal["passed", "skipped", "failed"] = "passed" + else: + skip_exceptions = [Skipped] + unittest = sys.modules.get("unittest") + if unittest is not None: + # Type ignored because unittest is loaded dynamically. + skip_exceptions.append(unittest.SkipTest) # type: ignore + if isinstance(call.excinfo.value, tuple(skip_exceptions)): + outcome = "skipped" + r_ = collector._repr_failure_py(call.excinfo, "line") + assert isinstance(r_, ExceptionChainRepr), repr(r_) + r = r_.reprcrash + assert r + longrepr = (str(r.path), r.lineno, r.message) + else: + outcome = "failed" + errorinfo = collector.repr_failure(call.excinfo) + if not hasattr(errorinfo, "toterminal"): + assert isinstance(errorinfo, str) + errorinfo = CollectErrorRepr(errorinfo) + longrepr = errorinfo + result = call.result if not call.excinfo else None + rep = CollectReport(collector.nodeid, outcome, longrepr, result) + rep.call = call # type: ignore # see collect_one_node + return rep + + +class SetupState: + """Shared state for setting up/tearing down test items or collectors + in a session. + + Suppose we have a collection tree as follows: + + + + + + + + The SetupState maintains a stack. The stack starts out empty: + + [] + + During the setup phase of item1, setup(item1) is called. What it does + is: + + push session to stack, run session.setup() + push mod1 to stack, run mod1.setup() + push item1 to stack, run item1.setup() + + The stack is: + + [session, mod1, item1] + + While the stack is in this shape, it is allowed to add finalizers to + each of session, mod1, item1 using addfinalizer(). + + During the teardown phase of item1, teardown_exact(item2) is called, + where item2 is the next item to item1. What it does is: + + pop item1 from stack, run its teardowns + pop mod1 from stack, run its teardowns + + mod1 was popped because it ended its purpose with item1. The stack is: + + [session] + + During the setup phase of item2, setup(item2) is called. What it does + is: + + push mod2 to stack, run mod2.setup() + push item2 to stack, run item2.setup() + + Stack: + + [session, mod2, item2] + + During the teardown phase of item2, teardown_exact(None) is called, + because item2 is the last item. What it does is: + + pop item2 from stack, run its teardowns + pop mod2 from stack, run its teardowns + pop session from stack, run its teardowns + + Stack: + + [] + + The end! + """ + + def __init__(self) -> None: + # The stack is in the dict insertion order. + self.stack: Dict[ + Node, + Tuple[ + # Node's finalizers. + List[Callable[[], object]], + # Node's exception, if its setup raised. + Optional[Union[OutcomeException, Exception]], + ], + ] = {} + + def setup(self, item: Item) -> None: + """Setup objects along the collector chain to the item.""" + needed_collectors = item.listchain() + + # If a collector fails its setup, fail its entire subtree of items. + # The setup is not retried for each item - the same exception is used. + for col, (finalizers, exc) in self.stack.items(): + assert col in needed_collectors, "previous item was not torn down properly" + if exc: + raise exc + + for col in needed_collectors[len(self.stack) :]: + assert col not in self.stack + # Push onto the stack. + self.stack[col] = ([col.teardown], None) + try: + col.setup() + except TEST_OUTCOME as exc: + self.stack[col] = (self.stack[col][0], exc) + raise exc + + def addfinalizer(self, finalizer: Callable[[], object], node: Node) -> None: + """Attach a finalizer to the given node. + + The node must be currently active in the stack. + """ + assert node and not isinstance(node, tuple) + assert callable(finalizer) + assert node in self.stack, (node, self.stack) + self.stack[node][0].append(finalizer) + + def teardown_exact(self, nextitem: Optional[Item]) -> None: + """Teardown the current stack up until reaching nodes that nextitem + also descends from. + + When nextitem is None (meaning we're at the last item), the entire + stack is torn down. + """ + needed_collectors = nextitem and nextitem.listchain() or [] + exceptions: List[BaseException] = [] + while self.stack: + if list(self.stack.keys()) == needed_collectors[: len(self.stack)]: + break + node, (finalizers, _) = self.stack.popitem() + these_exceptions = [] + while finalizers: + fin = finalizers.pop() + try: + fin() + except TEST_OUTCOME as e: + these_exceptions.append(e) + + if len(these_exceptions) == 1: + exceptions.extend(these_exceptions) + elif these_exceptions: + msg = f"errors while tearing down {node!r}" + exceptions.append(BaseExceptionGroup(msg, these_exceptions[::-1])) + + if len(exceptions) == 1: + raise exceptions[0] + elif exceptions: + raise BaseExceptionGroup("errors during test teardown", exceptions[::-1]) + if nextitem is None: + assert not self.stack + + +def collect_one_node(collector: Collector) -> CollectReport: + ihook = collector.ihook + ihook.pytest_collectstart(collector=collector) + rep: CollectReport = ihook.pytest_make_collect_report(collector=collector) + call = rep.__dict__.pop("call", None) + if call and check_interactive_exception(call, rep): + ihook.pytest_exception_interact(node=collector, call=call, report=rep) + return rep diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/scope.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/scope.py new file mode 100644 index 000000000..7a746fb9f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/scope.py @@ -0,0 +1,91 @@ +""" +Scope definition and related utilities. + +Those are defined here, instead of in the 'fixtures' module because +their use is spread across many other pytest modules, and centralizing it in 'fixtures' +would cause circular references. + +Also this makes the module light to import, as it should. +""" +from enum import Enum +from functools import total_ordering +from typing import Optional +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + from typing_extensions import Literal + + _ScopeName = Literal["session", "package", "module", "class", "function"] + + +@total_ordering +class Scope(Enum): + """ + Represents one of the possible fixture scopes in pytest. + + Scopes are ordered from lower to higher, that is: + + ->>> higher ->>> + + Function < Class < Module < Package < Session + + <<<- lower <<<- + """ + + # Scopes need to be listed from lower to higher. + Function: "_ScopeName" = "function" + Class: "_ScopeName" = "class" + Module: "_ScopeName" = "module" + Package: "_ScopeName" = "package" + Session: "_ScopeName" = "session" + + def next_lower(self) -> "Scope": + """Return the next lower scope.""" + index = _SCOPE_INDICES[self] + if index == 0: + raise ValueError(f"{self} is the lower-most scope") + return _ALL_SCOPES[index - 1] + + def next_higher(self) -> "Scope": + """Return the next higher scope.""" + index = _SCOPE_INDICES[self] + if index == len(_SCOPE_INDICES) - 1: + raise ValueError(f"{self} is the upper-most scope") + return _ALL_SCOPES[index + 1] + + def __lt__(self, other: "Scope") -> bool: + self_index = _SCOPE_INDICES[self] + other_index = _SCOPE_INDICES[other] + return self_index < other_index + + @classmethod + def from_user( + cls, scope_name: "_ScopeName", descr: str, where: Optional[str] = None + ) -> "Scope": + """ + Given a scope name from the user, return the equivalent Scope enum. Should be used + whenever we want to convert a user provided scope name to its enum object. + + If the scope name is invalid, construct a user friendly message and call pytest.fail. + """ + from _pytest.outcomes import fail + + try: + # Holding this reference is necessary for mypy at the moment. + scope = Scope(scope_name) + except ValueError: + fail( + "{} {}got an unexpected scope value '{}'".format( + descr, f"from {where} " if where else "", scope_name + ), + pytrace=False, + ) + return scope + + +_ALL_SCOPES = list(Scope) +_SCOPE_INDICES = {scope: index for index, scope in enumerate(_ALL_SCOPES)} + + +# Ordered list of scopes which can contain many tests (in practice all except Function). +HIGH_SCOPES = [x for x in Scope if x is not Scope.Function] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/setuponly.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/setuponly.py new file mode 100644 index 000000000..583590d6b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/setuponly.py @@ -0,0 +1,97 @@ +from typing import Generator +from typing import Optional +from typing import Union + +import pytest +from _pytest._io.saferepr import saferepr +from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config.argparsing import Parser +from _pytest.fixtures import FixtureDef +from _pytest.fixtures import SubRequest +from _pytest.scope import Scope + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("debugconfig") + group.addoption( + "--setuponly", + "--setup-only", + action="store_true", + help="Only setup fixtures, do not execute tests", + ) + group.addoption( + "--setupshow", + "--setup-show", + action="store_true", + help="Show setup of fixtures while executing tests", + ) + + +@pytest.hookimpl(hookwrapper=True) +def pytest_fixture_setup( + fixturedef: FixtureDef[object], request: SubRequest +) -> Generator[None, None, None]: + yield + if request.config.option.setupshow: + if hasattr(request, "param"): + # Save the fixture parameter so ._show_fixture_action() can + # display it now and during the teardown (in .finish()). + if fixturedef.ids: + if callable(fixturedef.ids): + param = fixturedef.ids(request.param) + else: + param = fixturedef.ids[request.param_index] + else: + param = request.param + fixturedef.cached_param = param # type: ignore[attr-defined] + _show_fixture_action(fixturedef, "SETUP") + + +def pytest_fixture_post_finalizer(fixturedef: FixtureDef[object]) -> None: + if fixturedef.cached_result is not None: + config = fixturedef._fixturemanager.config + if config.option.setupshow: + _show_fixture_action(fixturedef, "TEARDOWN") + if hasattr(fixturedef, "cached_param"): + del fixturedef.cached_param # type: ignore[attr-defined] + + +def _show_fixture_action(fixturedef: FixtureDef[object], msg: str) -> None: + config = fixturedef._fixturemanager.config + capman = config.pluginmanager.getplugin("capturemanager") + if capman: + capman.suspend_global_capture() + + tw = config.get_terminal_writer() + tw.line() + # Use smaller indentation the higher the scope: Session = 0, Package = 1, etc. + scope_indent = list(reversed(Scope)).index(fixturedef._scope) + tw.write(" " * 2 * scope_indent) + tw.write( + "{step} {scope} {fixture}".format( + step=msg.ljust(8), # align the output to TEARDOWN + scope=fixturedef.scope[0].upper(), + fixture=fixturedef.argname, + ) + ) + + if msg == "SETUP": + deps = sorted(arg for arg in fixturedef.argnames if arg != "request") + if deps: + tw.write(" (fixtures used: {})".format(", ".join(deps))) + + if hasattr(fixturedef, "cached_param"): + tw.write(f"[{saferepr(fixturedef.cached_param, maxsize=42)}]") # type: ignore[attr-defined] + + tw.flush() + + if capman: + capman.resume_global_capture() + + +@pytest.hookimpl(tryfirst=True) +def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]: + if config.option.setuponly: + config.option.setupshow = True + return None diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/setupplan.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/setupplan.py new file mode 100644 index 000000000..1a4ebdd99 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/setupplan.py @@ -0,0 +1,40 @@ +from typing import Optional +from typing import Union + +import pytest +from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config.argparsing import Parser +from _pytest.fixtures import FixtureDef +from _pytest.fixtures import SubRequest + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("debugconfig") + group.addoption( + "--setupplan", + "--setup-plan", + action="store_true", + help="Show what fixtures and tests would be executed but " + "don't execute anything", + ) + + +@pytest.hookimpl(tryfirst=True) +def pytest_fixture_setup( + fixturedef: FixtureDef[object], request: SubRequest +) -> Optional[object]: + # Will return a dummy fixture if the setuponly option is provided. + if request.config.option.setupplan: + my_cache_key = fixturedef.cache_key(request) + fixturedef.cached_result = (None, my_cache_key, None) + return fixturedef.cached_result + return None + + +@pytest.hookimpl(tryfirst=True) +def pytest_cmdline_main(config: Config) -> Optional[Union[int, ExitCode]]: + if config.option.setupplan: + config.option.setuponly = True + config.option.setupshow = True + return None diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/skipping.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/skipping.py new file mode 100644 index 000000000..26ce73758 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/skipping.py @@ -0,0 +1,297 @@ +"""Support for skip/xfail functions and markers.""" +import dataclasses +import os +import platform +import sys +import traceback +from collections.abc import Mapping +from typing import Generator +from typing import Optional +from typing import Tuple +from typing import Type + +from _pytest.config import Config +from _pytest.config import hookimpl +from _pytest.config.argparsing import Parser +from _pytest.mark.structures import Mark +from _pytest.nodes import Item +from _pytest.outcomes import fail +from _pytest.outcomes import skip +from _pytest.outcomes import xfail +from _pytest.reports import BaseReport +from _pytest.runner import CallInfo +from _pytest.stash import StashKey + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("general") + group.addoption( + "--runxfail", + action="store_true", + dest="runxfail", + default=False, + help="Report the results of xfail tests as if they were not marked", + ) + + parser.addini( + "xfail_strict", + "Default for the strict parameter of xfail " + "markers when not given explicitly (default: False)", + default=False, + type="bool", + ) + + +def pytest_configure(config: Config) -> None: + if config.option.runxfail: + # yay a hack + import pytest + + old = pytest.xfail + config.add_cleanup(lambda: setattr(pytest, "xfail", old)) + + def nop(*args, **kwargs): + pass + + nop.Exception = xfail.Exception # type: ignore[attr-defined] + setattr(pytest, "xfail", nop) + + config.addinivalue_line( + "markers", + "skip(reason=None): skip the given test function with an optional reason. " + 'Example: skip(reason="no way of currently testing this") skips the ' + "test.", + ) + config.addinivalue_line( + "markers", + "skipif(condition, ..., *, reason=...): " + "skip the given test function if any of the conditions evaluate to True. " + "Example: skipif(sys.platform == 'win32') skips the test if we are on the win32 platform. " + "See https://docs.pytest.org/en/stable/reference/reference.html#pytest-mark-skipif", + ) + config.addinivalue_line( + "markers", + "xfail(condition, ..., *, reason=..., run=True, raises=None, strict=xfail_strict): " + "mark the test function as an expected failure if any of the conditions " + "evaluate to True. Optionally specify a reason for better reporting " + "and run=False if you don't even want to execute the test function. " + "If only specific exception(s) are expected, you can list them in " + "raises, and if the test fails in other ways, it will be reported as " + "a true failure. See https://docs.pytest.org/en/stable/reference/reference.html#pytest-mark-xfail", + ) + + +def evaluate_condition(item: Item, mark: Mark, condition: object) -> Tuple[bool, str]: + """Evaluate a single skipif/xfail condition. + + If an old-style string condition is given, it is eval()'d, otherwise the + condition is bool()'d. If this fails, an appropriately formatted pytest.fail + is raised. + + Returns (result, reason). The reason is only relevant if the result is True. + """ + # String condition. + if isinstance(condition, str): + globals_ = { + "os": os, + "sys": sys, + "platform": platform, + "config": item.config, + } + for dictionary in reversed( + item.ihook.pytest_markeval_namespace(config=item.config) + ): + if not isinstance(dictionary, Mapping): + raise ValueError( + "pytest_markeval_namespace() needs to return a dict, got {!r}".format( + dictionary + ) + ) + globals_.update(dictionary) + if hasattr(item, "obj"): + globals_.update(item.obj.__globals__) # type: ignore[attr-defined] + try: + filename = f"<{mark.name} condition>" + condition_code = compile(condition, filename, "eval") + result = eval(condition_code, globals_) + except SyntaxError as exc: + msglines = [ + "Error evaluating %r condition" % mark.name, + " " + condition, + " " + " " * (exc.offset or 0) + "^", + "SyntaxError: invalid syntax", + ] + fail("\n".join(msglines), pytrace=False) + except Exception as exc: + msglines = [ + "Error evaluating %r condition" % mark.name, + " " + condition, + *traceback.format_exception_only(type(exc), exc), + ] + fail("\n".join(msglines), pytrace=False) + + # Boolean condition. + else: + try: + result = bool(condition) + except Exception as exc: + msglines = [ + "Error evaluating %r condition as a boolean" % mark.name, + *traceback.format_exception_only(type(exc), exc), + ] + fail("\n".join(msglines), pytrace=False) + + reason = mark.kwargs.get("reason", None) + if reason is None: + if isinstance(condition, str): + reason = "condition: " + condition + else: + # XXX better be checked at collection time + msg = ( + "Error evaluating %r: " % mark.name + + "you need to specify reason=STRING when using booleans as conditions." + ) + fail(msg, pytrace=False) + + return result, reason + + +@dataclasses.dataclass(frozen=True) +class Skip: + """The result of evaluate_skip_marks().""" + + reason: str = "unconditional skip" + + +def evaluate_skip_marks(item: Item) -> Optional[Skip]: + """Evaluate skip and skipif marks on item, returning Skip if triggered.""" + for mark in item.iter_markers(name="skipif"): + if "condition" not in mark.kwargs: + conditions = mark.args + else: + conditions = (mark.kwargs["condition"],) + + # Unconditional. + if not conditions: + reason = mark.kwargs.get("reason", "") + return Skip(reason) + + # If any of the conditions are true. + for condition in conditions: + result, reason = evaluate_condition(item, mark, condition) + if result: + return Skip(reason) + + for mark in item.iter_markers(name="skip"): + try: + return Skip(*mark.args, **mark.kwargs) + except TypeError as e: + raise TypeError(str(e) + " - maybe you meant pytest.mark.skipif?") from None + + return None + + +@dataclasses.dataclass(frozen=True) +class Xfail: + """The result of evaluate_xfail_marks().""" + + __slots__ = ("reason", "run", "strict", "raises") + + reason: str + run: bool + strict: bool + raises: Optional[Tuple[Type[BaseException], ...]] + + +def evaluate_xfail_marks(item: Item) -> Optional[Xfail]: + """Evaluate xfail marks on item, returning Xfail if triggered.""" + for mark in item.iter_markers(name="xfail"): + run = mark.kwargs.get("run", True) + strict = mark.kwargs.get("strict", item.config.getini("xfail_strict")) + raises = mark.kwargs.get("raises", None) + if "condition" not in mark.kwargs: + conditions = mark.args + else: + conditions = (mark.kwargs["condition"],) + + # Unconditional. + if not conditions: + reason = mark.kwargs.get("reason", "") + return Xfail(reason, run, strict, raises) + + # If any of the conditions are true. + for condition in conditions: + result, reason = evaluate_condition(item, mark, condition) + if result: + return Xfail(reason, run, strict, raises) + + return None + + +# Saves the xfail mark evaluation. Can be refreshed during call if None. +xfailed_key = StashKey[Optional[Xfail]]() + + +@hookimpl(tryfirst=True) +def pytest_runtest_setup(item: Item) -> None: + skipped = evaluate_skip_marks(item) + if skipped: + raise skip.Exception(skipped.reason, _use_item_location=True) + + item.stash[xfailed_key] = xfailed = evaluate_xfail_marks(item) + if xfailed and not item.config.option.runxfail and not xfailed.run: + xfail("[NOTRUN] " + xfailed.reason) + + +@hookimpl(hookwrapper=True) +def pytest_runtest_call(item: Item) -> Generator[None, None, None]: + xfailed = item.stash.get(xfailed_key, None) + if xfailed is None: + item.stash[xfailed_key] = xfailed = evaluate_xfail_marks(item) + + if xfailed and not item.config.option.runxfail and not xfailed.run: + xfail("[NOTRUN] " + xfailed.reason) + + yield + + # The test run may have added an xfail mark dynamically. + xfailed = item.stash.get(xfailed_key, None) + if xfailed is None: + item.stash[xfailed_key] = xfailed = evaluate_xfail_marks(item) + + +@hookimpl(hookwrapper=True) +def pytest_runtest_makereport(item: Item, call: CallInfo[None]): + outcome = yield + rep = outcome.get_result() + xfailed = item.stash.get(xfailed_key, None) + if item.config.option.runxfail: + pass # don't interfere + elif call.excinfo and isinstance(call.excinfo.value, xfail.Exception): + assert call.excinfo.value.msg is not None + rep.wasxfail = "reason: " + call.excinfo.value.msg + rep.outcome = "skipped" + elif not rep.skipped and xfailed: + if call.excinfo: + raises = xfailed.raises + if raises is not None and not isinstance(call.excinfo.value, raises): + rep.outcome = "failed" + else: + rep.outcome = "skipped" + rep.wasxfail = xfailed.reason + elif call.when == "call": + if xfailed.strict: + rep.outcome = "failed" + rep.longrepr = "[XPASS(strict)] " + xfailed.reason + else: + rep.outcome = "passed" + rep.wasxfail = xfailed.reason + + +def pytest_report_teststatus(report: BaseReport) -> Optional[Tuple[str, str, str]]: + if hasattr(report, "wasxfail"): + if report.skipped: + return "xfailed", "x", "XFAIL" + elif report.passed: + return "xpassed", "X", "XPASS" + return None diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/stash.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/stash.py new file mode 100644 index 000000000..e61d75b95 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/stash.py @@ -0,0 +1,112 @@ +from typing import Any +from typing import cast +from typing import Dict +from typing import Generic +from typing import TypeVar +from typing import Union + + +__all__ = ["Stash", "StashKey"] + + +T = TypeVar("T") +D = TypeVar("D") + + +class StashKey(Generic[T]): + """``StashKey`` is an object used as a key to a :class:`Stash`. + + A ``StashKey`` is associated with the type ``T`` of the value of the key. + + A ``StashKey`` is unique and cannot conflict with another key. + """ + + __slots__ = () + + +class Stash: + r"""``Stash`` is a type-safe heterogeneous mutable mapping that + allows keys and value types to be defined separately from + where it (the ``Stash``) is created. + + Usually you will be given an object which has a ``Stash``, for example + :class:`~pytest.Config` or a :class:`~_pytest.nodes.Node`: + + .. code-block:: python + + stash: Stash = some_object.stash + + If a module or plugin wants to store data in this ``Stash``, it creates + :class:`StashKey`\s for its keys (at the module level): + + .. code-block:: python + + # At the top-level of the module + some_str_key = StashKey[str]() + some_bool_key = StashKey[bool]() + + To store information: + + .. code-block:: python + + # Value type must match the key. + stash[some_str_key] = "value" + stash[some_bool_key] = True + + To retrieve the information: + + .. code-block:: python + + # The static type of some_str is str. + some_str = stash[some_str_key] + # The static type of some_bool is bool. + some_bool = stash[some_bool_key] + """ + + __slots__ = ("_storage",) + + def __init__(self) -> None: + self._storage: Dict[StashKey[Any], object] = {} + + def __setitem__(self, key: StashKey[T], value: T) -> None: + """Set a value for key.""" + self._storage[key] = value + + def __getitem__(self, key: StashKey[T]) -> T: + """Get the value for key. + + Raises ``KeyError`` if the key wasn't set before. + """ + return cast(T, self._storage[key]) + + def get(self, key: StashKey[T], default: D) -> Union[T, D]: + """Get the value for key, or return default if the key wasn't set + before.""" + try: + return self[key] + except KeyError: + return default + + def setdefault(self, key: StashKey[T], default: T) -> T: + """Return the value of key if already set, otherwise set the value + of key to default and return default.""" + try: + return self[key] + except KeyError: + self[key] = default + return default + + def __delitem__(self, key: StashKey[T]) -> None: + """Delete the value for key. + + Raises ``KeyError`` if the key wasn't set before. + """ + del self._storage[key] + + def __contains__(self, key: StashKey[T]) -> bool: + """Return whether key was set.""" + return key in self._storage + + def __len__(self) -> int: + """Return how many items exist in the stash.""" + return len(self._storage) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/stepwise.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/stepwise.py new file mode 100644 index 000000000..74ad9dbd4 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/stepwise.py @@ -0,0 +1,130 @@ +from typing import List +from typing import Optional +from typing import TYPE_CHECKING + +import pytest +from _pytest import nodes +from _pytest.config import Config +from _pytest.config.argparsing import Parser +from _pytest.main import Session +from _pytest.reports import TestReport + +if TYPE_CHECKING: + from _pytest.cacheprovider import Cache + +STEPWISE_CACHE_DIR = "cache/stepwise" + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("general") + group.addoption( + "--sw", + "--stepwise", + action="store_true", + default=False, + dest="stepwise", + help="Exit on test failure and continue from last failing test next time", + ) + group.addoption( + "--sw-skip", + "--stepwise-skip", + action="store_true", + default=False, + dest="stepwise_skip", + help="Ignore the first failing test but stop on the next failing test. " + "Implicitly enables --stepwise.", + ) + + +@pytest.hookimpl +def pytest_configure(config: Config) -> None: + if config.option.stepwise_skip: + # allow --stepwise-skip to work on it's own merits. + config.option.stepwise = True + if config.getoption("stepwise"): + config.pluginmanager.register(StepwisePlugin(config), "stepwiseplugin") + + +def pytest_sessionfinish(session: Session) -> None: + if not session.config.getoption("stepwise"): + assert session.config.cache is not None + if hasattr(session.config, "workerinput"): + # Do not update cache if this process is a xdist worker to prevent + # race conditions (#10641). + return + # Clear the list of failing tests if the plugin is not active. + session.config.cache.set(STEPWISE_CACHE_DIR, []) + + +class StepwisePlugin: + def __init__(self, config: Config) -> None: + self.config = config + self.session: Optional[Session] = None + self.report_status = "" + assert config.cache is not None + self.cache: Cache = config.cache + self.lastfailed: Optional[str] = self.cache.get(STEPWISE_CACHE_DIR, None) + self.skip: bool = config.getoption("stepwise_skip") + + def pytest_sessionstart(self, session: Session) -> None: + self.session = session + + def pytest_collection_modifyitems( + self, config: Config, items: List[nodes.Item] + ) -> None: + if not self.lastfailed: + self.report_status = "no previously failed tests, not skipping." + return + + # check all item nodes until we find a match on last failed + failed_index = None + for index, item in enumerate(items): + if item.nodeid == self.lastfailed: + failed_index = index + break + + # If the previously failed test was not found among the test items, + # do not skip any tests. + if failed_index is None: + self.report_status = "previously failed test not found, not skipping." + else: + self.report_status = f"skipping {failed_index} already passed items." + deselected = items[:failed_index] + del items[:failed_index] + config.hook.pytest_deselected(items=deselected) + + def pytest_runtest_logreport(self, report: TestReport) -> None: + if report.failed: + if self.skip: + # Remove test from the failed ones (if it exists) and unset the skip option + # to make sure the following tests will not be skipped. + if report.nodeid == self.lastfailed: + self.lastfailed = None + + self.skip = False + else: + # Mark test as the last failing and interrupt the test session. + self.lastfailed = report.nodeid + assert self.session is not None + self.session.shouldstop = ( + "Test failed, continuing from this test next run." + ) + + else: + # If the test was actually run and did pass. + if report.when == "call": + # Remove test from the failed ones, if exists. + if report.nodeid == self.lastfailed: + self.lastfailed = None + + def pytest_report_collectionfinish(self) -> Optional[str]: + if self.config.getoption("verbose") >= 0 and self.report_status: + return f"stepwise: {self.report_status}" + return None + + def pytest_sessionfinish(self) -> None: + if hasattr(self.config, "workerinput"): + # Do not update cache if this process is a xdist worker to prevent + # race conditions (#10641). + return + self.cache.set(STEPWISE_CACHE_DIR, self.lastfailed) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/terminal.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/terminal.py new file mode 100644 index 000000000..b0cdb58ce --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/terminal.py @@ -0,0 +1,1481 @@ +"""Terminal reporting of the full testing process. + +This is a good source for looking at the various reporting hooks. +""" +import argparse +import dataclasses +import datetime +import inspect +import platform +import sys +import textwrap +import warnings +from collections import Counter +from functools import partial +from pathlib import Path +from typing import Any +from typing import Callable +from typing import cast +from typing import ClassVar +from typing import Dict +from typing import Generator +from typing import List +from typing import Mapping +from typing import NamedTuple +from typing import Optional +from typing import Sequence +from typing import Set +from typing import TextIO +from typing import Tuple +from typing import TYPE_CHECKING +from typing import Union + +import pluggy + +import _pytest._version +from _pytest import nodes +from _pytest import timing +from _pytest._code import ExceptionInfo +from _pytest._code.code import ExceptionRepr +from _pytest._io import TerminalWriter +from _pytest._io.wcwidth import wcswidth +from _pytest.assertion.util import running_on_ci +from _pytest.compat import final +from _pytest.config import _PluggyPlugin +from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config import hookimpl +from _pytest.config.argparsing import Parser +from _pytest.nodes import Item +from _pytest.nodes import Node +from _pytest.pathlib import absolutepath +from _pytest.pathlib import bestrelpath +from _pytest.reports import BaseReport +from _pytest.reports import CollectReport +from _pytest.reports import TestReport + +if TYPE_CHECKING: + from typing_extensions import Literal + + from _pytest.main import Session + + +REPORT_COLLECTING_RESOLUTION = 0.5 + +KNOWN_TYPES = ( + "failed", + "passed", + "skipped", + "deselected", + "xfailed", + "xpassed", + "warnings", + "error", +) + +_REPORTCHARS_DEFAULT = "fE" + + +class MoreQuietAction(argparse.Action): + """A modified copy of the argparse count action which counts down and updates + the legacy quiet attribute at the same time. + + Used to unify verbosity handling. + """ + + def __init__( + self, + option_strings: Sequence[str], + dest: str, + default: object = None, + required: bool = False, + help: Optional[str] = None, + ) -> None: + super().__init__( + option_strings=option_strings, + dest=dest, + nargs=0, + default=default, + required=required, + help=help, + ) + + def __call__( + self, + parser: argparse.ArgumentParser, + namespace: argparse.Namespace, + values: Union[str, Sequence[object], None], + option_string: Optional[str] = None, + ) -> None: + new_count = getattr(namespace, self.dest, 0) - 1 + setattr(namespace, self.dest, new_count) + # todo Deprecate config.quiet + namespace.quiet = getattr(namespace, "quiet", 0) + 1 + + +class TestShortLogReport(NamedTuple): + """Used to store the test status result category, shortletter and verbose word. + For example ``"rerun", "R", ("RERUN", {"yellow": True})``. + + :ivar category: + The class of result, for example ``“passed”``, ``“skipped”``, ``“error”``, or the empty string. + + :ivar letter: + The short letter shown as testing progresses, for example ``"."``, ``"s"``, ``"E"``, or the empty string. + + :ivar word: + Verbose word is shown as testing progresses in verbose mode, for example ``"PASSED"``, ``"SKIPPED"``, + ``"ERROR"``, or the empty string. + """ + + category: str + letter: str + word: Union[str, Tuple[str, Mapping[str, bool]]] + + +def pytest_addoption(parser: Parser) -> None: + group = parser.getgroup("terminal reporting", "Reporting", after="general") + group._addoption( + "-v", + "--verbose", + action="count", + default=0, + dest="verbose", + help="Increase verbosity", + ) + group._addoption( + "--no-header", + action="store_true", + default=False, + dest="no_header", + help="Disable header", + ) + group._addoption( + "--no-summary", + action="store_true", + default=False, + dest="no_summary", + help="Disable summary", + ) + group._addoption( + "-q", + "--quiet", + action=MoreQuietAction, + default=0, + dest="verbose", + help="Decrease verbosity", + ) + group._addoption( + "--verbosity", + dest="verbose", + type=int, + default=0, + help="Set verbosity. Default: 0.", + ) + group._addoption( + "-r", + action="store", + dest="reportchars", + default=_REPORTCHARS_DEFAULT, + metavar="chars", + help="Show extra test summary info as specified by chars: (f)ailed, " + "(E)rror, (s)kipped, (x)failed, (X)passed, " + "(p)assed, (P)assed with output, (a)ll except passed (p/P), or (A)ll. " + "(w)arnings are enabled by default (see --disable-warnings), " + "'N' can be used to reset the list. (default: 'fE').", + ) + group._addoption( + "--disable-warnings", + "--disable-pytest-warnings", + default=False, + dest="disable_warnings", + action="store_true", + help="Disable warnings summary", + ) + group._addoption( + "-l", + "--showlocals", + action="store_true", + dest="showlocals", + default=False, + help="Show locals in tracebacks (disabled by default)", + ) + group._addoption( + "--no-showlocals", + action="store_false", + dest="showlocals", + help="Hide locals in tracebacks (negate --showlocals passed through addopts)", + ) + group._addoption( + "--tb", + metavar="style", + action="store", + dest="tbstyle", + default="auto", + choices=["auto", "long", "short", "no", "line", "native"], + help="Traceback print mode (auto/long/short/line/native/no)", + ) + group._addoption( + "--show-capture", + action="store", + dest="showcapture", + choices=["no", "stdout", "stderr", "log", "all"], + default="all", + help="Controls how captured stdout/stderr/log is shown on failed tests. " + "Default: all.", + ) + group._addoption( + "--fulltrace", + "--full-trace", + action="store_true", + default=False, + help="Don't cut any tracebacks (default is to cut)", + ) + group._addoption( + "--color", + metavar="color", + action="store", + dest="color", + default="auto", + choices=["yes", "no", "auto"], + help="Color terminal output (yes/no/auto)", + ) + group._addoption( + "--code-highlight", + default="yes", + choices=["yes", "no"], + help="Whether code should be highlighted (only if --color is also enabled). " + "Default: yes.", + ) + + parser.addini( + "console_output_style", + help='Console output: "classic", or with additional progress information ' + '("progress" (percentage) | "count" | "progress-even-when-capture-no" (forces ' + "progress even when capture=no)", + default="progress", + ) + + +def pytest_configure(config: Config) -> None: + reporter = TerminalReporter(config, sys.stdout) + config.pluginmanager.register(reporter, "terminalreporter") + if config.option.debug or config.option.traceconfig: + + def mywriter(tags, args): + msg = " ".join(map(str, args)) + reporter.write_line("[traceconfig] " + msg) + + config.trace.root.setprocessor("pytest:config", mywriter) + + +def getreportopt(config: Config) -> str: + reportchars: str = config.option.reportchars + + old_aliases = {"F", "S"} + reportopts = "" + for char in reportchars: + if char in old_aliases: + char = char.lower() + if char == "a": + reportopts = "sxXEf" + elif char == "A": + reportopts = "PpsxXEf" + elif char == "N": + reportopts = "" + elif char not in reportopts: + reportopts += char + + if not config.option.disable_warnings and "w" not in reportopts: + reportopts = "w" + reportopts + elif config.option.disable_warnings and "w" in reportopts: + reportopts = reportopts.replace("w", "") + + return reportopts + + +@hookimpl(trylast=True) # after _pytest.runner +def pytest_report_teststatus(report: BaseReport) -> Tuple[str, str, str]: + letter = "F" + if report.passed: + letter = "." + elif report.skipped: + letter = "s" + + outcome: str = report.outcome + if report.when in ("collect", "setup", "teardown") and outcome == "failed": + outcome = "error" + letter = "E" + + return outcome, letter, outcome.upper() + + +@dataclasses.dataclass +class WarningReport: + """Simple structure to hold warnings information captured by ``pytest_warning_recorded``. + + :ivar str message: + User friendly message about the warning. + :ivar str|None nodeid: + nodeid that generated the warning (see ``get_location``). + :ivar tuple fslocation: + File system location of the source of the warning (see ``get_location``). + """ + + message: str + nodeid: Optional[str] = None + fslocation: Optional[Tuple[str, int]] = None + + count_towards_summary: ClassVar = True + + def get_location(self, config: Config) -> Optional[str]: + """Return the more user-friendly information about the location of a warning, or None.""" + if self.nodeid: + return self.nodeid + if self.fslocation: + filename, linenum = self.fslocation + relpath = bestrelpath(config.invocation_params.dir, absolutepath(filename)) + return f"{relpath}:{linenum}" + return None + + +@final +class TerminalReporter: + def __init__(self, config: Config, file: Optional[TextIO] = None) -> None: + import _pytest.config + + self.config = config + self._numcollected = 0 + self._session: Optional[Session] = None + self._showfspath: Optional[bool] = None + + self.stats: Dict[str, List[Any]] = {} + self._main_color: Optional[str] = None + self._known_types: Optional[List[str]] = None + self.startpath = config.invocation_params.dir + if file is None: + file = sys.stdout + self._tw = _pytest.config.create_terminal_writer(config, file) + self._screen_width = self._tw.fullwidth + self.currentfspath: Union[None, Path, str, int] = None + self.reportchars = getreportopt(config) + self.hasmarkup = self._tw.hasmarkup + self.isatty = file.isatty() + self._progress_nodeids_reported: Set[str] = set() + self._show_progress_info = self._determine_show_progress_info() + self._collect_report_last_write: Optional[float] = None + self._already_displayed_warnings: Optional[int] = None + self._keyboardinterrupt_memo: Optional[ExceptionRepr] = None + + def _determine_show_progress_info(self) -> "Literal['progress', 'count', False]": + """Return whether we should display progress information based on the current config.""" + # do not show progress if we are not capturing output (#3038) unless explicitly + # overridden by progress-even-when-capture-no + if ( + self.config.getoption("capture", "no") == "no" + and self.config.getini("console_output_style") + != "progress-even-when-capture-no" + ): + return False + # do not show progress if we are showing fixture setup/teardown + if self.config.getoption("setupshow", False): + return False + cfg: str = self.config.getini("console_output_style") + if cfg == "progress" or cfg == "progress-even-when-capture-no": + return "progress" + elif cfg == "count": + return "count" + else: + return False + + @property + def verbosity(self) -> int: + verbosity: int = self.config.option.verbose + return verbosity + + @property + def showheader(self) -> bool: + return self.verbosity >= 0 + + @property + def no_header(self) -> bool: + return bool(self.config.option.no_header) + + @property + def no_summary(self) -> bool: + return bool(self.config.option.no_summary) + + @property + def showfspath(self) -> bool: + if self._showfspath is None: + return self.verbosity >= 0 + return self._showfspath + + @showfspath.setter + def showfspath(self, value: Optional[bool]) -> None: + self._showfspath = value + + @property + def showlongtestinfo(self) -> bool: + return self.verbosity > 0 + + def hasopt(self, char: str) -> bool: + char = {"xfailed": "x", "skipped": "s"}.get(char, char) + return char in self.reportchars + + def write_fspath_result(self, nodeid: str, res, **markup: bool) -> None: + fspath = self.config.rootpath / nodeid.split("::")[0] + if self.currentfspath is None or fspath != self.currentfspath: + if self.currentfspath is not None and self._show_progress_info: + self._write_progress_information_filling_space() + self.currentfspath = fspath + relfspath = bestrelpath(self.startpath, fspath) + self._tw.line() + self._tw.write(relfspath + " ") + self._tw.write(res, flush=True, **markup) + + def write_ensure_prefix(self, prefix: str, extra: str = "", **kwargs) -> None: + if self.currentfspath != prefix: + self._tw.line() + self.currentfspath = prefix + self._tw.write(prefix) + if extra: + self._tw.write(extra, **kwargs) + self.currentfspath = -2 + + def ensure_newline(self) -> None: + if self.currentfspath: + self._tw.line() + self.currentfspath = None + + def wrap_write( + self, + content: str, + *, + flush: bool = False, + margin: int = 8, + line_sep: str = "\n", + **markup: bool, + ) -> None: + """Wrap message with margin for progress info.""" + width_of_current_line = self._tw.width_of_current_line + wrapped = line_sep.join( + textwrap.wrap( + " " * width_of_current_line + content, + width=self._screen_width - margin, + drop_whitespace=True, + replace_whitespace=False, + ), + ) + wrapped = wrapped[width_of_current_line:] + self._tw.write(wrapped, flush=flush, **markup) + + def write(self, content: str, *, flush: bool = False, **markup: bool) -> None: + self._tw.write(content, flush=flush, **markup) + + def flush(self) -> None: + self._tw.flush() + + def write_line(self, line: Union[str, bytes], **markup: bool) -> None: + if not isinstance(line, str): + line = str(line, errors="replace") + self.ensure_newline() + self._tw.line(line, **markup) + + def rewrite(self, line: str, **markup: bool) -> None: + """Rewinds the terminal cursor to the beginning and writes the given line. + + :param erase: + If True, will also add spaces until the full terminal width to ensure + previous lines are properly erased. + + The rest of the keyword arguments are markup instructions. + """ + erase = markup.pop("erase", False) + if erase: + fill_count = self._tw.fullwidth - len(line) - 1 + fill = " " * fill_count + else: + fill = "" + line = str(line) + self._tw.write("\r" + line + fill, **markup) + + def write_sep( + self, + sep: str, + title: Optional[str] = None, + fullwidth: Optional[int] = None, + **markup: bool, + ) -> None: + self.ensure_newline() + self._tw.sep(sep, title, fullwidth, **markup) + + def section(self, title: str, sep: str = "=", **kw: bool) -> None: + self._tw.sep(sep, title, **kw) + + def line(self, msg: str, **kw: bool) -> None: + self._tw.line(msg, **kw) + + def _add_stats(self, category: str, items: Sequence[Any]) -> None: + set_main_color = category not in self.stats + self.stats.setdefault(category, []).extend(items) + if set_main_color: + self._set_main_color() + + def pytest_internalerror(self, excrepr: ExceptionRepr) -> bool: + for line in str(excrepr).split("\n"): + self.write_line("INTERNALERROR> " + line) + return True + + def pytest_warning_recorded( + self, + warning_message: warnings.WarningMessage, + nodeid: str, + ) -> None: + from _pytest.warnings import warning_record_to_str + + fslocation = warning_message.filename, warning_message.lineno + message = warning_record_to_str(warning_message) + + warning_report = WarningReport( + fslocation=fslocation, message=message, nodeid=nodeid + ) + self._add_stats("warnings", [warning_report]) + + def pytest_plugin_registered(self, plugin: _PluggyPlugin) -> None: + if self.config.option.traceconfig: + msg = f"PLUGIN registered: {plugin}" + # XXX This event may happen during setup/teardown time + # which unfortunately captures our output here + # which garbles our output if we use self.write_line. + self.write_line(msg) + + def pytest_deselected(self, items: Sequence[Item]) -> None: + self._add_stats("deselected", items) + + def pytest_runtest_logstart( + self, nodeid: str, location: Tuple[str, Optional[int], str] + ) -> None: + # Ensure that the path is printed before the + # 1st test of a module starts running. + if self.showlongtestinfo: + line = self._locationline(nodeid, *location) + self.write_ensure_prefix(line, "") + self.flush() + elif self.showfspath: + self.write_fspath_result(nodeid, "") + self.flush() + + def pytest_runtest_logreport(self, report: TestReport) -> None: + self._tests_ran = True + rep = report + + res = TestShortLogReport( + *self.config.hook.pytest_report_teststatus(report=rep, config=self.config) + ) + category, letter, word = res.category, res.letter, res.word + if not isinstance(word, tuple): + markup = None + else: + word, markup = word + self._add_stats(category, [rep]) + if not letter and not word: + # Probably passed setup/teardown. + return + running_xdist = hasattr(rep, "node") + if markup is None: + was_xfail = hasattr(report, "wasxfail") + if rep.passed and not was_xfail: + markup = {"green": True} + elif rep.passed and was_xfail: + markup = {"yellow": True} + elif rep.failed: + markup = {"red": True} + elif rep.skipped: + markup = {"yellow": True} + else: + markup = {} + if self.verbosity <= 0: + self._tw.write(letter, **markup) + else: + self._progress_nodeids_reported.add(rep.nodeid) + line = self._locationline(rep.nodeid, *rep.location) + if not running_xdist: + self.write_ensure_prefix(line, word, **markup) + if rep.skipped or hasattr(report, "wasxfail"): + reason = _get_raw_skip_reason(rep) + if self.config.option.verbose < 2: + available_width = ( + (self._tw.fullwidth - self._tw.width_of_current_line) + - len(" [100%]") + - 1 + ) + formatted_reason = _format_trimmed( + " ({})", reason, available_width + ) + else: + formatted_reason = f" ({reason})" + + if reason and formatted_reason is not None: + self.wrap_write(formatted_reason) + if self._show_progress_info: + self._write_progress_information_filling_space() + else: + self.ensure_newline() + self._tw.write("[%s]" % rep.node.gateway.id) + if self._show_progress_info: + self._tw.write( + self._get_progress_information_message() + " ", cyan=True + ) + else: + self._tw.write(" ") + self._tw.write(word, **markup) + self._tw.write(" " + line) + self.currentfspath = -2 + self.flush() + + @property + def _is_last_item(self) -> bool: + assert self._session is not None + return len(self._progress_nodeids_reported) == self._session.testscollected + + def pytest_runtest_logfinish(self, nodeid: str) -> None: + assert self._session + if self.verbosity <= 0 and self._show_progress_info: + if self._show_progress_info == "count": + num_tests = self._session.testscollected + progress_length = len(f" [{num_tests}/{num_tests}]") + else: + progress_length = len(" [100%]") + + self._progress_nodeids_reported.add(nodeid) + + if self._is_last_item: + self._write_progress_information_filling_space() + else: + main_color, _ = self._get_main_color() + w = self._width_of_current_line + past_edge = w + progress_length + 1 >= self._screen_width + if past_edge: + msg = self._get_progress_information_message() + self._tw.write(msg + "\n", **{main_color: True}) + + def _get_progress_information_message(self) -> str: + assert self._session + collected = self._session.testscollected + if self._show_progress_info == "count": + if collected: + progress = self._progress_nodeids_reported + counter_format = f"{{:{len(str(collected))}d}}" + format_string = f" [{counter_format}/{{}}]" + return format_string.format(len(progress), collected) + return f" [ {collected} / {collected} ]" + else: + if collected: + return " [{:3d}%]".format( + len(self._progress_nodeids_reported) * 100 // collected + ) + return " [100%]" + + def _write_progress_information_filling_space(self) -> None: + color, _ = self._get_main_color() + msg = self._get_progress_information_message() + w = self._width_of_current_line + fill = self._tw.fullwidth - w - 1 + self.write(msg.rjust(fill), flush=True, **{color: True}) + + @property + def _width_of_current_line(self) -> int: + """Return the width of the current line.""" + return self._tw.width_of_current_line + + def pytest_collection(self) -> None: + if self.isatty: + if self.config.option.verbose >= 0: + self.write("collecting ... ", flush=True, bold=True) + self._collect_report_last_write = timing.time() + elif self.config.option.verbose >= 1: + self.write("collecting ... ", flush=True, bold=True) + + def pytest_collectreport(self, report: CollectReport) -> None: + if report.failed: + self._add_stats("error", [report]) + elif report.skipped: + self._add_stats("skipped", [report]) + items = [x for x in report.result if isinstance(x, Item)] + self._numcollected += len(items) + if self.isatty: + self.report_collect() + + def report_collect(self, final: bool = False) -> None: + if self.config.option.verbose < 0: + return + + if not final: + # Only write "collecting" report every 0.5s. + t = timing.time() + if ( + self._collect_report_last_write is not None + and self._collect_report_last_write > t - REPORT_COLLECTING_RESOLUTION + ): + return + self._collect_report_last_write = t + + errors = len(self.stats.get("error", [])) + skipped = len(self.stats.get("skipped", [])) + deselected = len(self.stats.get("deselected", [])) + selected = self._numcollected - deselected + line = "collected " if final else "collecting " + line += ( + str(self._numcollected) + " item" + ("" if self._numcollected == 1 else "s") + ) + if errors: + line += " / %d error%s" % (errors, "s" if errors != 1 else "") + if deselected: + line += " / %d deselected" % deselected + if skipped: + line += " / %d skipped" % skipped + if self._numcollected > selected: + line += " / %d selected" % selected + if self.isatty: + self.rewrite(line, bold=True, erase=True) + if final: + self.write("\n") + else: + self.write_line(line) + + @hookimpl(trylast=True) + def pytest_sessionstart(self, session: "Session") -> None: + self._session = session + self._sessionstarttime = timing.time() + if not self.showheader: + return + self.write_sep("=", "test session starts", bold=True) + verinfo = platform.python_version() + if not self.no_header: + msg = f"platform {sys.platform} -- Python {verinfo}" + pypy_version_info = getattr(sys, "pypy_version_info", None) + if pypy_version_info: + verinfo = ".".join(map(str, pypy_version_info[:3])) + msg += f"[pypy-{verinfo}-{pypy_version_info[3]}]" + msg += ", pytest-{}, pluggy-{}".format( + _pytest._version.version, pluggy.__version__ + ) + if ( + self.verbosity > 0 + or self.config.option.debug + or getattr(self.config.option, "pastebin", None) + ): + msg += " -- " + str(sys.executable) + self.write_line(msg) + lines = self.config.hook.pytest_report_header( + config=self.config, start_path=self.startpath + ) + self._write_report_lines_from_hooks(lines) + + def _write_report_lines_from_hooks( + self, lines: Sequence[Union[str, Sequence[str]]] + ) -> None: + for line_or_lines in reversed(lines): + if isinstance(line_or_lines, str): + self.write_line(line_or_lines) + else: + for line in line_or_lines: + self.write_line(line) + + def pytest_report_header(self, config: Config) -> List[str]: + result = [f"rootdir: {config.rootpath}"] + + if config.inipath: + result.append("configfile: " + bestrelpath(config.rootpath, config.inipath)) + + if config.args_source == Config.ArgsSource.TESTPATHS: + testpaths: List[str] = config.getini("testpaths") + result.append("testpaths: {}".format(", ".join(testpaths))) + + plugininfo = config.pluginmanager.list_plugin_distinfo() + if plugininfo: + result.append("plugins: %s" % ", ".join(_plugin_nameversions(plugininfo))) + return result + + def pytest_collection_finish(self, session: "Session") -> None: + self.report_collect(True) + + lines = self.config.hook.pytest_report_collectionfinish( + config=self.config, + start_path=self.startpath, + items=session.items, + ) + self._write_report_lines_from_hooks(lines) + + if self.config.getoption("collectonly"): + if session.items: + if self.config.option.verbose > -1: + self._tw.line("") + self._printcollecteditems(session.items) + + failed = self.stats.get("failed") + if failed: + self._tw.sep("!", "collection failures") + for rep in failed: + rep.toterminal(self._tw) + + def _printcollecteditems(self, items: Sequence[Item]) -> None: + if self.config.option.verbose < 0: + if self.config.option.verbose < -1: + counts = Counter(item.nodeid.split("::", 1)[0] for item in items) + for name, count in sorted(counts.items()): + self._tw.line("%s: %d" % (name, count)) + else: + for item in items: + self._tw.line(item.nodeid) + return + stack: List[Node] = [] + indent = "" + for item in items: + needed_collectors = item.listchain()[1:] # strip root node + while stack: + if stack == needed_collectors[: len(stack)]: + break + stack.pop() + for col in needed_collectors[len(stack) :]: + stack.append(col) + indent = (len(stack) - 1) * " " + self._tw.line(f"{indent}{col}") + if self.config.option.verbose >= 1: + obj = getattr(col, "obj", None) + doc = inspect.getdoc(obj) if obj else None + if doc: + for line in doc.splitlines(): + self._tw.line("{}{}".format(indent + " ", line)) + + @hookimpl(hookwrapper=True) + def pytest_sessionfinish( + self, session: "Session", exitstatus: Union[int, ExitCode] + ): + outcome = yield + outcome.get_result() + self._tw.line("") + summary_exit_codes = ( + ExitCode.OK, + ExitCode.TESTS_FAILED, + ExitCode.INTERRUPTED, + ExitCode.USAGE_ERROR, + ExitCode.NO_TESTS_COLLECTED, + ) + if exitstatus in summary_exit_codes and not self.no_summary: + self.config.hook.pytest_terminal_summary( + terminalreporter=self, exitstatus=exitstatus, config=self.config + ) + if session.shouldfail: + self.write_sep("!", str(session.shouldfail), red=True) + if exitstatus == ExitCode.INTERRUPTED: + self._report_keyboardinterrupt() + self._keyboardinterrupt_memo = None + elif session.shouldstop: + self.write_sep("!", str(session.shouldstop), red=True) + self.summary_stats() + + @hookimpl(hookwrapper=True) + def pytest_terminal_summary(self) -> Generator[None, None, None]: + self.summary_errors() + self.summary_failures() + self.summary_warnings() + self.summary_passes() + yield + self.short_test_summary() + # Display any extra warnings from teardown here (if any). + self.summary_warnings() + + def pytest_keyboard_interrupt(self, excinfo: ExceptionInfo[BaseException]) -> None: + self._keyboardinterrupt_memo = excinfo.getrepr(funcargs=True) + + def pytest_unconfigure(self) -> None: + if self._keyboardinterrupt_memo is not None: + self._report_keyboardinterrupt() + + def _report_keyboardinterrupt(self) -> None: + excrepr = self._keyboardinterrupt_memo + assert excrepr is not None + assert excrepr.reprcrash is not None + msg = excrepr.reprcrash.message + self.write_sep("!", msg) + if "KeyboardInterrupt" in msg: + if self.config.option.fulltrace: + excrepr.toterminal(self._tw) + else: + excrepr.reprcrash.toterminal(self._tw) + self._tw.line( + "(to show a full traceback on KeyboardInterrupt use --full-trace)", + yellow=True, + ) + + def _locationline( + self, nodeid: str, fspath: str, lineno: Optional[int], domain: str + ) -> str: + def mkrel(nodeid: str) -> str: + line = self.config.cwd_relative_nodeid(nodeid) + if domain and line.endswith(domain): + line = line[: -len(domain)] + values = domain.split("[") + values[0] = values[0].replace(".", "::") # don't replace '.' in params + line += "[".join(values) + return line + + # collect_fspath comes from testid which has a "/"-normalized path. + if fspath: + res = mkrel(nodeid) + if self.verbosity >= 2 and nodeid.split("::")[0] != fspath.replace( + "\\", nodes.SEP + ): + res += " <- " + bestrelpath(self.startpath, Path(fspath)) + else: + res = "[location]" + return res + " " + + def _getfailureheadline(self, rep): + head_line = rep.head_line + if head_line: + return head_line + return "test session" # XXX? + + def _getcrashline(self, rep): + try: + return str(rep.longrepr.reprcrash) + except AttributeError: + try: + return str(rep.longrepr)[:50] + except AttributeError: + return "" + + # + # Summaries for sessionfinish. + # + def getreports(self, name: str): + return [x for x in self.stats.get(name, ()) if not hasattr(x, "_pdbshown")] + + def summary_warnings(self) -> None: + if self.hasopt("w"): + all_warnings: Optional[List[WarningReport]] = self.stats.get("warnings") + if not all_warnings: + return + + final = self._already_displayed_warnings is not None + if final: + warning_reports = all_warnings[self._already_displayed_warnings :] + else: + warning_reports = all_warnings + self._already_displayed_warnings = len(warning_reports) + if not warning_reports: + return + + reports_grouped_by_message: Dict[str, List[WarningReport]] = {} + for wr in warning_reports: + reports_grouped_by_message.setdefault(wr.message, []).append(wr) + + def collapsed_location_report(reports: List[WarningReport]) -> str: + locations = [] + for w in reports: + location = w.get_location(self.config) + if location: + locations.append(location) + + if len(locations) < 10: + return "\n".join(map(str, locations)) + + counts_by_filename = Counter( + str(loc).split("::", 1)[0] for loc in locations + ) + return "\n".join( + "{}: {} warning{}".format(k, v, "s" if v > 1 else "") + for k, v in counts_by_filename.items() + ) + + title = "warnings summary (final)" if final else "warnings summary" + self.write_sep("=", title, yellow=True, bold=False) + for message, message_reports in reports_grouped_by_message.items(): + maybe_location = collapsed_location_report(message_reports) + if maybe_location: + self._tw.line(maybe_location) + lines = message.splitlines() + indented = "\n".join(" " + x for x in lines) + message = indented.rstrip() + else: + message = message.rstrip() + self._tw.line(message) + self._tw.line() + self._tw.line( + "-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html" + ) + + def summary_passes(self) -> None: + if self.config.option.tbstyle != "no": + if self.hasopt("P"): + reports: List[TestReport] = self.getreports("passed") + if not reports: + return + self.write_sep("=", "PASSES") + for rep in reports: + if rep.sections: + msg = self._getfailureheadline(rep) + self.write_sep("_", msg, green=True, bold=True) + self._outrep_summary(rep) + self._handle_teardown_sections(rep.nodeid) + + def _get_teardown_reports(self, nodeid: str) -> List[TestReport]: + reports = self.getreports("") + return [ + report + for report in reports + if report.when == "teardown" and report.nodeid == nodeid + ] + + def _handle_teardown_sections(self, nodeid: str) -> None: + for report in self._get_teardown_reports(nodeid): + self.print_teardown_sections(report) + + def print_teardown_sections(self, rep: TestReport) -> None: + showcapture = self.config.option.showcapture + if showcapture == "no": + return + for secname, content in rep.sections: + if showcapture != "all" and showcapture not in secname: + continue + if "teardown" in secname: + self._tw.sep("-", secname) + if content[-1:] == "\n": + content = content[:-1] + self._tw.line(content) + + def summary_failures(self) -> None: + if self.config.option.tbstyle != "no": + reports: List[BaseReport] = self.getreports("failed") + if not reports: + return + self.write_sep("=", "FAILURES") + if self.config.option.tbstyle == "line": + for rep in reports: + line = self._getcrashline(rep) + self.write_line(line) + else: + for rep in reports: + msg = self._getfailureheadline(rep) + self.write_sep("_", msg, red=True, bold=True) + self._outrep_summary(rep) + self._handle_teardown_sections(rep.nodeid) + + def summary_errors(self) -> None: + if self.config.option.tbstyle != "no": + reports: List[BaseReport] = self.getreports("error") + if not reports: + return + self.write_sep("=", "ERRORS") + for rep in self.stats["error"]: + msg = self._getfailureheadline(rep) + if rep.when == "collect": + msg = "ERROR collecting " + msg + else: + msg = f"ERROR at {rep.when} of {msg}" + self.write_sep("_", msg, red=True, bold=True) + self._outrep_summary(rep) + + def _outrep_summary(self, rep: BaseReport) -> None: + rep.toterminal(self._tw) + showcapture = self.config.option.showcapture + if showcapture == "no": + return + for secname, content in rep.sections: + if showcapture != "all" and showcapture not in secname: + continue + self._tw.sep("-", secname) + if content[-1:] == "\n": + content = content[:-1] + self._tw.line(content) + + def summary_stats(self) -> None: + if self.verbosity < -1: + return + + session_duration = timing.time() - self._sessionstarttime + (parts, main_color) = self.build_summary_stats_line() + line_parts = [] + + display_sep = self.verbosity >= 0 + if display_sep: + fullwidth = self._tw.fullwidth + for text, markup in parts: + with_markup = self._tw.markup(text, **markup) + if display_sep: + fullwidth += len(with_markup) - len(text) + line_parts.append(with_markup) + msg = ", ".join(line_parts) + + main_markup = {main_color: True} + duration = f" in {format_session_duration(session_duration)}" + duration_with_markup = self._tw.markup(duration, **main_markup) + if display_sep: + fullwidth += len(duration_with_markup) - len(duration) + msg += duration_with_markup + + if display_sep: + markup_for_end_sep = self._tw.markup("", **main_markup) + if markup_for_end_sep.endswith("\x1b[0m"): + markup_for_end_sep = markup_for_end_sep[:-4] + fullwidth += len(markup_for_end_sep) + msg += markup_for_end_sep + + if display_sep: + self.write_sep("=", msg, fullwidth=fullwidth, **main_markup) + else: + self.write_line(msg, **main_markup) + + def short_test_summary(self) -> None: + if not self.reportchars: + return + + def show_simple(lines: List[str], *, stat: str) -> None: + failed = self.stats.get(stat, []) + if not failed: + return + config = self.config + for rep in failed: + color = _color_for_type.get(stat, _color_for_type_default) + line = _get_line_with_reprcrash_message( + config, rep, self._tw, {color: True} + ) + lines.append(line) + + def show_xfailed(lines: List[str]) -> None: + xfailed = self.stats.get("xfailed", []) + for rep in xfailed: + verbose_word = rep._get_verbose_word(self.config) + markup_word = self._tw.markup( + verbose_word, **{_color_for_type["warnings"]: True} + ) + nodeid = _get_node_id_with_markup(self._tw, self.config, rep) + line = f"{markup_word} {nodeid}" + reason = rep.wasxfail + if reason: + line += " - " + str(reason) + + lines.append(line) + + def show_xpassed(lines: List[str]) -> None: + xpassed = self.stats.get("xpassed", []) + for rep in xpassed: + verbose_word = rep._get_verbose_word(self.config) + markup_word = self._tw.markup( + verbose_word, **{_color_for_type["warnings"]: True} + ) + nodeid = _get_node_id_with_markup(self._tw, self.config, rep) + reason = rep.wasxfail + lines.append(f"{markup_word} {nodeid} {reason}") + + def show_skipped(lines: List[str]) -> None: + skipped: List[CollectReport] = self.stats.get("skipped", []) + fskips = _folded_skips(self.startpath, skipped) if skipped else [] + if not fskips: + return + verbose_word = skipped[0]._get_verbose_word(self.config) + markup_word = self._tw.markup( + verbose_word, **{_color_for_type["warnings"]: True} + ) + prefix = "Skipped: " + for num, fspath, lineno, reason in fskips: + if reason.startswith(prefix): + reason = reason[len(prefix) :] + if lineno is not None: + lines.append( + "%s [%d] %s:%d: %s" % (markup_word, num, fspath, lineno, reason) + ) + else: + lines.append("%s [%d] %s: %s" % (markup_word, num, fspath, reason)) + + REPORTCHAR_ACTIONS: Mapping[str, Callable[[List[str]], None]] = { + "x": show_xfailed, + "X": show_xpassed, + "f": partial(show_simple, stat="failed"), + "s": show_skipped, + "p": partial(show_simple, stat="passed"), + "E": partial(show_simple, stat="error"), + } + + lines: List[str] = [] + for char in self.reportchars: + action = REPORTCHAR_ACTIONS.get(char) + if action: # skipping e.g. "P" (passed with output) here. + action(lines) + + if lines: + self.write_sep("=", "short test summary info", cyan=True, bold=True) + for line in lines: + self.write_line(line) + + def _get_main_color(self) -> Tuple[str, List[str]]: + if self._main_color is None or self._known_types is None or self._is_last_item: + self._set_main_color() + assert self._main_color + assert self._known_types + return self._main_color, self._known_types + + def _determine_main_color(self, unknown_type_seen: bool) -> str: + stats = self.stats + if "failed" in stats or "error" in stats: + main_color = "red" + elif "warnings" in stats or "xpassed" in stats or unknown_type_seen: + main_color = "yellow" + elif "passed" in stats or not self._is_last_item: + main_color = "green" + else: + main_color = "yellow" + return main_color + + def _set_main_color(self) -> None: + unknown_types: List[str] = [] + for found_type in self.stats.keys(): + if found_type: # setup/teardown reports have an empty key, ignore them + if found_type not in KNOWN_TYPES and found_type not in unknown_types: + unknown_types.append(found_type) + self._known_types = list(KNOWN_TYPES) + unknown_types + self._main_color = self._determine_main_color(bool(unknown_types)) + + def build_summary_stats_line(self) -> Tuple[List[Tuple[str, Dict[str, bool]]], str]: + """ + Build the parts used in the last summary stats line. + + The summary stats line is the line shown at the end, "=== 12 passed, 2 errors in Xs===". + + This function builds a list of the "parts" that make up for the text in that line, in + the example above it would be: + + [ + ("12 passed", {"green": True}), + ("2 errors", {"red": True} + ] + + That last dict for each line is a "markup dictionary", used by TerminalWriter to + color output. + + The final color of the line is also determined by this function, and is the second + element of the returned tuple. + """ + if self.config.getoption("collectonly"): + return self._build_collect_only_summary_stats_line() + else: + return self._build_normal_summary_stats_line() + + def _get_reports_to_display(self, key: str) -> List[Any]: + """Get test/collection reports for the given status key, such as `passed` or `error`.""" + reports = self.stats.get(key, []) + return [x for x in reports if getattr(x, "count_towards_summary", True)] + + def _build_normal_summary_stats_line( + self, + ) -> Tuple[List[Tuple[str, Dict[str, bool]]], str]: + main_color, known_types = self._get_main_color() + parts = [] + + for key in known_types: + reports = self._get_reports_to_display(key) + if reports: + count = len(reports) + color = _color_for_type.get(key, _color_for_type_default) + markup = {color: True, "bold": color == main_color} + parts.append(("%d %s" % pluralize(count, key), markup)) + + if not parts: + parts = [("no tests ran", {_color_for_type_default: True})] + + return parts, main_color + + def _build_collect_only_summary_stats_line( + self, + ) -> Tuple[List[Tuple[str, Dict[str, bool]]], str]: + deselected = len(self._get_reports_to_display("deselected")) + errors = len(self._get_reports_to_display("error")) + + if self._numcollected == 0: + parts = [("no tests collected", {"yellow": True})] + main_color = "yellow" + + elif deselected == 0: + main_color = "green" + collected_output = "%d %s collected" % pluralize(self._numcollected, "test") + parts = [(collected_output, {main_color: True})] + else: + all_tests_were_deselected = self._numcollected == deselected + if all_tests_were_deselected: + main_color = "yellow" + collected_output = f"no tests collected ({deselected} deselected)" + else: + main_color = "green" + selected = self._numcollected - deselected + collected_output = f"{selected}/{self._numcollected} tests collected ({deselected} deselected)" + + parts = [(collected_output, {main_color: True})] + + if errors: + main_color = _color_for_type["error"] + parts += [("%d %s" % pluralize(errors, "error"), {main_color: True})] + + return parts, main_color + + +def _get_node_id_with_markup(tw: TerminalWriter, config: Config, rep: BaseReport): + nodeid = config.cwd_relative_nodeid(rep.nodeid) + path, *parts = nodeid.split("::") + if parts: + parts_markup = tw.markup("::".join(parts), bold=True) + return path + "::" + parts_markup + else: + return path + + +def _format_trimmed(format: str, msg: str, available_width: int) -> Optional[str]: + """Format msg into format, ellipsizing it if doesn't fit in available_width. + + Returns None if even the ellipsis can't fit. + """ + # Only use the first line. + i = msg.find("\n") + if i != -1: + msg = msg[:i] + + ellipsis = "..." + format_width = wcswidth(format.format("")) + if format_width + len(ellipsis) > available_width: + return None + + if format_width + wcswidth(msg) > available_width: + available_width -= len(ellipsis) + msg = msg[:available_width] + while format_width + wcswidth(msg) > available_width: + msg = msg[:-1] + msg += ellipsis + + return format.format(msg) + + +def _get_line_with_reprcrash_message( + config: Config, rep: BaseReport, tw: TerminalWriter, word_markup: Dict[str, bool] +) -> str: + """Get summary line for a report, trying to add reprcrash message.""" + verbose_word = rep._get_verbose_word(config) + word = tw.markup(verbose_word, **word_markup) + node = _get_node_id_with_markup(tw, config, rep) + + line = f"{word} {node}" + line_width = wcswidth(line) + + try: + # Type ignored intentionally -- possible AttributeError expected. + msg = rep.longrepr.reprcrash.message # type: ignore[union-attr] + except AttributeError: + pass + else: + if not running_on_ci(): + available_width = tw.fullwidth - line_width + msg = _format_trimmed(" - {}", msg, available_width) + else: + msg = f" - {msg}" + if msg is not None: + line += msg + + return line + + +def _folded_skips( + startpath: Path, + skipped: Sequence[CollectReport], +) -> List[Tuple[int, str, Optional[int], str]]: + d: Dict[Tuple[str, Optional[int], str], List[CollectReport]] = {} + for event in skipped: + assert event.longrepr is not None + assert isinstance(event.longrepr, tuple), (event, event.longrepr) + assert len(event.longrepr) == 3, (event, event.longrepr) + fspath, lineno, reason = event.longrepr + # For consistency, report all fspaths in relative form. + fspath = bestrelpath(startpath, Path(fspath)) + keywords = getattr(event, "keywords", {}) + # Folding reports with global pytestmark variable. + # This is a workaround, because for now we cannot identify the scope of a skip marker + # TODO: Revisit after marks scope would be fixed. + if ( + event.when == "setup" + and "skip" in keywords + and "pytestmark" not in keywords + ): + key: Tuple[str, Optional[int], str] = (fspath, None, reason) + else: + key = (fspath, lineno, reason) + d.setdefault(key, []).append(event) + values: List[Tuple[int, str, Optional[int], str]] = [] + for key, events in d.items(): + values.append((len(events), *key)) + return values + + +_color_for_type = { + "failed": "red", + "error": "red", + "warnings": "yellow", + "passed": "green", +} +_color_for_type_default = "yellow" + + +def pluralize(count: int, noun: str) -> Tuple[int, str]: + # No need to pluralize words such as `failed` or `passed`. + if noun not in ["error", "warnings", "test"]: + return count, noun + + # The `warnings` key is plural. To avoid API breakage, we keep it that way but + # set it to singular here so we can determine plurality in the same way as we do + # for `error`. + noun = noun.replace("warnings", "warning") + + return count, noun + "s" if count != 1 else noun + + +def _plugin_nameversions(plugininfo) -> List[str]: + values: List[str] = [] + for plugin, dist in plugininfo: + # Gets us name and version! + name = "{dist.project_name}-{dist.version}".format(dist=dist) + # Questionable convenience, but it keeps things short. + if name.startswith("pytest-"): + name = name[7:] + # We decided to print python package names they can have more than one plugin. + if name not in values: + values.append(name) + return values + + +def format_session_duration(seconds: float) -> str: + """Format the given seconds in a human readable manner to show in the final summary.""" + if seconds < 60: + return f"{seconds:.2f}s" + else: + dt = datetime.timedelta(seconds=int(seconds)) + return f"{seconds:.2f}s ({dt})" + + +def _get_raw_skip_reason(report: TestReport) -> str: + """Get the reason string of a skip/xfail/xpass test report. + + The string is just the part given by the user. + """ + if hasattr(report, "wasxfail"): + reason = cast(str, report.wasxfail) + if reason.startswith("reason: "): + reason = reason[len("reason: ") :] + return reason + else: + assert report.skipped + assert isinstance(report.longrepr, tuple) + _, _, reason = report.longrepr + if reason.startswith("Skipped: "): + reason = reason[len("Skipped: ") :] + elif reason == "Skipped": + reason = "" + return reason diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/threadexception.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/threadexception.py new file mode 100644 index 000000000..43341e739 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/threadexception.py @@ -0,0 +1,88 @@ +import threading +import traceback +import warnings +from types import TracebackType +from typing import Any +from typing import Callable +from typing import Generator +from typing import Optional +from typing import Type + +import pytest + + +# Copied from cpython/Lib/test/support/threading_helper.py, with modifications. +class catch_threading_exception: + """Context manager catching threading.Thread exception using + threading.excepthook. + + Storing exc_value using a custom hook can create a reference cycle. The + reference cycle is broken explicitly when the context manager exits. + + Storing thread using a custom hook can resurrect it if it is set to an + object which is being finalized. Exiting the context manager clears the + stored object. + + Usage: + with threading_helper.catch_threading_exception() as cm: + # code spawning a thread which raises an exception + ... + # check the thread exception: use cm.args + ... + # cm.args attribute no longer exists at this point + # (to break a reference cycle) + """ + + def __init__(self) -> None: + self.args: Optional["threading.ExceptHookArgs"] = None + self._old_hook: Optional[Callable[["threading.ExceptHookArgs"], Any]] = None + + def _hook(self, args: "threading.ExceptHookArgs") -> None: + self.args = args + + def __enter__(self) -> "catch_threading_exception": + self._old_hook = threading.excepthook + threading.excepthook = self._hook + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + assert self._old_hook is not None + threading.excepthook = self._old_hook + self._old_hook = None + del self.args + + +def thread_exception_runtest_hook() -> Generator[None, None, None]: + with catch_threading_exception() as cm: + yield + if cm.args: + thread_name = "" if cm.args.thread is None else cm.args.thread.name + msg = f"Exception in thread {thread_name}\n\n" + msg += "".join( + traceback.format_exception( + cm.args.exc_type, + cm.args.exc_value, + cm.args.exc_traceback, + ) + ) + warnings.warn(pytest.PytestUnhandledThreadExceptionWarning(msg)) + + +@pytest.hookimpl(hookwrapper=True, trylast=True) +def pytest_runtest_setup() -> Generator[None, None, None]: + yield from thread_exception_runtest_hook() + + +@pytest.hookimpl(hookwrapper=True, tryfirst=True) +def pytest_runtest_call() -> Generator[None, None, None]: + yield from thread_exception_runtest_hook() + + +@pytest.hookimpl(hookwrapper=True, tryfirst=True) +def pytest_runtest_teardown() -> Generator[None, None, None]: + yield from thread_exception_runtest_hook() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/timing.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/timing.py new file mode 100644 index 000000000..925163a58 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/timing.py @@ -0,0 +1,12 @@ +"""Indirection for time functions. + +We intentionally grab some "time" functions internally to avoid tests mocking "time" to affect +pytest runtime information (issue #185). + +Fixture "mock_timing" also interacts with this module for pytest's own tests. +""" +from time import perf_counter +from time import sleep +from time import time + +__all__ = ["perf_counter", "sleep", "time"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/tmpdir.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/tmpdir.py new file mode 100644 index 000000000..3cc2bace5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/tmpdir.py @@ -0,0 +1,324 @@ +"""Support for providing temporary directories to test functions.""" +import dataclasses +import os +import re +import tempfile +from pathlib import Path +from shutil import rmtree +from typing import Any +from typing import Dict +from typing import Generator +from typing import Optional +from typing import TYPE_CHECKING +from typing import Union + +from _pytest.nodes import Item +from _pytest.reports import CollectReport +from _pytest.stash import StashKey + +if TYPE_CHECKING: + from typing_extensions import Literal + + RetentionType = Literal["all", "failed", "none"] + + +from _pytest.config.argparsing import Parser + +from .pathlib import LOCK_TIMEOUT +from .pathlib import make_numbered_dir +from .pathlib import make_numbered_dir_with_cleanup +from .pathlib import rm_rf +from .pathlib import cleanup_dead_symlinks +from _pytest.compat import final, get_user_id +from _pytest.config import Config +from _pytest.config import ExitCode +from _pytest.config import hookimpl +from _pytest.deprecated import check_ispytest +from _pytest.fixtures import fixture +from _pytest.fixtures import FixtureRequest +from _pytest.monkeypatch import MonkeyPatch + +tmppath_result_key = StashKey[Dict[str, bool]]() + + +@final +@dataclasses.dataclass +class TempPathFactory: + """Factory for temporary directories under the common base temp directory. + + The base directory can be configured using the ``--basetemp`` option. + """ + + _given_basetemp: Optional[Path] + # pluggy TagTracerSub, not currently exposed, so Any. + _trace: Any + _basetemp: Optional[Path] + _retention_count: int + _retention_policy: "RetentionType" + + def __init__( + self, + given_basetemp: Optional[Path], + retention_count: int, + retention_policy: "RetentionType", + trace, + basetemp: Optional[Path] = None, + *, + _ispytest: bool = False, + ) -> None: + check_ispytest(_ispytest) + if given_basetemp is None: + self._given_basetemp = None + else: + # Use os.path.abspath() to get absolute path instead of resolve() as it + # does not work the same in all platforms (see #4427). + # Path.absolute() exists, but it is not public (see https://bugs.python.org/issue25012). + self._given_basetemp = Path(os.path.abspath(str(given_basetemp))) + self._trace = trace + self._retention_count = retention_count + self._retention_policy = retention_policy + self._basetemp = basetemp + + @classmethod + def from_config( + cls, + config: Config, + *, + _ispytest: bool = False, + ) -> "TempPathFactory": + """Create a factory according to pytest configuration. + + :meta private: + """ + check_ispytest(_ispytest) + count = int(config.getini("tmp_path_retention_count")) + if count < 0: + raise ValueError( + f"tmp_path_retention_count must be >= 0. Current input: {count}." + ) + + policy = config.getini("tmp_path_retention_policy") + if policy not in ("all", "failed", "none"): + raise ValueError( + f"tmp_path_retention_policy must be either all, failed, none. Current input: {policy}." + ) + + return cls( + given_basetemp=config.option.basetemp, + trace=config.trace.get("tmpdir"), + retention_count=count, + retention_policy=policy, + _ispytest=True, + ) + + def _ensure_relative_to_basetemp(self, basename: str) -> str: + basename = os.path.normpath(basename) + if (self.getbasetemp() / basename).resolve().parent != self.getbasetemp(): + raise ValueError(f"{basename} is not a normalized and relative path") + return basename + + def mktemp(self, basename: str, numbered: bool = True) -> Path: + """Create a new temporary directory managed by the factory. + + :param basename: + Directory base name, must be a relative path. + + :param numbered: + If ``True``, ensure the directory is unique by adding a numbered + suffix greater than any existing one: ``basename="foo-"`` and ``numbered=True`` + means that this function will create directories named ``"foo-0"``, + ``"foo-1"``, ``"foo-2"`` and so on. + + :returns: + The path to the new directory. + """ + basename = self._ensure_relative_to_basetemp(basename) + if not numbered: + p = self.getbasetemp().joinpath(basename) + p.mkdir(mode=0o700) + else: + p = make_numbered_dir(root=self.getbasetemp(), prefix=basename, mode=0o700) + self._trace("mktemp", p) + return p + + def getbasetemp(self) -> Path: + """Return the base temporary directory, creating it if needed. + + :returns: + The base temporary directory. + """ + if self._basetemp is not None: + return self._basetemp + + if self._given_basetemp is not None: + basetemp = self._given_basetemp + if basetemp.exists(): + rm_rf(basetemp) + basetemp.mkdir(mode=0o700) + basetemp = basetemp.resolve() + else: + from_env = os.environ.get("PYTEST_DEBUG_TEMPROOT") + temproot = Path(from_env or tempfile.gettempdir()).resolve() + user = get_user() or "unknown" + # use a sub-directory in the temproot to speed-up + # make_numbered_dir() call + rootdir = temproot.joinpath(f"pytest-of-{user}") + try: + rootdir.mkdir(mode=0o700, exist_ok=True) + except OSError: + # getuser() likely returned illegal characters for the platform, use unknown back off mechanism + rootdir = temproot.joinpath("pytest-of-unknown") + rootdir.mkdir(mode=0o700, exist_ok=True) + # Because we use exist_ok=True with a predictable name, make sure + # we are the owners, to prevent any funny business (on unix, where + # temproot is usually shared). + # Also, to keep things private, fixup any world-readable temp + # rootdir's permissions. Historically 0o755 was used, so we can't + # just error out on this, at least for a while. + uid = get_user_id() + if uid is not None: + rootdir_stat = rootdir.stat() + if rootdir_stat.st_uid != uid: + raise OSError( + f"The temporary directory {rootdir} is not owned by the current user. " + "Fix this and try again." + ) + if (rootdir_stat.st_mode & 0o077) != 0: + os.chmod(rootdir, rootdir_stat.st_mode & ~0o077) + keep = self._retention_count + if self._retention_policy == "none": + keep = 0 + basetemp = make_numbered_dir_with_cleanup( + prefix="pytest-", + root=rootdir, + keep=keep, + lock_timeout=LOCK_TIMEOUT, + mode=0o700, + ) + assert basetemp is not None, basetemp + self._basetemp = basetemp + self._trace("new basetemp", basetemp) + return basetemp + + +def get_user() -> Optional[str]: + """Return the current user name, or None if getuser() does not work + in the current environment (see #1010).""" + try: + # In some exotic environments, getpass may not be importable. + import getpass + + return getpass.getuser() + except (ImportError, KeyError): + return None + + +def pytest_configure(config: Config) -> None: + """Create a TempPathFactory and attach it to the config object. + + This is to comply with existing plugins which expect the handler to be + available at pytest_configure time, but ideally should be moved entirely + to the tmp_path_factory session fixture. + """ + mp = MonkeyPatch() + config.add_cleanup(mp.undo) + _tmp_path_factory = TempPathFactory.from_config(config, _ispytest=True) + mp.setattr(config, "_tmp_path_factory", _tmp_path_factory, raising=False) + + +def pytest_addoption(parser: Parser) -> None: + parser.addini( + "tmp_path_retention_count", + help="How many sessions should we keep the `tmp_path` directories, according to `tmp_path_retention_policy`.", + default=3, + ) + + parser.addini( + "tmp_path_retention_policy", + help="Controls which directories created by the `tmp_path` fixture are kept around, based on test outcome. " + "(all/failed/none)", + default="all", + ) + + +@fixture(scope="session") +def tmp_path_factory(request: FixtureRequest) -> TempPathFactory: + """Return a :class:`pytest.TempPathFactory` instance for the test session.""" + # Set dynamically by pytest_configure() above. + return request.config._tmp_path_factory # type: ignore + + +def _mk_tmp(request: FixtureRequest, factory: TempPathFactory) -> Path: + name = request.node.name + name = re.sub(r"[\W]", "_", name) + MAXVAL = 30 + name = name[:MAXVAL] + return factory.mktemp(name, numbered=True) + + +@fixture +def tmp_path( + request: FixtureRequest, tmp_path_factory: TempPathFactory +) -> Generator[Path, None, None]: + """Return a temporary directory path object which is unique to each test + function invocation, created as a sub directory of the base temporary + directory. + + By default, a new base temporary directory is created each test session, + and old bases are removed after 3 sessions, to aid in debugging. + This behavior can be configured with :confval:`tmp_path_retention_count` and + :confval:`tmp_path_retention_policy`. + If ``--basetemp`` is used then it is cleared each session. See :ref:`base + temporary directory`. + + The returned object is a :class:`pathlib.Path` object. + """ + + path = _mk_tmp(request, tmp_path_factory) + yield path + + # Remove the tmpdir if the policy is "failed" and the test passed. + tmp_path_factory: TempPathFactory = request.session.config._tmp_path_factory # type: ignore + policy = tmp_path_factory._retention_policy + result_dict = request.node.stash[tmppath_result_key] + + if policy == "failed" and result_dict.get("call", True): + # We do a "best effort" to remove files, but it might not be possible due to some leaked resource, + # permissions, etc, in which case we ignore it. + rmtree(path, ignore_errors=True) + + del request.node.stash[tmppath_result_key] + + +def pytest_sessionfinish(session, exitstatus: Union[int, ExitCode]): + """After each session, remove base directory if all the tests passed, + the policy is "failed", and the basetemp is not specified by a user. + """ + tmp_path_factory: TempPathFactory = session.config._tmp_path_factory + basetemp = tmp_path_factory._basetemp + if basetemp is None: + return + + policy = tmp_path_factory._retention_policy + if ( + exitstatus == 0 + and policy == "failed" + and tmp_path_factory._given_basetemp is None + ): + if basetemp.is_dir(): + # We do a "best effort" to remove files, but it might not be possible due to some leaked resource, + # permissions, etc, in which case we ignore it. + rmtree(basetemp, ignore_errors=True) + + # Remove dead symlinks. + if basetemp.is_dir(): + cleanup_dead_symlinks(basetemp) + + +@hookimpl(tryfirst=True, hookwrapper=True) +def pytest_runtest_makereport(item: Item, call): + outcome = yield + result: CollectReport = outcome.get_result() + + empty: Dict[str, bool] = {} + item.stash.setdefault(tmppath_result_key, empty)[result.when] = result.passed diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/unittest.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/unittest.py new file mode 100644 index 000000000..d42a12a3a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/unittest.py @@ -0,0 +1,421 @@ +"""Discover and run std-library "unittest" style tests.""" +import sys +import traceback +import types +from typing import Any +from typing import Callable +from typing import Generator +from typing import Iterable +from typing import List +from typing import Optional +from typing import Tuple +from typing import Type +from typing import TYPE_CHECKING +from typing import Union + +import _pytest._code +import pytest +from _pytest.compat import getimfunc +from _pytest.compat import is_async_function +from _pytest.config import hookimpl +from _pytest.fixtures import FixtureRequest +from _pytest.nodes import Collector +from _pytest.nodes import Item +from _pytest.outcomes import exit +from _pytest.outcomes import fail +from _pytest.outcomes import skip +from _pytest.outcomes import xfail +from _pytest.python import Class +from _pytest.python import Function +from _pytest.python import Module +from _pytest.runner import CallInfo +from _pytest.scope import Scope + +if TYPE_CHECKING: + import unittest + import twisted.trial.unittest + + _SysExcInfoType = Union[ + Tuple[Type[BaseException], BaseException, types.TracebackType], + Tuple[None, None, None], + ] + + +def pytest_pycollect_makeitem( + collector: Union[Module, Class], name: str, obj: object +) -> Optional["UnitTestCase"]: + # Has unittest been imported and is obj a subclass of its TestCase? + try: + ut = sys.modules["unittest"] + # Type ignored because `ut` is an opaque module. + if not issubclass(obj, ut.TestCase): # type: ignore + return None + except Exception: + return None + # Yes, so let's collect it. + item: UnitTestCase = UnitTestCase.from_parent(collector, name=name, obj=obj) + return item + + +class UnitTestCase(Class): + # Marker for fixturemanger.getfixtureinfo() + # to declare that our children do not support funcargs. + nofuncargs = True + + def collect(self) -> Iterable[Union[Item, Collector]]: + from unittest import TestLoader + + cls = self.obj + if not getattr(cls, "__test__", True): + return + + skipped = _is_skipped(cls) + if not skipped: + self._inject_setup_teardown_fixtures(cls) + self._inject_setup_class_fixture() + + self.session._fixturemanager.parsefactories(self, unittest=True) + loader = TestLoader() + foundsomething = False + for name in loader.getTestCaseNames(self.obj): + x = getattr(self.obj, name) + if not getattr(x, "__test__", True): + continue + funcobj = getimfunc(x) + yield TestCaseFunction.from_parent(self, name=name, callobj=funcobj) + foundsomething = True + + if not foundsomething: + runtest = getattr(self.obj, "runTest", None) + if runtest is not None: + ut = sys.modules.get("twisted.trial.unittest", None) + # Type ignored because `ut` is an opaque module. + if ut is None or runtest != ut.TestCase.runTest: # type: ignore + yield TestCaseFunction.from_parent(self, name="runTest") + + def _inject_setup_teardown_fixtures(self, cls: type) -> None: + """Injects a hidden auto-use fixture to invoke setUpClass/setup_method and corresponding + teardown functions (#517).""" + class_fixture = _make_xunit_fixture( + cls, + "setUpClass", + "tearDownClass", + "doClassCleanups", + scope=Scope.Class, + pass_self=False, + ) + if class_fixture: + cls.__pytest_class_setup = class_fixture # type: ignore[attr-defined] + + method_fixture = _make_xunit_fixture( + cls, + "setup_method", + "teardown_method", + None, + scope=Scope.Function, + pass_self=True, + ) + if method_fixture: + cls.__pytest_method_setup = method_fixture # type: ignore[attr-defined] + + +def _make_xunit_fixture( + obj: type, + setup_name: str, + teardown_name: str, + cleanup_name: Optional[str], + scope: Scope, + pass_self: bool, +): + setup = getattr(obj, setup_name, None) + teardown = getattr(obj, teardown_name, None) + if setup is None and teardown is None: + return None + + if cleanup_name: + cleanup = getattr(obj, cleanup_name, lambda *args: None) + else: + + def cleanup(*args): + pass + + @pytest.fixture( + scope=scope.value, + autouse=True, + # Use a unique name to speed up lookup. + name=f"_unittest_{setup_name}_fixture_{obj.__qualname__}", + ) + def fixture(self, request: FixtureRequest) -> Generator[None, None, None]: + if _is_skipped(self): + reason = self.__unittest_skip_why__ + raise pytest.skip.Exception(reason, _use_item_location=True) + if setup is not None: + try: + if pass_self: + setup(self, request.function) + else: + setup() + # unittest does not call the cleanup function for every BaseException, so we + # follow this here. + except Exception: + if pass_self: + cleanup(self) + else: + cleanup() + + raise + yield + try: + if teardown is not None: + if pass_self: + teardown(self, request.function) + else: + teardown() + finally: + if pass_self: + cleanup(self) + else: + cleanup() + + return fixture + + +class TestCaseFunction(Function): + nofuncargs = True + _excinfo: Optional[List[_pytest._code.ExceptionInfo[BaseException]]] = None + _testcase: Optional["unittest.TestCase"] = None + + def _getobj(self): + assert self.parent is not None + # Unlike a regular Function in a Class, where `item.obj` returns + # a *bound* method (attached to an instance), TestCaseFunction's + # `obj` returns an *unbound* method (not attached to an instance). + # This inconsistency is probably not desirable, but needs some + # consideration before changing. + return getattr(self.parent.obj, self.originalname) # type: ignore[attr-defined] + + def setup(self) -> None: + # A bound method to be called during teardown() if set (see 'runtest()'). + self._explicit_tearDown: Optional[Callable[[], None]] = None + assert self.parent is not None + self._testcase = self.parent.obj(self.name) # type: ignore[attr-defined] + self._obj = getattr(self._testcase, self.name) + if hasattr(self, "_request"): + self._request._fillfixtures() + + def teardown(self) -> None: + if self._explicit_tearDown is not None: + self._explicit_tearDown() + self._explicit_tearDown = None + self._testcase = None + self._obj = None + + def startTest(self, testcase: "unittest.TestCase") -> None: + pass + + def _addexcinfo(self, rawexcinfo: "_SysExcInfoType") -> None: + # Unwrap potential exception info (see twisted trial support below). + rawexcinfo = getattr(rawexcinfo, "_rawexcinfo", rawexcinfo) + try: + excinfo = _pytest._code.ExceptionInfo[BaseException].from_exc_info(rawexcinfo) # type: ignore[arg-type] + # Invoke the attributes to trigger storing the traceback + # trial causes some issue there. + excinfo.value + excinfo.traceback + except TypeError: + try: + try: + values = traceback.format_exception(*rawexcinfo) + values.insert( + 0, + "NOTE: Incompatible Exception Representation, " + "displaying natively:\n\n", + ) + fail("".join(values), pytrace=False) + except (fail.Exception, KeyboardInterrupt): + raise + except BaseException: + fail( + "ERROR: Unknown Incompatible Exception " + "representation:\n%r" % (rawexcinfo,), + pytrace=False, + ) + except KeyboardInterrupt: + raise + except fail.Exception: + excinfo = _pytest._code.ExceptionInfo.from_current() + self.__dict__.setdefault("_excinfo", []).append(excinfo) + + def addError( + self, testcase: "unittest.TestCase", rawexcinfo: "_SysExcInfoType" + ) -> None: + try: + if isinstance(rawexcinfo[1], exit.Exception): + exit(rawexcinfo[1].msg) + except TypeError: + pass + self._addexcinfo(rawexcinfo) + + def addFailure( + self, testcase: "unittest.TestCase", rawexcinfo: "_SysExcInfoType" + ) -> None: + self._addexcinfo(rawexcinfo) + + def addSkip(self, testcase: "unittest.TestCase", reason: str) -> None: + try: + raise pytest.skip.Exception(reason, _use_item_location=True) + except skip.Exception: + self._addexcinfo(sys.exc_info()) + + def addExpectedFailure( + self, + testcase: "unittest.TestCase", + rawexcinfo: "_SysExcInfoType", + reason: str = "", + ) -> None: + try: + xfail(str(reason)) + except xfail.Exception: + self._addexcinfo(sys.exc_info()) + + def addUnexpectedSuccess( + self, + testcase: "unittest.TestCase", + reason: Optional["twisted.trial.unittest.Todo"] = None, + ) -> None: + msg = "Unexpected success" + if reason: + msg += f": {reason.reason}" + # Preserve unittest behaviour - fail the test. Explicitly not an XPASS. + try: + fail(msg, pytrace=False) + except fail.Exception: + self._addexcinfo(sys.exc_info()) + + def addSuccess(self, testcase: "unittest.TestCase") -> None: + pass + + def stopTest(self, testcase: "unittest.TestCase") -> None: + pass + + def addDuration(self, testcase: "unittest.TestCase", elapsed: float) -> None: + pass + + def runtest(self) -> None: + from _pytest.debugging import maybe_wrap_pytest_function_for_tracing + + assert self._testcase is not None + + maybe_wrap_pytest_function_for_tracing(self) + + # Let the unittest framework handle async functions. + if is_async_function(self.obj): + # Type ignored because self acts as the TestResult, but is not actually one. + self._testcase(result=self) # type: ignore[arg-type] + else: + # When --pdb is given, we want to postpone calling tearDown() otherwise + # when entering the pdb prompt, tearDown() would have probably cleaned up + # instance variables, which makes it difficult to debug. + # Arguably we could always postpone tearDown(), but this changes the moment where the + # TestCase instance interacts with the results object, so better to only do it + # when absolutely needed. + # We need to consider if the test itself is skipped, or the whole class. + assert isinstance(self.parent, UnitTestCase) + skipped = _is_skipped(self.obj) or _is_skipped(self.parent.obj) + if self.config.getoption("usepdb") and not skipped: + self._explicit_tearDown = self._testcase.tearDown + setattr(self._testcase, "tearDown", lambda *args: None) + + # We need to update the actual bound method with self.obj, because + # wrap_pytest_function_for_tracing replaces self.obj by a wrapper. + setattr(self._testcase, self.name, self.obj) + try: + self._testcase(result=self) # type: ignore[arg-type] + finally: + delattr(self._testcase, self.name) + + def _traceback_filter( + self, excinfo: _pytest._code.ExceptionInfo[BaseException] + ) -> _pytest._code.Traceback: + traceback = super()._traceback_filter(excinfo) + ntraceback = traceback.filter( + lambda x: not x.frame.f_globals.get("__unittest"), + ) + if not ntraceback: + ntraceback = traceback + return ntraceback + + +@hookimpl(tryfirst=True) +def pytest_runtest_makereport(item: Item, call: CallInfo[None]) -> None: + if isinstance(item, TestCaseFunction): + if item._excinfo: + call.excinfo = item._excinfo.pop(0) + try: + del call.result + except AttributeError: + pass + + # Convert unittest.SkipTest to pytest.skip. + # This is actually only needed for nose, which reuses unittest.SkipTest for + # its own nose.SkipTest. For unittest TestCases, SkipTest is already + # handled internally, and doesn't reach here. + unittest = sys.modules.get("unittest") + if ( + unittest + and call.excinfo + and isinstance(call.excinfo.value, unittest.SkipTest) # type: ignore[attr-defined] + ): + excinfo = call.excinfo + call2 = CallInfo[None].from_call( + lambda: pytest.skip(str(excinfo.value)), call.when + ) + call.excinfo = call2.excinfo + + +# Twisted trial support. + + +@hookimpl(hookwrapper=True) +def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]: + if isinstance(item, TestCaseFunction) and "twisted.trial.unittest" in sys.modules: + ut: Any = sys.modules["twisted.python.failure"] + Failure__init__ = ut.Failure.__init__ + check_testcase_implements_trial_reporter() + + def excstore( + self, exc_value=None, exc_type=None, exc_tb=None, captureVars=None + ): + if exc_value is None: + self._rawexcinfo = sys.exc_info() + else: + if exc_type is None: + exc_type = type(exc_value) + self._rawexcinfo = (exc_type, exc_value, exc_tb) + try: + Failure__init__( + self, exc_value, exc_type, exc_tb, captureVars=captureVars + ) + except TypeError: + Failure__init__(self, exc_value, exc_type, exc_tb) + + ut.Failure.__init__ = excstore + yield + ut.Failure.__init__ = Failure__init__ + else: + yield + + +def check_testcase_implements_trial_reporter(done: List[int] = []) -> None: + if done: + return + from zope.interface import classImplements + from twisted.trial.itrial import IReporter + + classImplements(TestCaseFunction, IReporter) + done.append(1) + + +def _is_skipped(obj) -> bool: + """Return True if the given object has been marked with @unittest.skip.""" + return bool(getattr(obj, "__unittest_skip__", False)) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/unraisableexception.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/unraisableexception.py new file mode 100644 index 000000000..fcb5d8237 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/unraisableexception.py @@ -0,0 +1,93 @@ +import sys +import traceback +import warnings +from types import TracebackType +from typing import Any +from typing import Callable +from typing import Generator +from typing import Optional +from typing import Type + +import pytest + + +# Copied from cpython/Lib/test/support/__init__.py, with modifications. +class catch_unraisable_exception: + """Context manager catching unraisable exception using sys.unraisablehook. + + Storing the exception value (cm.unraisable.exc_value) creates a reference + cycle. The reference cycle is broken explicitly when the context manager + exits. + + Storing the object (cm.unraisable.object) can resurrect it if it is set to + an object which is being finalized. Exiting the context manager clears the + stored object. + + Usage: + with catch_unraisable_exception() as cm: + # code creating an "unraisable exception" + ... + # check the unraisable exception: use cm.unraisable + ... + # cm.unraisable attribute no longer exists at this point + # (to break a reference cycle) + """ + + def __init__(self) -> None: + self.unraisable: Optional["sys.UnraisableHookArgs"] = None + self._old_hook: Optional[Callable[["sys.UnraisableHookArgs"], Any]] = None + + def _hook(self, unraisable: "sys.UnraisableHookArgs") -> None: + # Storing unraisable.object can resurrect an object which is being + # finalized. Storing unraisable.exc_value creates a reference cycle. + self.unraisable = unraisable + + def __enter__(self) -> "catch_unraisable_exception": + self._old_hook = sys.unraisablehook + sys.unraisablehook = self._hook + return self + + def __exit__( + self, + exc_type: Optional[Type[BaseException]], + exc_val: Optional[BaseException], + exc_tb: Optional[TracebackType], + ) -> None: + assert self._old_hook is not None + sys.unraisablehook = self._old_hook + self._old_hook = None + del self.unraisable + + +def unraisable_exception_runtest_hook() -> Generator[None, None, None]: + with catch_unraisable_exception() as cm: + yield + if cm.unraisable: + if cm.unraisable.err_msg is not None: + err_msg = cm.unraisable.err_msg + else: + err_msg = "Exception ignored in" + msg = f"{err_msg}: {cm.unraisable.object!r}\n\n" + msg += "".join( + traceback.format_exception( + cm.unraisable.exc_type, + cm.unraisable.exc_value, + cm.unraisable.exc_traceback, + ) + ) + warnings.warn(pytest.PytestUnraisableExceptionWarning(msg)) + + +@pytest.hookimpl(hookwrapper=True, tryfirst=True) +def pytest_runtest_setup() -> Generator[None, None, None]: + yield from unraisable_exception_runtest_hook() + + +@pytest.hookimpl(hookwrapper=True, tryfirst=True) +def pytest_runtest_call() -> Generator[None, None, None]: + yield from unraisable_exception_runtest_hook() + + +@pytest.hookimpl(hookwrapper=True, tryfirst=True) +def pytest_runtest_teardown() -> Generator[None, None, None]: + yield from unraisable_exception_runtest_hook() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/warning_types.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/warning_types.py new file mode 100644 index 000000000..bd5f41873 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/warning_types.py @@ -0,0 +1,170 @@ +import dataclasses +import inspect +import warnings +from types import FunctionType +from typing import Any +from typing import Generic +from typing import Type +from typing import TypeVar + +from _pytest.compat import final + + +class PytestWarning(UserWarning): + """Base class for all warnings emitted by pytest.""" + + __module__ = "pytest" + + +@final +class PytestAssertRewriteWarning(PytestWarning): + """Warning emitted by the pytest assert rewrite module.""" + + __module__ = "pytest" + + +@final +class PytestCacheWarning(PytestWarning): + """Warning emitted by the cache plugin in various situations.""" + + __module__ = "pytest" + + +@final +class PytestConfigWarning(PytestWarning): + """Warning emitted for configuration issues.""" + + __module__ = "pytest" + + +@final +class PytestCollectionWarning(PytestWarning): + """Warning emitted when pytest is not able to collect a file or symbol in a module.""" + + __module__ = "pytest" + + +class PytestDeprecationWarning(PytestWarning, DeprecationWarning): + """Warning class for features that will be removed in a future version.""" + + __module__ = "pytest" + + +class PytestRemovedIn8Warning(PytestDeprecationWarning): + """Warning class for features that will be removed in pytest 8.""" + + __module__ = "pytest" + + +class PytestReturnNotNoneWarning(PytestRemovedIn8Warning): + """Warning emitted when a test function is returning value other than None.""" + + __module__ = "pytest" + + +@final +class PytestExperimentalApiWarning(PytestWarning, FutureWarning): + """Warning category used to denote experiments in pytest. + + Use sparingly as the API might change or even be removed completely in a + future version. + """ + + __module__ = "pytest" + + @classmethod + def simple(cls, apiname: str) -> "PytestExperimentalApiWarning": + return cls( + "{apiname} is an experimental api that may change over time".format( + apiname=apiname + ) + ) + + +@final +class PytestUnhandledCoroutineWarning(PytestReturnNotNoneWarning): + """Warning emitted for an unhandled coroutine. + + A coroutine was encountered when collecting test functions, but was not + handled by any async-aware plugin. + Coroutine test functions are not natively supported. + """ + + __module__ = "pytest" + + +@final +class PytestUnknownMarkWarning(PytestWarning): + """Warning emitted on use of unknown markers. + + See :ref:`mark` for details. + """ + + __module__ = "pytest" + + +@final +class PytestUnraisableExceptionWarning(PytestWarning): + """An unraisable exception was reported. + + Unraisable exceptions are exceptions raised in :meth:`__del__ ` + implementations and similar situations when the exception cannot be raised + as normal. + """ + + __module__ = "pytest" + + +@final +class PytestUnhandledThreadExceptionWarning(PytestWarning): + """An unhandled exception occurred in a :class:`~threading.Thread`. + + Such exceptions don't propagate normally. + """ + + __module__ = "pytest" + + +_W = TypeVar("_W", bound=PytestWarning) + + +@final +@dataclasses.dataclass +class UnformattedWarning(Generic[_W]): + """A warning meant to be formatted during runtime. + + This is used to hold warnings that need to format their message at runtime, + as opposed to a direct message. + """ + + category: Type["_W"] + template: str + + def format(self, **kwargs: Any) -> _W: + """Return an instance of the warning category, formatted with given kwargs.""" + return self.category(self.template.format(**kwargs)) + + +def warn_explicit_for(method: FunctionType, message: PytestWarning) -> None: + """ + Issue the warning :param:`message` for the definition of the given :param:`method` + + this helps to log warnings for functions defined prior to finding an issue with them + (like hook wrappers being marked in a legacy mechanism) + """ + lineno = method.__code__.co_firstlineno + filename = inspect.getfile(method) + module = method.__module__ + mod_globals = method.__globals__ + try: + warnings.warn_explicit( + message, + type(message), + filename=filename, + module=module, + registry=mod_globals.setdefault("__warningregistry__", {}), + lineno=lineno, + ) + except Warning as w: + # If warnings are errors (e.g. -Werror), location information gets lost, so we add it to the message. + raise type(w)(f"{w}\n at {filename}:{lineno}") from None diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/warnings.py b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/warnings.py new file mode 100644 index 000000000..4aaa94452 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/_pytest/warnings.py @@ -0,0 +1,148 @@ +import sys +import warnings +from contextlib import contextmanager +from typing import Generator +from typing import Optional +from typing import TYPE_CHECKING + +import pytest +from _pytest.config import apply_warning_filters +from _pytest.config import Config +from _pytest.config import parse_warning_filter +from _pytest.main import Session +from _pytest.nodes import Item +from _pytest.terminal import TerminalReporter + +if TYPE_CHECKING: + from typing_extensions import Literal + + +def pytest_configure(config: Config) -> None: + config.addinivalue_line( + "markers", + "filterwarnings(warning): add a warning filter to the given test. " + "see https://docs.pytest.org/en/stable/how-to/capture-warnings.html#pytest-mark-filterwarnings ", + ) + + +@contextmanager +def catch_warnings_for_item( + config: Config, + ihook, + when: "Literal['config', 'collect', 'runtest']", + item: Optional[Item], +) -> Generator[None, None, None]: + """Context manager that catches warnings generated in the contained execution block. + + ``item`` can be None if we are not in the context of an item execution. + + Each warning captured triggers the ``pytest_warning_recorded`` hook. + """ + config_filters = config.getini("filterwarnings") + cmdline_filters = config.known_args_namespace.pythonwarnings or [] + with warnings.catch_warnings(record=True) as log: + # mypy can't infer that record=True means log is not None; help it. + assert log is not None + + if not sys.warnoptions: + # If user is not explicitly configuring warning filters, show deprecation warnings by default (#2908). + warnings.filterwarnings("always", category=DeprecationWarning) + warnings.filterwarnings("always", category=PendingDeprecationWarning) + + apply_warning_filters(config_filters, cmdline_filters) + + # apply filters from "filterwarnings" marks + nodeid = "" if item is None else item.nodeid + if item is not None: + for mark in item.iter_markers(name="filterwarnings"): + for arg in mark.args: + warnings.filterwarnings(*parse_warning_filter(arg, escape=False)) + + yield + + for warning_message in log: + ihook.pytest_warning_recorded.call_historic( + kwargs=dict( + warning_message=warning_message, + nodeid=nodeid, + when=when, + location=None, + ) + ) + + +def warning_record_to_str(warning_message: warnings.WarningMessage) -> str: + """Convert a warnings.WarningMessage to a string.""" + warn_msg = warning_message.message + msg = warnings.formatwarning( + str(warn_msg), + warning_message.category, + warning_message.filename, + warning_message.lineno, + warning_message.line, + ) + if warning_message.source is not None: + try: + import tracemalloc + except ImportError: + pass + else: + tb = tracemalloc.get_object_traceback(warning_message.source) + if tb is not None: + formatted_tb = "\n".join(tb.format()) + # Use a leading new line to better separate the (large) output + # from the traceback to the previous warning text. + msg += f"\nObject allocated at:\n{formatted_tb}" + else: + # No need for a leading new line. + url = "https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings" + msg += "Enable tracemalloc to get traceback where the object was allocated.\n" + msg += f"See {url} for more info." + return msg + + +@pytest.hookimpl(hookwrapper=True, tryfirst=True) +def pytest_runtest_protocol(item: Item) -> Generator[None, None, None]: + with catch_warnings_for_item( + config=item.config, ihook=item.ihook, when="runtest", item=item + ): + yield + + +@pytest.hookimpl(hookwrapper=True, tryfirst=True) +def pytest_collection(session: Session) -> Generator[None, None, None]: + config = session.config + with catch_warnings_for_item( + config=config, ihook=config.hook, when="collect", item=None + ): + yield + + +@pytest.hookimpl(hookwrapper=True) +def pytest_terminal_summary( + terminalreporter: TerminalReporter, +) -> Generator[None, None, None]: + config = terminalreporter.config + with catch_warnings_for_item( + config=config, ihook=config.hook, when="config", item=None + ): + yield + + +@pytest.hookimpl(hookwrapper=True) +def pytest_sessionfinish(session: Session) -> Generator[None, None, None]: + config = session.config + with catch_warnings_for_item( + config=config, ihook=config.hook, when="config", item=None + ): + yield + + +@pytest.hookimpl(hookwrapper=True) +def pytest_load_initial_conftests( + early_config: "Config", +) -> Generator[None, None, None]: + with catch_warnings_for_item( + config=early_config, ihook=early_config.hook, when="config", item=None + ): + yield diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/INSTALLER b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/LICENSE b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/LICENSE new file mode 100644 index 000000000..6013a212b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/LICENSE @@ -0,0 +1,18 @@ +Copyright (c) 2004 Istvan Albert unless otherwise noted. +Copyright (c) 2006-2010 Bob Ippolito +Copyright (2) 2010-2020 Ronald Oussoren, et. al. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to +deal in the Software without restriction, including without limitation the +rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the +Software is furnished to do so. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +IN THE SOFTWARE. diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/METADATA b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/METADATA new file mode 100644 index 000000000..589d1f5fc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/METADATA @@ -0,0 +1,293 @@ +Metadata-Version: 2.1 +Name: altgraph +Version: 0.17.4 +Summary: Python graph (network) package +Home-page: https://altgraph.readthedocs.io +Download-URL: http://pypi.python.org/pypi/altgraph +Author: Ronald Oussoren +Author-email: ronaldoussoren@mac.com +Maintainer: Ronald Oussoren +Maintainer-email: ronaldoussoren@mac.com +License: MIT +Keywords: graph +Platform: any +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Scientific/Engineering :: Mathematics +Classifier: Topic :: Scientific/Engineering :: Visualization +Description-Content-Type: text/x-rst; charset=UTF-8 +License-File: LICENSE +Project-URL: Documentation, https://altgraph.readthedocs.io/en/latest/ +Project-URL: Issue tracker, https://github.com/ronaldoussoren/altgraph/issues +Project-URL: Repository, https://github.com/ronaldoussoren/altgraph + +altgraph is a fork of graphlib: a graph (network) package for constructing +graphs, BFS and DFS traversals, topological sort, shortest paths, etc. with +graphviz output. + +altgraph includes some additional usage of Python 2.6+ features and +enhancements related to modulegraph and macholib. + +Project links +------------- + +* `Documentation `_ + +* `Issue Tracker `_ + +* `Repository `_ + + +Release history +=============== + +0.17.3 +------ + +* Update classifiers for Python 3.11 + +0.17.2 +------ + +* Change in setup.py to fix the sidebar links on PyPI + +0.17.1 +------ + +* Explicitly mark Python 3.10 as supported in wheel metadata. + +0.17 +---- + +* Explicitly mark Python 3.8 as supported in wheel metadata. + +* Migrate from Bitbucket to GitHub + +* Run black on the entire repository + +0.16.1 +------ + +* Explicitly mark Python 3.7 as supported in wheel metadata. + +0.16 +---- + +* Add LICENSE file + +0.15 +---- + +* ``ObjectGraph.get_edges``, ``ObjectGraph.getEdgeData`` and ``ObjectGraph.updateEdgeData`` + accept *None* as the node to get and treat this as an alias for *self* (as other + methods already did). + +0.14 +---- + +- Issue #7: Remove use of ``iteritems`` in altgraph.GraphAlgo code + +0.13 +---- + +- Issue #4: Graph._bfs_subgraph and back_bfs_subgraph return subgraphs with reversed edges + + Fix by "pombredanne" on bitbucket. + + +0.12 +---- + +- Added ``ObjectGraph.edgeData`` to retrieve the edge data + from a specific edge. + +- Added ``AltGraph.update_edge_data`` and ``ObjectGraph.updateEdgeData`` + to update the data associated with a graph edge. + +0.11 +---- + +- Stabilize the order of elements in dot file exports, + patch from bitbucket user 'pombredanne'. + +- Tweak setup.py file to remove dependency on distribute (but + keep the dependency on setuptools) + + +0.10.2 +------ + +- There where no classifiers in the package metadata due to a bug + in setup.py + +0.10.1 +------ + +This is a bugfix release + +Bug fixes: + +- Issue #3: The source archive contains a README.txt + while the setup file refers to ReadMe.txt. + + This is caused by a misfeature in distutils, as a + workaround I've renamed ReadMe.txt to README.txt + in the source tree and setup file. + + +0.10 +----- + +This is a minor feature release + +Features: + +- Do not use "2to3" to support Python 3. + + As a side effect of this altgraph now supports + Python 2.6 and later, and no longer supports + earlier releases of Python. + +- The order of attributes in the Dot output + is now always alphabetical. + + With this change the output will be consistent + between runs and Python versions. + +0.9 +--- + +This is a minor bugfix release + +Features: + +- Added ``altgraph.ObjectGraph.ObjectGraph.nodes``, a method + yielding all nodes in an object graph. + +Bugfixes: + +- The 0.8 release didn't work with py2app when using + python 3.x. + + +0.8 +----- + +This is a minor feature release. The major new feature +is a extensive set of unittests, which explains almost +all other changes in this release. + +Bugfixes: + +- Installing failed with Python 2.5 due to using a distutils + class that isn't available in that version of Python + (issue #1 on the issue tracker) + +- ``altgraph.GraphStat.degree_dist`` now actually works + +- ``altgraph.Graph.add_edge(a, b, create_nodes=False)`` will + no longer create the edge when one of the nodes doesn't + exist. + +- ``altgraph.Graph.forw_topo_sort`` failed for some sparse graphs. + +- ``altgraph.Graph.back_topo_sort`` was completely broken in + previous releases. + +- ``altgraph.Graph.forw_bfs_subgraph`` now actually works. + +- ``altgraph.Graph.back_bfs_subgraph`` now actually works. + +- ``altgraph.Graph.iterdfs`` now returns the correct result + when the ``forward`` argument is ``False``. + +- ``altgraph.Graph.iterdata`` now returns the correct result + when the ``forward`` argument is ``False``. + + +Features: + +- The ``altgraph.Graph`` constructor now accepts an argument + that contains 2- and 3-tuples instead of requireing that + all items have the same size. The (optional) argument can now + also be any iterator. + +- ``altgraph.Graph.Graph.add_node`` has no effect when you + add a hidden node. + +- The private method ``altgraph.Graph._bfs`` is no longer + present. + +- The private method ``altgraph.Graph._dfs`` is no longer + present. + +- ``altgraph.ObjectGraph`` now has a ``__contains__`` methods, + which means you can use the ``in`` operator to check if a + node is part of a graph. + +- ``altgraph.GraphUtil.generate_random_graph`` will raise + ``GraphError`` instead of looping forever when it is + impossible to create the requested graph. + +- ``altgraph.Dot.edge_style`` raises ``GraphError`` when + one of the nodes is not present in the graph. The method + silently added the tail in the past, but without ensuring + a consistent graph state. + +- ``altgraph.Dot.save_img`` now works when the mode is + ``"neato"``. + +0.7.2 +----- + +This is a minor bugfix release + +Bugfixes: + +- distutils didn't include the documentation subtree + +0.7.1 +----- + +This is a minor feature release + +Features: + +- Documentation is now generated using `sphinx `_ + and can be viewed at . + +- The repository has moved to bitbucket + +- ``altgraph.GraphStat.avg_hops`` is no longer present, the function had no + implementation and no specified behaviour. + +- the module ``altgraph.compat`` is gone, which means altgraph will no + longer work with Python 2.3. + + +0.7.0 +----- + +This is a minor feature release. + +Features: + +- Support for Python 3 + +- It is now possible to run tests using 'python setup.py test' + + (The actual testsuite is still very minimal though) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/RECORD b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/RECORD new file mode 100644 index 000000000..46b8f0c27 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/RECORD @@ -0,0 +1,21 @@ +altgraph-0.17.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +altgraph-0.17.4.dist-info/LICENSE,sha256=bBlNbbDGTUVTXRDJUUK5sM2nt9zH8d3uMCs9U289vkY,1002 +altgraph-0.17.4.dist-info/METADATA,sha256=aREWy2Dksd1VVAd4BJMv0CkDVxIPyZIfA9J2ZFJrEpU,7264 +altgraph-0.17.4.dist-info/RECORD,, +altgraph-0.17.4.dist-info/WHEEL,sha256=a-zpFRIJzOq5QfuhBzbhiA1eHTzNCJn8OdRvhdNX0Rk,110 +altgraph-0.17.4.dist-info/top_level.txt,sha256=HEBeRWf5ItVPc7Y9hW7hGlrLXZjPoL4by6CAhBV_BwA,9 +altgraph-0.17.4.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1 +altgraph/Dot.py,sha256=gKEp6Su_CoOWQYt5HIVs_7MBYK1BEOhKX0RLAAA-vQs,9929 +altgraph/Graph.py,sha256=6b6fSHLA5QSqMDnSHIO7_WJnBYIdq3K5Bt8VipRODwg,20788 +altgraph/GraphAlgo.py,sha256=Uu9aTjSKWi38iQ_e9ZrwCnzQaI1WWFDhJ6kfmu0jxAA,5645 +altgraph/GraphStat.py,sha256=LKya4BKXJ5GZi5-sNYU17aOBTLxqn_tVgbiw4sWGYIU,1888 +altgraph/GraphUtil.py,sha256=1T4DJc2bJn6EIU_Ct4m0oiKlXWkXvqcXE8CGL2K9en8,3990 +altgraph/ObjectGraph.py,sha256=o7fPJtyBEgJSXAkUjzvj35B-FOY4uKzfLGqSvTitx8c,6490 +altgraph/__init__.py,sha256=YtY-rHf6X_lYk8820da2uVZT-C-B9KGpGXvBg1oZ0Fc,5015 +altgraph/__pycache__/Dot.cpython-311.pyc,, +altgraph/__pycache__/Graph.cpython-311.pyc,, +altgraph/__pycache__/GraphAlgo.cpython-311.pyc,, +altgraph/__pycache__/GraphStat.cpython-311.pyc,, +altgraph/__pycache__/GraphUtil.cpython-311.pyc,, +altgraph/__pycache__/ObjectGraph.cpython-311.pyc,, +altgraph/__pycache__/__init__.cpython-311.pyc,, diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/WHEEL b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/WHEEL new file mode 100644 index 000000000..f771c29b8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.40.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/top_level.txt b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/top_level.txt new file mode 100644 index 000000000..5ad6b8ad1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/top_level.txt @@ -0,0 +1 @@ +altgraph diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/zip-safe b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/zip-safe new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph-0.17.4.dist-info/zip-safe @@ -0,0 +1 @@ + diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/Dot.py b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/Dot.py new file mode 100644 index 000000000..1d19cb1ec --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/Dot.py @@ -0,0 +1,321 @@ +""" +altgraph.Dot - Interface to the dot language +============================================ + +The :py:mod:`~altgraph.Dot` module provides a simple interface to the +file format used in the +`graphviz `_ +program. The module is intended to offload the most tedious part of the process +(the **dot** file generation) while transparently exposing most of its +features. + +To display the graphs or to generate image files the +`graphviz `_ +package needs to be installed on the system, moreover the :command:`dot` and +:command:`dotty` programs must be accesible in the program path so that they +can be ran from processes spawned within the module. + +Example usage +------------- + +Here is a typical usage:: + + from altgraph import Graph, Dot + + # create a graph + edges = [ (1,2), (1,3), (3,4), (3,5), (4,5), (5,4) ] + graph = Graph.Graph(edges) + + # create a dot representation of the graph + dot = Dot.Dot(graph) + + # display the graph + dot.display() + + # save the dot representation into the mydot.dot file + dot.save_dot(file_name='mydot.dot') + + # save dot file as gif image into the graph.gif file + dot.save_img(file_name='graph', file_type='gif') + +Directed graph and non-directed graph +------------------------------------- + +Dot class can use for both directed graph and non-directed graph +by passing ``graphtype`` parameter. + +Example:: + + # create directed graph(default) + dot = Dot.Dot(graph, graphtype="digraph") + + # create non-directed graph + dot = Dot.Dot(graph, graphtype="graph") + +Customizing the output +---------------------- + +The graph drawing process may be customized by passing +valid :command:`dot` parameters for the nodes and edges. For a list of all +parameters see the `graphviz `_ +documentation. + +Example:: + + # customizing the way the overall graph is drawn + dot.style(size='10,10', rankdir='RL', page='5, 5' , ranksep=0.75) + + # customizing node drawing + dot.node_style(1, label='BASE_NODE',shape='box', color='blue' ) + dot.node_style(2, style='filled', fillcolor='red') + + # customizing edge drawing + dot.edge_style(1, 2, style='dotted') + dot.edge_style(3, 5, arrowhead='dot', label='binds', labelangle='90') + dot.edge_style(4, 5, arrowsize=2, style='bold') + + +.. note:: + + dotty (invoked via :py:func:`~altgraph.Dot.display`) may not be able to + display all graphics styles. To verify the output save it to an image file + and look at it that way. + +Valid attributes +---------------- + + - dot styles, passed via the :py:meth:`Dot.style` method:: + + rankdir = 'LR' (draws the graph horizontally, left to right) + ranksep = number (rank separation in inches) + + - node attributes, passed via the :py:meth:`Dot.node_style` method:: + + style = 'filled' | 'invisible' | 'diagonals' | 'rounded' + shape = 'box' | 'ellipse' | 'circle' | 'point' | 'triangle' + + - edge attributes, passed via the :py:meth:`Dot.edge_style` method:: + + style = 'dashed' | 'dotted' | 'solid' | 'invis' | 'bold' + arrowhead = 'box' | 'crow' | 'diamond' | 'dot' | 'inv' | 'none' + | 'tee' | 'vee' + weight = number (the larger the number the closer the nodes will be) + + - valid `graphviz colors + `_ + + - for more details on how to control the graph drawing process see the + `graphviz reference + `_. +""" +import os +import warnings + +from altgraph import GraphError + + +class Dot(object): + """ + A class providing a **graphviz** (dot language) representation + allowing a fine grained control over how the graph is being + displayed. + + If the :command:`dot` and :command:`dotty` programs are not in the current + system path their location needs to be specified in the contructor. + """ + + def __init__( + self, + graph=None, + nodes=None, + edgefn=None, + nodevisitor=None, + edgevisitor=None, + name="G", + dot="dot", + dotty="dotty", + neato="neato", + graphtype="digraph", + ): + """ + Initialization. + """ + self.name, self.attr = name, {} + + assert graphtype in ["graph", "digraph"] + self.type = graphtype + + self.temp_dot = "tmp_dot.dot" + self.temp_neo = "tmp_neo.dot" + + self.dot, self.dotty, self.neato = dot, dotty, neato + + # self.nodes: node styles + # self.edges: edge styles + self.nodes, self.edges = {}, {} + + if graph is not None and nodes is None: + nodes = graph + if graph is not None and edgefn is None: + + def edgefn(node, graph=graph): + return graph.out_nbrs(node) + + if nodes is None: + nodes = () + + seen = set() + for node in nodes: + if nodevisitor is None: + style = {} + else: + style = nodevisitor(node) + if style is not None: + self.nodes[node] = {} + self.node_style(node, **style) + seen.add(node) + if edgefn is not None: + for head in seen: + for tail in (n for n in edgefn(head) if n in seen): + if edgevisitor is None: + edgestyle = {} + else: + edgestyle = edgevisitor(head, tail) + if edgestyle is not None: + if head not in self.edges: + self.edges[head] = {} + self.edges[head][tail] = {} + self.edge_style(head, tail, **edgestyle) + + def style(self, **attr): + """ + Changes the overall style + """ + self.attr = attr + + def display(self, mode="dot"): + """ + Displays the current graph via dotty + """ + + if mode == "neato": + self.save_dot(self.temp_neo) + neato_cmd = "%s -o %s %s" % (self.neato, self.temp_dot, self.temp_neo) + os.system(neato_cmd) + else: + self.save_dot(self.temp_dot) + + plot_cmd = "%s %s" % (self.dotty, self.temp_dot) + os.system(plot_cmd) + + def node_style(self, node, **kwargs): + """ + Modifies a node style to the dot representation. + """ + if node not in self.edges: + self.edges[node] = {} + self.nodes[node] = kwargs + + def all_node_style(self, **kwargs): + """ + Modifies all node styles + """ + for node in self.nodes: + self.node_style(node, **kwargs) + + def edge_style(self, head, tail, **kwargs): + """ + Modifies an edge style to the dot representation. + """ + if tail not in self.nodes: + raise GraphError("invalid node %s" % (tail,)) + + try: + if tail not in self.edges[head]: + self.edges[head][tail] = {} + self.edges[head][tail] = kwargs + except KeyError: + raise GraphError("invalid edge %s -> %s " % (head, tail)) + + def iterdot(self): + # write graph title + if self.type == "digraph": + yield "digraph %s {\n" % (self.name,) + elif self.type == "graph": + yield "graph %s {\n" % (self.name,) + + else: + raise GraphError("unsupported graphtype %s" % (self.type,)) + + # write overall graph attributes + for attr_name, attr_value in sorted(self.attr.items()): + yield '%s="%s";' % (attr_name, attr_value) + yield "\n" + + # some reusable patterns + cpatt = '%s="%s",' # to separate attributes + epatt = "];\n" # to end attributes + + # write node attributes + for node_name, node_attr in sorted(self.nodes.items()): + yield '\t"%s" [' % (node_name,) + for attr_name, attr_value in sorted(node_attr.items()): + yield cpatt % (attr_name, attr_value) + yield epatt + + # write edge attributes + for head in sorted(self.edges): + for tail in sorted(self.edges[head]): + if self.type == "digraph": + yield '\t"%s" -> "%s" [' % (head, tail) + else: + yield '\t"%s" -- "%s" [' % (head, tail) + for attr_name, attr_value in sorted(self.edges[head][tail].items()): + yield cpatt % (attr_name, attr_value) + yield epatt + + # finish file + yield "}\n" + + def __iter__(self): + return self.iterdot() + + def save_dot(self, file_name=None): + """ + Saves the current graph representation into a file + """ + + if not file_name: + warnings.warn(DeprecationWarning, "always pass a file_name", stacklevel=2) + file_name = self.temp_dot + + with open(file_name, "w") as fp: + for chunk in self.iterdot(): + fp.write(chunk) + + def save_img(self, file_name=None, file_type="gif", mode="dot"): + """ + Saves the dot file as an image file + """ + + if not file_name: + warnings.warn(DeprecationWarning, "always pass a file_name", stacklevel=2) + file_name = "out" + + if mode == "neato": + self.save_dot(self.temp_neo) + neato_cmd = "%s -o %s %s" % (self.neato, self.temp_dot, self.temp_neo) + os.system(neato_cmd) + plot_cmd = self.dot + else: + self.save_dot(self.temp_dot) + plot_cmd = self.dot + + file_name = "%s.%s" % (file_name, file_type) + create_cmd = "%s -T%s %s -o %s" % ( + plot_cmd, + file_type, + self.temp_dot, + file_name, + ) + os.system(create_cmd) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/Graph.py b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/Graph.py new file mode 100644 index 000000000..8088007ab --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/Graph.py @@ -0,0 +1,682 @@ +""" +altgraph.Graph - Base Graph class +================================= + +.. + #--Version 2.1 + #--Bob Ippolito October, 2004 + + #--Version 2.0 + #--Istvan Albert June, 2004 + + #--Version 1.0 + #--Nathan Denny, May 27, 1999 +""" + +from collections import deque + +from altgraph import GraphError + + +class Graph(object): + """ + The Graph class represents a directed graph with *N* nodes and *E* edges. + + Naming conventions: + + - the prefixes such as *out*, *inc* and *all* will refer to methods + that operate on the outgoing, incoming or all edges of that node. + + For example: :py:meth:`inc_degree` will refer to the degree of the node + computed over the incoming edges (the number of neighbours linking to + the node). + + - the prefixes such as *forw* and *back* will refer to the + orientation of the edges used in the method with respect to the node. + + For example: :py:meth:`forw_bfs` will start at the node then use the + outgoing edges to traverse the graph (goes forward). + """ + + def __init__(self, edges=None): + """ + Initialization + """ + + self.next_edge = 0 + self.nodes, self.edges = {}, {} + self.hidden_edges, self.hidden_nodes = {}, {} + + if edges is not None: + for item in edges: + if len(item) == 2: + head, tail = item + self.add_edge(head, tail) + elif len(item) == 3: + head, tail, data = item + self.add_edge(head, tail, data) + else: + raise GraphError("Cannot create edge from %s" % (item,)) + + def __repr__(self): + return "" % ( + self.number_of_nodes(), + self.number_of_edges(), + ) + + def add_node(self, node, node_data=None): + """ + Adds a new node to the graph. Arbitrary data can be attached to the + node via the node_data parameter. Adding the same node twice will be + silently ignored. + + The node must be a hashable value. + """ + # + # the nodes will contain tuples that will store incoming edges, + # outgoing edges and data + # + # index 0 -> incoming edges + # index 1 -> outgoing edges + + if node in self.hidden_nodes: + # Node is present, but hidden + return + + if node not in self.nodes: + self.nodes[node] = ([], [], node_data) + + def add_edge(self, head_id, tail_id, edge_data=1, create_nodes=True): + """ + Adds a directed edge going from head_id to tail_id. + Arbitrary data can be attached to the edge via edge_data. + It may create the nodes if adding edges between nonexisting ones. + + :param head_id: head node + :param tail_id: tail node + :param edge_data: (optional) data attached to the edge + :param create_nodes: (optional) creates the head_id or tail_id + node in case they did not exist + """ + # shorcut + edge = self.next_edge + + # add nodes if on automatic node creation + if create_nodes: + self.add_node(head_id) + self.add_node(tail_id) + + # update the corresponding incoming and outgoing lists in the nodes + # index 0 -> incoming edges + # index 1 -> outgoing edges + + try: + self.nodes[tail_id][0].append(edge) + self.nodes[head_id][1].append(edge) + except KeyError: + raise GraphError("Invalid nodes %s -> %s" % (head_id, tail_id)) + + # store edge information + self.edges[edge] = (head_id, tail_id, edge_data) + + self.next_edge += 1 + + def hide_edge(self, edge): + """ + Hides an edge from the graph. The edge may be unhidden at some later + time. + """ + try: + head_id, tail_id, edge_data = self.hidden_edges[edge] = self.edges[edge] + self.nodes[tail_id][0].remove(edge) + self.nodes[head_id][1].remove(edge) + del self.edges[edge] + except KeyError: + raise GraphError("Invalid edge %s" % edge) + + def hide_node(self, node): + """ + Hides a node from the graph. The incoming and outgoing edges of the + node will also be hidden. The node may be unhidden at some later time. + """ + try: + all_edges = self.all_edges(node) + self.hidden_nodes[node] = (self.nodes[node], all_edges) + for edge in all_edges: + self.hide_edge(edge) + del self.nodes[node] + except KeyError: + raise GraphError("Invalid node %s" % node) + + def restore_node(self, node): + """ + Restores a previously hidden node back into the graph and restores + all of its incoming and outgoing edges. + """ + try: + self.nodes[node], all_edges = self.hidden_nodes[node] + for edge in all_edges: + self.restore_edge(edge) + del self.hidden_nodes[node] + except KeyError: + raise GraphError("Invalid node %s" % node) + + def restore_edge(self, edge): + """ + Restores a previously hidden edge back into the graph. + """ + try: + head_id, tail_id, data = self.hidden_edges[edge] + self.nodes[tail_id][0].append(edge) + self.nodes[head_id][1].append(edge) + self.edges[edge] = head_id, tail_id, data + del self.hidden_edges[edge] + except KeyError: + raise GraphError("Invalid edge %s" % edge) + + def restore_all_edges(self): + """ + Restores all hidden edges. + """ + for edge in list(self.hidden_edges.keys()): + try: + self.restore_edge(edge) + except GraphError: + pass + + def restore_all_nodes(self): + """ + Restores all hidden nodes. + """ + for node in list(self.hidden_nodes.keys()): + self.restore_node(node) + + def __contains__(self, node): + """ + Test whether a node is in the graph + """ + return node in self.nodes + + def edge_by_id(self, edge): + """ + Returns the edge that connects the head_id and tail_id nodes + """ + try: + head, tail, data = self.edges[edge] + except KeyError: + head, tail = None, None + raise GraphError("Invalid edge %s" % edge) + + return (head, tail) + + def edge_by_node(self, head, tail): + """ + Returns the edge that connects the head_id and tail_id nodes + """ + for edge in self.out_edges(head): + if self.tail(edge) == tail: + return edge + return None + + def number_of_nodes(self): + """ + Returns the number of nodes + """ + return len(self.nodes) + + def number_of_edges(self): + """ + Returns the number of edges + """ + return len(self.edges) + + def __iter__(self): + """ + Iterates over all nodes in the graph + """ + return iter(self.nodes) + + def node_list(self): + """ + Return a list of the node ids for all visible nodes in the graph. + """ + return list(self.nodes.keys()) + + def edge_list(self): + """ + Returns an iterator for all visible nodes in the graph. + """ + return list(self.edges.keys()) + + def number_of_hidden_edges(self): + """ + Returns the number of hidden edges + """ + return len(self.hidden_edges) + + def number_of_hidden_nodes(self): + """ + Returns the number of hidden nodes + """ + return len(self.hidden_nodes) + + def hidden_node_list(self): + """ + Returns the list with the hidden nodes + """ + return list(self.hidden_nodes.keys()) + + def hidden_edge_list(self): + """ + Returns a list with the hidden edges + """ + return list(self.hidden_edges.keys()) + + def describe_node(self, node): + """ + return node, node data, outgoing edges, incoming edges for node + """ + incoming, outgoing, data = self.nodes[node] + return node, data, outgoing, incoming + + def describe_edge(self, edge): + """ + return edge, edge data, head, tail for edge + """ + head, tail, data = self.edges[edge] + return edge, data, head, tail + + def node_data(self, node): + """ + Returns the data associated with a node + """ + return self.nodes[node][2] + + def edge_data(self, edge): + """ + Returns the data associated with an edge + """ + return self.edges[edge][2] + + def update_edge_data(self, edge, edge_data): + """ + Replace the edge data for a specific edge + """ + self.edges[edge] = self.edges[edge][0:2] + (edge_data,) + + def head(self, edge): + """ + Returns the node of the head of the edge. + """ + return self.edges[edge][0] + + def tail(self, edge): + """ + Returns node of the tail of the edge. + """ + return self.edges[edge][1] + + def out_nbrs(self, node): + """ + List of nodes connected by outgoing edges + """ + return [self.tail(n) for n in self.out_edges(node)] + + def inc_nbrs(self, node): + """ + List of nodes connected by incoming edges + """ + return [self.head(n) for n in self.inc_edges(node)] + + def all_nbrs(self, node): + """ + List of nodes connected by incoming and outgoing edges + """ + return list(dict.fromkeys(self.inc_nbrs(node) + self.out_nbrs(node))) + + def out_edges(self, node): + """ + Returns a list of the outgoing edges + """ + try: + return list(self.nodes[node][1]) + except KeyError: + raise GraphError("Invalid node %s" % node) + + def inc_edges(self, node): + """ + Returns a list of the incoming edges + """ + try: + return list(self.nodes[node][0]) + except KeyError: + raise GraphError("Invalid node %s" % node) + + def all_edges(self, node): + """ + Returns a list of incoming and outging edges. + """ + return set(self.inc_edges(node) + self.out_edges(node)) + + def out_degree(self, node): + """ + Returns the number of outgoing edges + """ + return len(self.out_edges(node)) + + def inc_degree(self, node): + """ + Returns the number of incoming edges + """ + return len(self.inc_edges(node)) + + def all_degree(self, node): + """ + The total degree of a node + """ + return self.inc_degree(node) + self.out_degree(node) + + def _topo_sort(self, forward=True): + """ + Topological sort. + + Returns a list of nodes where the successors (based on outgoing and + incoming edges selected by the forward parameter) of any given node + appear in the sequence after that node. + """ + topo_list = [] + queue = deque() + indeg = {} + + # select the operation that will be performed + if forward: + get_edges = self.out_edges + get_degree = self.inc_degree + get_next = self.tail + else: + get_edges = self.inc_edges + get_degree = self.out_degree + get_next = self.head + + for node in self.node_list(): + degree = get_degree(node) + if degree: + indeg[node] = degree + else: + queue.append(node) + + while queue: + curr_node = queue.popleft() + topo_list.append(curr_node) + for edge in get_edges(curr_node): + tail_id = get_next(edge) + if tail_id in indeg: + indeg[tail_id] -= 1 + if indeg[tail_id] == 0: + queue.append(tail_id) + + if len(topo_list) == len(self.node_list()): + valid = True + else: + # the graph has cycles, invalid topological sort + valid = False + + return (valid, topo_list) + + def forw_topo_sort(self): + """ + Topological sort. + + Returns a list of nodes where the successors (based on outgoing edges) + of any given node appear in the sequence after that node. + """ + return self._topo_sort(forward=True) + + def back_topo_sort(self): + """ + Reverse topological sort. + + Returns a list of nodes where the successors (based on incoming edges) + of any given node appear in the sequence after that node. + """ + return self._topo_sort(forward=False) + + def _bfs_subgraph(self, start_id, forward=True): + """ + Private method creates a subgraph in a bfs order. + + The forward parameter specifies whether it is a forward or backward + traversal. + """ + if forward: + get_bfs = self.forw_bfs + get_nbrs = self.out_nbrs + else: + get_bfs = self.back_bfs + get_nbrs = self.inc_nbrs + + g = Graph() + bfs_list = get_bfs(start_id) + for node in bfs_list: + g.add_node(node) + + for node in bfs_list: + for nbr_id in get_nbrs(node): + if forward: + g.add_edge(node, nbr_id) + else: + g.add_edge(nbr_id, node) + + return g + + def forw_bfs_subgraph(self, start_id): + """ + Creates and returns a subgraph consisting of the breadth first + reachable nodes based on their outgoing edges. + """ + return self._bfs_subgraph(start_id, forward=True) + + def back_bfs_subgraph(self, start_id): + """ + Creates and returns a subgraph consisting of the breadth first + reachable nodes based on the incoming edges. + """ + return self._bfs_subgraph(start_id, forward=False) + + def iterdfs(self, start, end=None, forward=True): + """ + Collecting nodes in some depth first traversal. + + The forward parameter specifies whether it is a forward or backward + traversal. + """ + visited, stack = {start}, deque([start]) + + if forward: + get_edges = self.out_edges + get_next = self.tail + else: + get_edges = self.inc_edges + get_next = self.head + + while stack: + curr_node = stack.pop() + yield curr_node + if curr_node == end: + break + for edge in sorted(get_edges(curr_node)): + tail = get_next(edge) + if tail not in visited: + visited.add(tail) + stack.append(tail) + + def iterdata(self, start, end=None, forward=True, condition=None): + """ + Perform a depth-first walk of the graph (as ``iterdfs``) + and yield the item data of every node where condition matches. The + condition callback is only called when node_data is not None. + """ + + visited, stack = {start}, deque([start]) + + if forward: + get_edges = self.out_edges + get_next = self.tail + else: + get_edges = self.inc_edges + get_next = self.head + + get_data = self.node_data + + while stack: + curr_node = stack.pop() + curr_data = get_data(curr_node) + if curr_data is not None: + if condition is not None and not condition(curr_data): + continue + yield curr_data + if curr_node == end: + break + for edge in get_edges(curr_node): + tail = get_next(edge) + if tail not in visited: + visited.add(tail) + stack.append(tail) + + def _iterbfs(self, start, end=None, forward=True): + """ + The forward parameter specifies whether it is a forward or backward + traversal. Returns a list of tuples where the first value is the hop + value the second value is the node id. + """ + queue, visited = deque([(start, 0)]), {start} + + # the direction of the bfs depends on the edges that are sampled + if forward: + get_edges = self.out_edges + get_next = self.tail + else: + get_edges = self.inc_edges + get_next = self.head + + while queue: + curr_node, curr_step = queue.popleft() + yield (curr_node, curr_step) + if curr_node == end: + break + for edge in get_edges(curr_node): + tail = get_next(edge) + if tail not in visited: + visited.add(tail) + queue.append((tail, curr_step + 1)) + + def forw_bfs(self, start, end=None): + """ + Returns a list of nodes in some forward BFS order. + + Starting from the start node the breadth first search proceeds along + outgoing edges. + """ + return [node for node, step in self._iterbfs(start, end, forward=True)] + + def back_bfs(self, start, end=None): + """ + Returns a list of nodes in some backward BFS order. + + Starting from the start node the breadth first search proceeds along + incoming edges. + """ + return [node for node, _ in self._iterbfs(start, end, forward=False)] + + def forw_dfs(self, start, end=None): + """ + Returns a list of nodes in some forward DFS order. + + Starting with the start node the depth first search proceeds along + outgoing edges. + """ + return list(self.iterdfs(start, end, forward=True)) + + def back_dfs(self, start, end=None): + """ + Returns a list of nodes in some backward DFS order. + + Starting from the start node the depth first search proceeds along + incoming edges. + """ + return list(self.iterdfs(start, end, forward=False)) + + def connected(self): + """ + Returns :py:data:`True` if the graph's every node can be reached from + every other node. + """ + node_list = self.node_list() + for node in node_list: + bfs_list = self.forw_bfs(node) + if len(bfs_list) != len(node_list): + return False + return True + + def clust_coef(self, node): + """ + Computes and returns the local clustering coefficient of node. + + The local cluster coefficient is proportion of the actual number of + edges between neighbours of node and the maximum number of edges + between those neighbours. + + See "Local Clustering Coefficient" on + + for a formal definition. + """ + num = 0 + nbr_set = set(self.out_nbrs(node)) + + if node in nbr_set: + nbr_set.remove(node) # loop defense + + for nbr in nbr_set: + sec_set = set(self.out_nbrs(nbr)) + if nbr in sec_set: + sec_set.remove(nbr) # loop defense + num += len(nbr_set & sec_set) + + nbr_num = len(nbr_set) + if nbr_num: + clust_coef = float(num) / (nbr_num * (nbr_num - 1)) + else: + clust_coef = 0.0 + return clust_coef + + def get_hops(self, start, end=None, forward=True): + """ + Computes the hop distance to all nodes centered around a node. + + First order neighbours are at hop 1, their neigbours are at hop 2 etc. + Uses :py:meth:`forw_bfs` or :py:meth:`back_bfs` depending on the value + of the forward parameter. If the distance between all neighbouring + nodes is 1 the hop number corresponds to the shortest distance between + the nodes. + + :param start: the starting node + :param end: ending node (optional). When not specified will search the + whole graph. + :param forward: directionality parameter (optional). + If C{True} (default) it uses L{forw_bfs} otherwise L{back_bfs}. + :return: returns a list of tuples where each tuple contains the + node and the hop. + + Typical usage:: + + >>> print (graph.get_hops(1, 8)) + >>> [(1, 0), (2, 1), (3, 1), (4, 2), (5, 3), (7, 4), (8, 5)] + # node 1 is at 0 hops + # node 2 is at 1 hop + # ... + # node 8 is at 5 hops + """ + if forward: + return list(self._iterbfs(start=start, end=end, forward=True)) + else: + return list(self._iterbfs(start=start, end=end, forward=False)) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/GraphAlgo.py b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/GraphAlgo.py new file mode 100644 index 000000000..f93e73dcd --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/GraphAlgo.py @@ -0,0 +1,171 @@ +""" +altgraph.GraphAlgo - Graph algorithms +===================================== +""" +from altgraph import GraphError + + +def dijkstra(graph, start, end=None): + """ + Dijkstra's algorithm for shortest paths + + `David Eppstein, UC Irvine, 4 April 2002 + `_ + + `Python Cookbook Recipe + `_ + + Find shortest paths from the start node to all nodes nearer than or + equal to the end node. + + Dijkstra's algorithm is only guaranteed to work correctly when all edge + lengths are positive. This code does not verify this property for all + edges (only the edges examined until the end vertex is reached), but will + correctly compute shortest paths even for some graphs with negative edges, + and will raise an exception if it discovers that a negative edge has + caused it to make a mistake. + + Adapted to altgraph by Istvan Albert, Pennsylvania State University - + June, 9 2004 + """ + D = {} # dictionary of final distances + P = {} # dictionary of predecessors + Q = _priorityDictionary() # estimated distances of non-final vertices + Q[start] = 0 + + for v in Q: + D[v] = Q[v] + if v == end: + break + + for w in graph.out_nbrs(v): + edge_id = graph.edge_by_node(v, w) + vwLength = D[v] + graph.edge_data(edge_id) + if w in D: + if vwLength < D[w]: + raise GraphError( + "Dijkstra: found better path to already-final vertex" + ) + elif w not in Q or vwLength < Q[w]: + Q[w] = vwLength + P[w] = v + + return (D, P) + + +def shortest_path(graph, start, end): + """ + Find a single shortest path from the *start* node to the *end* node. + The input has the same conventions as dijkstra(). The output is a list of + the nodes in order along the shortest path. + + **Note that the distances must be stored in the edge data as numeric data** + """ + + D, P = dijkstra(graph, start, end) + Path = [] + while 1: + Path.append(end) + if end == start: + break + end = P[end] + Path.reverse() + return Path + + +# +# Utility classes and functions +# +class _priorityDictionary(dict): + """ + Priority dictionary using binary heaps (internal use only) + + David Eppstein, UC Irvine, 8 Mar 2002 + + Implements a data structure that acts almost like a dictionary, with + two modifications: + + 1. D.smallest() returns the value x minimizing D[x]. For this to + work correctly, all values D[x] stored in the dictionary must be + comparable. + + 2. iterating "for x in D" finds and removes the items from D in sorted + order. Each item is not removed until the next item is requested, + so D[x] will still return a useful value until the next iteration + of the for-loop. Each operation takes logarithmic amortized time. + """ + + def __init__(self): + """ + Initialize priorityDictionary by creating binary heap of pairs + (value,key). Note that changing or removing a dict entry will not + remove the old pair from the heap until it is found by smallest() + or until the heap is rebuilt. + """ + self.__heap = [] + dict.__init__(self) + + def smallest(self): + """ + Find smallest item after removing deleted items from front of heap. + """ + if len(self) == 0: + raise IndexError("smallest of empty priorityDictionary") + heap = self.__heap + while heap[0][1] not in self or self[heap[0][1]] != heap[0][0]: + lastItem = heap.pop() + insertionPoint = 0 + while 1: + smallChild = 2 * insertionPoint + 1 + if ( + smallChild + 1 < len(heap) + and heap[smallChild] > heap[smallChild + 1] + ): + smallChild += 1 + if smallChild >= len(heap) or lastItem <= heap[smallChild]: + heap[insertionPoint] = lastItem + break + heap[insertionPoint] = heap[smallChild] + insertionPoint = smallChild + return heap[0][1] + + def __iter__(self): + """ + Create destructive sorted iterator of priorityDictionary. + """ + + def iterfn(): + while len(self) > 0: + x = self.smallest() + yield x + del self[x] + + return iterfn() + + def __setitem__(self, key, val): + """ + Change value stored in dictionary and add corresponding pair to heap. + Rebuilds the heap if the number of deleted items gets large, to avoid + memory leakage. + """ + dict.__setitem__(self, key, val) + heap = self.__heap + if len(heap) > 2 * len(self): + self.__heap = [(v, k) for k, v in self.items()] + self.__heap.sort() + else: + newPair = (val, key) + insertionPoint = len(heap) + heap.append(None) + while insertionPoint > 0 and newPair < heap[(insertionPoint - 1) // 2]: + heap[insertionPoint] = heap[(insertionPoint - 1) // 2] + insertionPoint = (insertionPoint - 1) // 2 + heap[insertionPoint] = newPair + + def setdefault(self, key, val): + """ + Reimplement setdefault to pass through our customized __setitem__. + """ + if key not in self: + self[key] = val + return self[key] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/GraphStat.py b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/GraphStat.py new file mode 100644 index 000000000..cccc66d10 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/GraphStat.py @@ -0,0 +1,73 @@ +""" +altgraph.GraphStat - Functions providing various graph statistics +================================================================= +""" + + +def degree_dist(graph, limits=(0, 0), bin_num=10, mode="out"): + """ + Computes the degree distribution for a graph. + + Returns a list of tuples where the first element of the tuple is the + center of the bin representing a range of degrees and the second element + of the tuple are the number of nodes with the degree falling in the range. + + Example:: + + .... + """ + + deg = [] + if mode == "inc": + get_deg = graph.inc_degree + else: + get_deg = graph.out_degree + + for node in graph: + deg.append(get_deg(node)) + + if not deg: + return [] + + results = _binning(values=deg, limits=limits, bin_num=bin_num) + + return results + + +_EPS = 1.0 / (2.0**32) + + +def _binning(values, limits=(0, 0), bin_num=10): + """ + Bins data that falls between certain limits, if the limits are (0, 0) the + minimum and maximum values are used. + + Returns a list of tuples where the first element of the tuple is the + center of the bin and the second element of the tuple are the counts. + """ + if limits == (0, 0): + min_val, max_val = min(values) - _EPS, max(values) + _EPS + else: + min_val, max_val = limits + + # get bin size + bin_size = (max_val - min_val) / float(bin_num) + bins = [0] * (bin_num) + + # will ignore these outliers for now + for value in values: + try: + if (value - min_val) >= 0: + index = int((value - min_val) / float(bin_size)) + bins[index] += 1 + except IndexError: + pass + + # make it ready for an x,y plot + result = [] + center = (bin_size / 2) + min_val + for i, y in enumerate(bins): + x = center + bin_size * i + result.append((x, y)) + + return result diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/GraphUtil.py b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/GraphUtil.py new file mode 100644 index 000000000..cfd6a34f3 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/GraphUtil.py @@ -0,0 +1,139 @@ +""" +altgraph.GraphUtil - Utility classes and functions +================================================== +""" + +import random +from collections import deque + +from altgraph import Graph, GraphError + + +def generate_random_graph(node_num, edge_num, self_loops=False, multi_edges=False): + """ + Generates and returns a :py:class:`~altgraph.Graph.Graph` instance with + *node_num* nodes randomly connected by *edge_num* edges. + """ + g = Graph.Graph() + + if not multi_edges: + if self_loops: + max_edges = node_num * node_num + else: + max_edges = node_num * (node_num - 1) + + if edge_num > max_edges: + raise GraphError("inconsistent arguments to 'generate_random_graph'") + + nodes = range(node_num) + + for node in nodes: + g.add_node(node) + + while 1: + head = random.choice(nodes) + tail = random.choice(nodes) + + # loop defense + if head == tail and not self_loops: + continue + + # multiple edge defense + if g.edge_by_node(head, tail) is not None and not multi_edges: + continue + + # add the edge + g.add_edge(head, tail) + if g.number_of_edges() >= edge_num: + break + + return g + + +def generate_scale_free_graph(steps, growth_num, self_loops=False, multi_edges=False): + """ + Generates and returns a :py:class:`~altgraph.Graph.Graph` instance that + will have *steps* \\* *growth_num* nodes and a scale free (powerlaw) + connectivity. Starting with a fully connected graph with *growth_num* + nodes at every step *growth_num* nodes are added to the graph and are + connected to existing nodes with a probability proportional to the degree + of these existing nodes. + """ + # The code doesn't seem to do what the documentation claims. + graph = Graph.Graph() + + # initialize the graph + store = [] + for i in range(growth_num): + for j in range(i + 1, growth_num): + store.append(i) + store.append(j) + graph.add_edge(i, j) + + # generate + for node in range(growth_num, steps * growth_num): + graph.add_node(node) + while graph.out_degree(node) < growth_num: + nbr = random.choice(store) + + # loop defense + if node == nbr and not self_loops: + continue + + # multi edge defense + if graph.edge_by_node(node, nbr) and not multi_edges: + continue + + graph.add_edge(node, nbr) + + for nbr in graph.out_nbrs(node): + store.append(node) + store.append(nbr) + + return graph + + +def filter_stack(graph, head, filters): + """ + Perform a walk in a depth-first order starting + at *head*. + + Returns (visited, removes, orphans). + + * visited: the set of visited nodes + * removes: the list of nodes where the node + data does not all *filters* + * orphans: tuples of (last_good, node), + where node is not in removes, is directly + reachable from a node in *removes* and + *last_good* is the closest upstream node that is not + in *removes*. + """ + + visited, removes, orphans = {head}, set(), set() + stack = deque([(head, head)]) + get_data = graph.node_data + get_edges = graph.out_edges + get_tail = graph.tail + + while stack: + last_good, node = stack.pop() + data = get_data(node) + if data is not None: + for filtfunc in filters: + if not filtfunc(data): + removes.add(node) + break + else: + last_good = node + for edge in get_edges(node): + tail = get_tail(edge) + if last_good is not node: + orphans.add((last_good, tail)) + if tail not in visited: + visited.add(tail) + stack.append((last_good, tail)) + + orphans = [(lg, tl) for (lg, tl) in orphans if tl not in removes] + + return visited, removes, orphans diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/ObjectGraph.py b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/ObjectGraph.py new file mode 100644 index 000000000..379b05b12 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/ObjectGraph.py @@ -0,0 +1,212 @@ +""" +altgraph.ObjectGraph - Graph of objects with an identifier +========================================================== + +A graph of objects that have a "graphident" attribute. +graphident is the key for the object in the graph +""" + +from altgraph import GraphError +from altgraph.Graph import Graph +from altgraph.GraphUtil import filter_stack + + +class ObjectGraph(object): + """ + A graph of objects that have a "graphident" attribute. + graphident is the key for the object in the graph + """ + + def __init__(self, graph=None, debug=0): + if graph is None: + graph = Graph() + self.graphident = self + self.graph = graph + self.debug = debug + self.indent = 0 + graph.add_node(self, None) + + def __repr__(self): + return "<%s>" % (type(self).__name__,) + + def flatten(self, condition=None, start=None): + """ + Iterate over the subgraph that is entirely reachable by condition + starting from the given start node or the ObjectGraph root + """ + if start is None: + start = self + start = self.getRawIdent(start) + return self.graph.iterdata(start=start, condition=condition) + + def nodes(self): + for ident in self.graph: + node = self.graph.node_data(ident) + if node is not None: + yield self.graph.node_data(ident) + + def get_edges(self, node): + if node is None: + node = self + start = self.getRawIdent(node) + _, _, outraw, incraw = self.graph.describe_node(start) + + def iter_edges(lst, n): + seen = set() + for tpl in (self.graph.describe_edge(e) for e in lst): + ident = tpl[n] + if ident not in seen: + yield self.findNode(ident) + seen.add(ident) + + return iter_edges(outraw, 3), iter_edges(incraw, 2) + + def edgeData(self, fromNode, toNode): + if fromNode is None: + fromNode = self + start = self.getRawIdent(fromNode) + stop = self.getRawIdent(toNode) + edge = self.graph.edge_by_node(start, stop) + return self.graph.edge_data(edge) + + def updateEdgeData(self, fromNode, toNode, edgeData): + if fromNode is None: + fromNode = self + start = self.getRawIdent(fromNode) + stop = self.getRawIdent(toNode) + edge = self.graph.edge_by_node(start, stop) + self.graph.update_edge_data(edge, edgeData) + + def filterStack(self, filters): + """ + Filter the ObjectGraph in-place by removing all edges to nodes that + do not match every filter in the given filter list + + Returns a tuple containing the number of: + (nodes_visited, nodes_removed, nodes_orphaned) + """ + visited, removes, orphans = filter_stack(self.graph, self, filters) + + for last_good, tail in orphans: + self.graph.add_edge(last_good, tail, edge_data="orphan") + + for node in removes: + self.graph.hide_node(node) + + return len(visited) - 1, len(removes), len(orphans) + + def removeNode(self, node): + """ + Remove the given node from the graph if it exists + """ + ident = self.getIdent(node) + if ident is not None: + self.graph.hide_node(ident) + + def removeReference(self, fromnode, tonode): + """ + Remove all edges from fromnode to tonode + """ + if fromnode is None: + fromnode = self + fromident = self.getIdent(fromnode) + toident = self.getIdent(tonode) + if fromident is not None and toident is not None: + while True: + edge = self.graph.edge_by_node(fromident, toident) + if edge is None: + break + self.graph.hide_edge(edge) + + def getIdent(self, node): + """ + Get the graph identifier for a node + """ + ident = self.getRawIdent(node) + if ident is not None: + return ident + node = self.findNode(node) + if node is None: + return None + return node.graphident + + def getRawIdent(self, node): + """ + Get the identifier for a node object + """ + if node is self: + return node + ident = getattr(node, "graphident", None) + return ident + + def __contains__(self, node): + return self.findNode(node) is not None + + def findNode(self, node): + """ + Find the node on the graph + """ + ident = self.getRawIdent(node) + if ident is None: + ident = node + try: + return self.graph.node_data(ident) + except KeyError: + return None + + def addNode(self, node): + """ + Add a node to the graph referenced by the root + """ + self.msg(4, "addNode", node) + + try: + self.graph.restore_node(node.graphident) + except GraphError: + self.graph.add_node(node.graphident, node) + + def createReference(self, fromnode, tonode, edge_data=None): + """ + Create a reference from fromnode to tonode + """ + if fromnode is None: + fromnode = self + fromident, toident = self.getIdent(fromnode), self.getIdent(tonode) + if fromident is None or toident is None: + return + self.msg(4, "createReference", fromnode, tonode, edge_data) + self.graph.add_edge(fromident, toident, edge_data=edge_data) + + def createNode(self, cls, name, *args, **kw): + """ + Add a node of type cls to the graph if it does not already exist + by the given name + """ + m = self.findNode(name) + if m is None: + m = cls(name, *args, **kw) + self.addNode(m) + return m + + def msg(self, level, s, *args): + """ + Print a debug message with the given level + """ + if s and level <= self.debug: + print("%s%s %s" % (" " * self.indent, s, " ".join(map(repr, args)))) + + def msgin(self, level, s, *args): + """ + Print a debug message and indent + """ + if level <= self.debug: + self.msg(level, s, *args) + self.indent = self.indent + 1 + + def msgout(self, level, s, *args): + """ + Dedent and print a debug message + """ + if level <= self.debug: + self.indent = self.indent - 1 + self.msg(level, s, *args) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/__init__.py new file mode 100644 index 000000000..a56342438 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/altgraph/__init__.py @@ -0,0 +1,148 @@ +""" +altgraph - a python graph library +================================= + +altgraph is a fork of `graphlib `_ tailored +to use newer Python 2.3+ features, including additional support used by the +py2app suite (modulegraph and macholib, specifically). + +altgraph is a python based graph (network) representation and manipulation +package. It has started out as an extension to the +`graph_lib module +`_ +written by Nathan Denny it has been significantly optimized and expanded. + +The :class:`altgraph.Graph.Graph` class is loosely modeled after the +`LEDA `_ +(Library of Efficient Datatypes) representation. The library +includes methods for constructing graphs, BFS and DFS traversals, +topological sort, finding connected components, shortest paths as well as a +number graph statistics functions. The library can also visualize graphs +via `graphviz `_. + +The package contains the following modules: + + - the :py:mod:`altgraph.Graph` module contains the + :class:`~altgraph.Graph.Graph` class that stores the graph data + + - the :py:mod:`altgraph.GraphAlgo` module implements graph algorithms + operating on graphs (:py:class:`~altgraph.Graph.Graph`} instances) + + - the :py:mod:`altgraph.GraphStat` module contains functions for + computing statistical measures on graphs + + - the :py:mod:`altgraph.GraphUtil` module contains functions for + generating, reading and saving graphs + + - the :py:mod:`altgraph.Dot` module contains functions for displaying + graphs via `graphviz `_ + + - the :py:mod:`altgraph.ObjectGraph` module implements a graph of + objects with a unique identifier + +Installation +------------ + +Download and unpack the archive then type:: + + python setup.py install + +This will install the library in the default location. For instructions on +how to customize the install procedure read the output of:: + + python setup.py --help install + +To verify that the code works run the test suite:: + + python setup.py test + +Example usage +------------- + +Lets assume that we want to analyze the graph below (links to the full picture) +GRAPH_IMG. Our script then might look the following way:: + + from altgraph import Graph, GraphAlgo, Dot + + # these are the edges + edges = [ (1,2), (2,4), (1,3), (2,4), (3,4), (4,5), (6,5), + (6,14), (14,15), (6, 15), (5,7), (7, 8), (7,13), (12,8), + (8,13), (11,12), (11,9), (13,11), (9,13), (13,10) ] + + # creates the graph + graph = Graph.Graph() + for head, tail in edges: + graph.add_edge(head, tail) + + # do a forward bfs from 1 at most to 20 + print(graph.forw_bfs(1)) + +This will print the nodes in some breadth first order:: + + [1, 2, 3, 4, 5, 7, 8, 13, 11, 10, 12, 9] + +If we wanted to get the hop-distance from node 1 to node 8 +we coud write:: + + print(graph.get_hops(1, 8)) + +This will print the following:: + + [(1, 0), (2, 1), (3, 1), (4, 2), (5, 3), (7, 4), (8, 5)] + +Node 1 is at 0 hops since it is the starting node, nodes 2,3 are 1 hop away ... +node 8 is 5 hops away. To find the shortest distance between two nodes you +can use:: + + print(GraphAlgo.shortest_path(graph, 1, 12)) + +It will print the nodes on one (if there are more) the shortest paths:: + + [1, 2, 4, 5, 7, 13, 11, 12] + +To display the graph we can use the GraphViz backend:: + + dot = Dot.Dot(graph) + + # display the graph on the monitor + dot.display() + + # save it in an image file + dot.save_img(file_name='graph', file_type='gif') + + + +.. + @author: U{Istvan Albert} + + @license: MIT License + + Copyright (c) 2004 Istvan Albert unless otherwise noted. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to + deal in the Software without restriction, including without limitation the + rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + IN THE SOFTWARE. + @requires: Python 2.3 or higher + + @newfield contributor: Contributors: + @contributor: U{Reka Albert } + +""" +import pkg_resources + +__version__ = pkg_resources.require("altgraph")[0].version + + +class GraphError(ValueError): + pass diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/asttokens-2.4.1.dist-info/INSTALLER b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens-2.4.1.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens-2.4.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/asttokens-2.4.1.dist-info/LICENSE b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens-2.4.1.dist-info/LICENSE new file mode 100644 index 000000000..8dada3eda --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens-2.4.1.dist-info/LICENSE @@ -0,0 +1,201 @@ + 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/inbm/venv-3.11/lib/python3.11/site-packages/asttokens-2.4.1.dist-info/METADATA b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens-2.4.1.dist-info/METADATA new file mode 100644 index 000000000..233cd9355 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens-2.4.1.dist-info/METADATA @@ -0,0 +1,124 @@ +Metadata-Version: 2.1 +Name: asttokens +Version: 2.4.1 +Summary: Annotate AST trees with source code positions +Home-page: https://github.com/gristlabs/asttokens +Author: Dmitry Sagalovskiy, Grist Labs +Author-email: dmitry@getgrist.com +License: Apache 2.0 +Keywords: code,ast,parse,tokenize,refactor +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Topic :: Software Development :: Code Generators +Classifier: Topic :: Software Development :: Compilers +Classifier: Topic :: Software Development :: Interpreters +Classifier: Topic :: Software Development :: Pre-processors +Classifier: Environment :: Console +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +License-File: LICENSE +Requires-Dist: six >=1.12.0 +Requires-Dist: typing ; python_version < "3.5" +Provides-Extra: astroid +Requires-Dist: astroid <2,>=1 ; (python_version < "3") and extra == 'astroid' +Requires-Dist: astroid <4,>=2 ; (python_version >= "3") and extra == 'astroid' +Provides-Extra: test +Requires-Dist: pytest ; extra == 'test' +Requires-Dist: astroid <2,>=1 ; (python_version < "3") and extra == 'test' +Requires-Dist: astroid <4,>=2 ; (python_version >= "3") and extra == 'test' + +ASTTokens +========= + +.. image:: https://img.shields.io/pypi/v/asttokens.svg + :target: https://pypi.python.org/pypi/asttokens/ +.. image:: https://img.shields.io/pypi/pyversions/asttokens.svg + :target: https://pypi.python.org/pypi/asttokens/ +.. image:: https://github.com/gristlabs/asttokens/actions/workflows/build-and-test.yml/badge.svg + :target: https://github.com/gristlabs/asttokens/actions/workflows/build-and-test.yml +.. image:: https://readthedocs.org/projects/asttokens/badge/?version=latest + :target: http://asttokens.readthedocs.io/en/latest/index.html +.. image:: https://coveralls.io/repos/github/gristlabs/asttokens/badge.svg + :target: https://coveralls.io/github/gristlabs/asttokens + +.. Start of user-guide + +The ``asttokens`` module annotates Python abstract syntax trees (ASTs) with the positions of tokens +and text in the source code that generated them. + +It makes it possible for tools that work with logical AST nodes to find the particular text that +resulted in those nodes, for example for automated refactoring or highlighting. + +Installation +------------ +asttokens is available on PyPI: https://pypi.python.org/pypi/asttokens/:: + + pip install asttokens + +The code is on GitHub: https://github.com/gristlabs/asttokens. + +The API Reference is here: http://asttokens.readthedocs.io/en/latest/api-index.html. + +Usage +----- +ASTTokens works with both Python2 and Python3. + +ASTTokens can annotate both trees built by `ast `_, +AND those built by `astroid `_. + +Here's an example: + +.. code-block:: python + + import asttokens, ast + source = "Robot('blue').walk(steps=10*n)" + atok = asttokens.ASTTokens(source, parse=True) + +Once the tree has been marked, nodes get ``.first_token``, ``.last_token`` attributes, and +the ``ASTTokens`` object offers helpful methods: + +.. code-block:: python + + attr_node = next(n for n in ast.walk(atok.tree) if isinstance(n, ast.Attribute)) + print(atok.get_text(attr_node)) + start, end = attr_node.last_token.startpos, attr_node.last_token.endpos + print(atok.text[:start] + 'RUN' + atok.text[end:]) + +Which produces this output: + +.. code-block:: text + + Robot('blue').walk + Robot('blue').RUN(steps=10*n) + +The ``ASTTokens`` object also offers methods to walk and search the list of tokens that make up +the code (or a particular AST node), which is more useful and powerful than dealing with the text +directly. + + +Contribute +---------- + +To contribute: + +1. Fork this repository, and clone your fork. +2. Install the package with test dependencies (ideally in a virtualenv) with:: + + pip install -e '.[test]' + +3. Run tests in your current interpreter with the command ``pytest`` or ``python -m pytest``. +4. Run tests across all supported interpreters with the ``tox`` command. You will need to have the interpreters installed separately. We recommend ``pyenv`` for that. Use ``tox -p auto`` to run the tests in parallel. +5. By default certain tests which take a very long time to run are skipped, but they are run on travis CI. To run them locally, set the environment variable ``ASTTOKENS_SLOW_TESTS``. For example run ``ASTTOKENS_SLOW_TESTS=1 tox`` to run the full suite of tests. diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/asttokens-2.4.1.dist-info/RECORD b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens-2.4.1.dist-info/RECORD new file mode 100644 index 000000000..2c743d205 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens-2.4.1.dist-info/RECORD @@ -0,0 +1,21 @@ +asttokens-2.4.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +asttokens-2.4.1.dist-info/LICENSE,sha256=tAkwu8-AdEyGxGoSvJ2gVmQdcicWw3j1ZZueVV74M-E,11357 +asttokens-2.4.1.dist-info/METADATA,sha256=NVktxMNmzWSV0jf8-LgkKQZ2w7HmHI_4ZHcuLTg6y-A,5197 +asttokens-2.4.1.dist-info/RECORD,, +asttokens-2.4.1.dist-info/WHEEL,sha256=iYlv5fX357PQyRT2o6tw1bN-YcKFFHKqB_LwHO5wP-g,110 +asttokens-2.4.1.dist-info/top_level.txt,sha256=nJDweSD7_NBhOlR3c8bkKJMKM-pxlAS8Kyh8GcCT2dk,10 +asttokens/__init__.py,sha256=8eONA3X-9s93-v-2gEoz4649fDUpvzBthFB5Ld7dHAg,962 +asttokens/__pycache__/__init__.cpython-311.pyc,, +asttokens/__pycache__/astroid_compat.cpython-311.pyc,, +asttokens/__pycache__/asttokens.cpython-311.pyc,, +asttokens/__pycache__/line_numbers.cpython-311.pyc,, +asttokens/__pycache__/mark_tokens.cpython-311.pyc,, +asttokens/__pycache__/util.cpython-311.pyc,, +asttokens/__pycache__/version.cpython-311.pyc,, +asttokens/astroid_compat.py,sha256=ilaVBRWcHpQ3ZLBSBs9usUwnLW3Orfn6sM89cMN8zNI,586 +asttokens/asttokens.py,sha256=WIExmOOKNK4OMzCwgmFKK7pJSvp90a40zf27_Ht03W4,18867 +asttokens/line_numbers.py,sha256=z3E38XvQaocXm_5MW8-jimFr-In5iMExFkmLPHBxenY,2842 +asttokens/mark_tokens.py,sha256=Yw9sNJ8BgQ7BVohzKjCAuSowj2fT4tVrEnby9D4g0gA,22956 +asttokens/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +asttokens/util.py,sha256=VzwdnLd_ZLc89mt6BBPGkDhdWKhNRfuFTJnFOVzC5_Q,17889 +asttokens/version.py,sha256=LgDSW5laOqA_7i2VW0cZ9QumZREigUxs3ZCBzJ1EG0o,22 diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/asttokens-2.4.1.dist-info/WHEEL b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens-2.4.1.dist-info/WHEEL new file mode 100644 index 000000000..c34f1162e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens-2.4.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.41.2) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/asttokens-2.4.1.dist-info/top_level.txt b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens-2.4.1.dist-info/top_level.txt new file mode 100644 index 000000000..7adf4c51f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens-2.4.1.dist-info/top_level.txt @@ -0,0 +1 @@ +asttokens diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/__init__.py new file mode 100644 index 000000000..eeda0ed4f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/__init__.py @@ -0,0 +1,24 @@ +# Copyright 2016 Grist Labs, Inc. +# +# 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. + +""" +This module enhances the Python AST tree with token and source code information, sufficent to +detect the source text of each AST node. This is helpful for tools that make source code +transformations. +""" + +from .line_numbers import LineNumbers +from .asttokens import ASTText, ASTTokens, supports_tokenless + +__all__ = ['ASTText', 'ASTTokens', 'LineNumbers', 'supports_tokenless'] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/astroid_compat.py b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/astroid_compat.py new file mode 100644 index 000000000..9af3e17e0 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/astroid_compat.py @@ -0,0 +1,18 @@ +try: + from astroid import nodes as astroid_node_classes + + # astroid_node_classes should be whichever module has the NodeNG class + from astroid.nodes import NodeNG + from astroid.nodes import BaseContainer +except Exception: + try: + from astroid import node_classes as astroid_node_classes + from astroid.node_classes import NodeNG + from astroid.node_classes import _BaseContainer as BaseContainer + except Exception: # pragma: no cover + astroid_node_classes = None + NodeNG = None + BaseContainer = None + + +__all__ = ["astroid_node_classes", "NodeNG", "BaseContainer"] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/asttokens.py b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/asttokens.py new file mode 100644 index 000000000..d2b902da4 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/asttokens.py @@ -0,0 +1,471 @@ +# Copyright 2016 Grist Labs, Inc. +# +# 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 abc +import ast +import bisect +import sys +import token +from ast import Module +from typing import Iterable, Iterator, List, Optional, Tuple, Any, cast, TYPE_CHECKING + +import six +from six.moves import xrange # pylint: disable=redefined-builtin + +from .line_numbers import LineNumbers +from .util import ( + Token, match_token, is_non_coding_token, patched_generate_tokens, last_stmt, + annotate_fstring_nodes, generate_tokens, is_module, is_stmt +) + +if TYPE_CHECKING: # pragma: no cover + from .util import AstNode, TokenInfo + + +class ASTTextBase(six.with_metaclass(abc.ABCMeta, object)): + def __init__(self, source_text, filename): + # type: (Any, str) -> None + # FIXME: Strictly, the type of source_text is one of the six string types, but hard to specify with mypy given + # https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases + + self._filename = filename + + # Decode source after parsing to let Python 2 handle coding declarations. + # (If the encoding was not utf-8 compatible, then even if it parses correctly, + # we'll fail with a unicode error here.) + source_text = six.ensure_text(source_text) + + self._text = source_text + self._line_numbers = LineNumbers(source_text) + + @abc.abstractmethod + def get_text_positions(self, node, padded): + # type: (AstNode, bool) -> Tuple[Tuple[int, int], Tuple[int, int]] + """ + Returns two ``(lineno, col_offset)`` tuples for the start and end of the given node. + If the positions can't be determined, or the nodes don't correspond to any particular text, + returns ``(1, 0)`` for both. + + ``padded`` corresponds to the ``padded`` argument to ``ast.get_source_segment()``. + This means that if ``padded`` is True, the start position will be adjusted to include + leading whitespace if ``node`` is a multiline statement. + """ + raise NotImplementedError # pragma: no cover + + def get_text_range(self, node, padded=True): + # type: (AstNode, bool) -> Tuple[int, int] + """ + Returns the (startpos, endpos) positions in source text corresponding to the given node. + Returns (0, 0) for nodes (like `Load`) that don't correspond to any particular text. + + See ``get_text_positions()`` for details on the ``padded`` argument. + """ + start, end = self.get_text_positions(node, padded) + return ( + self._line_numbers.line_to_offset(*start), + self._line_numbers.line_to_offset(*end), + ) + + def get_text(self, node, padded=True): + # type: (AstNode, bool) -> str + """ + Returns the text corresponding to the given node. + Returns '' for nodes (like `Load`) that don't correspond to any particular text. + + See ``get_text_positions()`` for details on the ``padded`` argument. + """ + start, end = self.get_text_range(node, padded) + return self._text[start: end] + + +class ASTTokens(ASTTextBase, object): + """ + ASTTokens maintains the text of Python code in several forms: as a string, as line numbers, and + as tokens, and is used to mark and access token and position information. + + ``source_text`` must be a unicode or UTF8-encoded string. If you pass in UTF8 bytes, remember + that all offsets you'll get are to the unicode text, which is available as the ``.text`` + property. + + If ``parse`` is set, the ``source_text`` will be parsed with ``ast.parse()``, and the resulting + tree marked with token info and made available as the ``.tree`` property. + + If ``tree`` is given, it will be marked and made available as the ``.tree`` property. In + addition to the trees produced by the ``ast`` module, ASTTokens will also mark trees produced + using ``astroid`` library . + + If only ``source_text`` is given, you may use ``.mark_tokens(tree)`` to mark the nodes of an AST + tree created separately. + """ + + def __init__(self, source_text, parse=False, tree=None, filename='', tokens=None): + # type: (Any, bool, Optional[Module], str, Iterable[TokenInfo]) -> None + # FIXME: Strictly, the type of source_text is one of the six string types, but hard to specify with mypy given + # https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases + + super(ASTTokens, self).__init__(source_text, filename) + + self._tree = ast.parse(source_text, filename) if parse else tree + + # Tokenize the code. + if tokens is None: + tokens = generate_tokens(self._text) + self._tokens = list(self._translate_tokens(tokens)) + + # Extract the start positions of all tokens, so that we can quickly map positions to tokens. + self._token_offsets = [tok.startpos for tok in self._tokens] + + if self._tree: + self.mark_tokens(self._tree) + + def mark_tokens(self, root_node): + # type: (Module) -> None + """ + Given the root of the AST or Astroid tree produced from source_text, visits all nodes marking + them with token and position information by adding ``.first_token`` and + ``.last_token``attributes. This is done automatically in the constructor when ``parse`` or + ``tree`` arguments are set, but may be used manually with a separate AST or Astroid tree. + """ + # The hard work of this class is done by MarkTokens + from .mark_tokens import MarkTokens # to avoid import loops + MarkTokens(self).visit_tree(root_node) + + def _translate_tokens(self, original_tokens): + # type: (Iterable[TokenInfo]) -> Iterator[Token] + """ + Translates the given standard library tokens into our own representation. + """ + for index, tok in enumerate(patched_generate_tokens(original_tokens)): + tok_type, tok_str, start, end, line = tok + yield Token(tok_type, tok_str, start, end, line, index, + self._line_numbers.line_to_offset(start[0], start[1]), + self._line_numbers.line_to_offset(end[0], end[1])) + + @property + def text(self): + # type: () -> str + """The source code passed into the constructor.""" + return self._text + + @property + def tokens(self): + # type: () -> List[Token] + """The list of tokens corresponding to the source code from the constructor.""" + return self._tokens + + @property + def tree(self): + # type: () -> Optional[Module] + """The root of the AST tree passed into the constructor or parsed from the source code.""" + return self._tree + + @property + def filename(self): + # type: () -> str + """The filename that was parsed""" + return self._filename + + def get_token_from_offset(self, offset): + # type: (int) -> Token + """ + Returns the token containing the given character offset (0-based position in source text), + or the preceeding token if the position is between tokens. + """ + return self._tokens[bisect.bisect(self._token_offsets, offset) - 1] + + def get_token(self, lineno, col_offset): + # type: (int, int) -> Token + """ + Returns the token containing the given (lineno, col_offset) position, or the preceeding token + if the position is between tokens. + """ + # TODO: add test for multibyte unicode. We need to translate offsets from ast module (which + # are in utf8) to offsets into the unicode text. tokenize module seems to use unicode offsets + # but isn't explicit. + return self.get_token_from_offset(self._line_numbers.line_to_offset(lineno, col_offset)) + + def get_token_from_utf8(self, lineno, col_offset): + # type: (int, int) -> Token + """ + Same as get_token(), but interprets col_offset as a UTF8 offset, which is what `ast` uses. + """ + return self.get_token(lineno, self._line_numbers.from_utf8_col(lineno, col_offset)) + + def next_token(self, tok, include_extra=False): + # type: (Token, bool) -> Token + """ + Returns the next token after the given one. If include_extra is True, includes non-coding + tokens from the tokenize module, such as NL and COMMENT. + """ + i = tok.index + 1 + if not include_extra: + while is_non_coding_token(self._tokens[i].type): + i += 1 + return self._tokens[i] + + def prev_token(self, tok, include_extra=False): + # type: (Token, bool) -> Token + """ + Returns the previous token before the given one. If include_extra is True, includes non-coding + tokens from the tokenize module, such as NL and COMMENT. + """ + i = tok.index - 1 + if not include_extra: + while is_non_coding_token(self._tokens[i].type): + i -= 1 + return self._tokens[i] + + def find_token(self, start_token, tok_type, tok_str=None, reverse=False): + # type: (Token, int, Optional[str], bool) -> Token + """ + Looks for the first token, starting at start_token, that matches tok_type and, if given, the + token string. Searches backwards if reverse is True. Returns ENDMARKER token if not found (you + can check it with `token.ISEOF(t.type)`). + """ + t = start_token + advance = self.prev_token if reverse else self.next_token + while not match_token(t, tok_type, tok_str) and not token.ISEOF(t.type): + t = advance(t, include_extra=True) + return t + + def token_range(self, + first_token, # type: Token + last_token, # type: Token + include_extra=False, # type: bool + ): + # type: (...) -> Iterator[Token] + """ + Yields all tokens in order from first_token through and including last_token. If + include_extra is True, includes non-coding tokens such as tokenize.NL and .COMMENT. + """ + for i in xrange(first_token.index, last_token.index + 1): + if include_extra or not is_non_coding_token(self._tokens[i].type): + yield self._tokens[i] + + def get_tokens(self, node, include_extra=False): + # type: (AstNode, bool) -> Iterator[Token] + """ + Yields all tokens making up the given node. If include_extra is True, includes non-coding + tokens such as tokenize.NL and .COMMENT. + """ + return self.token_range(node.first_token, node.last_token, include_extra=include_extra) + + def get_text_positions(self, node, padded): + # type: (AstNode, bool) -> Tuple[Tuple[int, int], Tuple[int, int]] + """ + Returns two ``(lineno, col_offset)`` tuples for the start and end of the given node. + If the positions can't be determined, or the nodes don't correspond to any particular text, + returns ``(1, 0)`` for both. + + ``padded`` corresponds to the ``padded`` argument to ``ast.get_source_segment()``. + This means that if ``padded`` is True, the start position will be adjusted to include + leading whitespace if ``node`` is a multiline statement. + """ + if not hasattr(node, 'first_token'): + return (1, 0), (1, 0) + + start = node.first_token.start + end = node.last_token.end + if padded and any(match_token(t, token.NEWLINE) for t in self.get_tokens(node)): + # Set col_offset to 0 to include leading indentation for multiline statements. + start = (start[0], 0) + + return start, end + + +class ASTText(ASTTextBase, object): + """ + Supports the same ``get_text*`` methods as ``ASTTokens``, + but uses the AST to determine the text positions instead of tokens. + This is faster than ``ASTTokens`` as it requires less setup work. + + It also (sometimes) supports nodes inside f-strings, which ``ASTTokens`` doesn't. + + Some node types and/or Python versions are not supported. + In these cases the ``get_text*`` methods will fall back to using ``ASTTokens`` + which incurs the usual setup cost the first time. + If you want to avoid this, check ``supports_tokenless(node)`` before calling ``get_text*`` methods. + """ + def __init__(self, source_text, tree=None, filename=''): + # type: (Any, Optional[Module], str) -> None + # FIXME: Strictly, the type of source_text is one of the six string types, but hard to specify with mypy given + # https://mypy.readthedocs.io/en/stable/common_issues.html#variables-vs-type-aliases + + super(ASTText, self).__init__(source_text, filename) + + self._tree = tree + if self._tree is not None: + annotate_fstring_nodes(self._tree) + + self._asttokens = None # type: Optional[ASTTokens] + + @property + def tree(self): + # type: () -> Module + if self._tree is None: + self._tree = ast.parse(self._text, self._filename) + annotate_fstring_nodes(self._tree) + return self._tree + + @property + def asttokens(self): + # type: () -> ASTTokens + if self._asttokens is None: + self._asttokens = ASTTokens( + self._text, + tree=self.tree, + filename=self._filename, + ) + return self._asttokens + + def _get_text_positions_tokenless(self, node, padded): + # type: (AstNode, bool) -> Tuple[Tuple[int, int], Tuple[int, int]] + """ + Version of ``get_text_positions()`` that doesn't use tokens. + """ + if sys.version_info[:2] < (3, 8): # pragma: no cover + # This is just for mpypy + raise AssertionError("This method should only be called internally after checking supports_tokenless()") + + if is_module(node): + # Modules don't have position info, so just return the range of the whole text. + # The token-using method does something different, but its behavior seems weird and inconsistent. + # For example, in a file with only comments, it only returns the first line. + # It's hard to imagine a case when this matters. + return (1, 0), self._line_numbers.offset_to_line(len(self._text)) + + if getattr(node, 'lineno', None) is None: + return (1, 0), (1, 0) + + assert node # tell mypy that node is not None, which we allowed up to here for compatibility + + decorators = getattr(node, 'decorator_list', []) + if not decorators: + # Astroid uses node.decorators.nodes instead of node.decorator_list. + decorators_node = getattr(node, 'decorators', None) + decorators = getattr(decorators_node, 'nodes', []) + if decorators: + # Function/Class definition nodes are marked by AST as starting at def/class, + # not the first decorator. This doesn't match the token-using behavior, + # or inspect.getsource(), and just seems weird. + start_node = decorators[0] + else: + start_node = node + + start_lineno = start_node.lineno + end_node = last_stmt(node) + + # Include leading indentation for multiline statements. + # This doesn't mean simple statements that happen to be on multiple lines, + # but compound statements where inner indentation matters. + # So we don't just compare node.lineno and node.end_lineno, + # we check for a contained statement starting on a different line. + if padded and ( + start_lineno != end_node.lineno + or ( + # Astroid docstrings aren't treated as separate statements. + # So to handle function/class definitions with a docstring but no other body, + # we just check that the node is a statement with a docstring + # and spanning multiple lines in the simple, literal sense. + start_lineno != node.end_lineno + and getattr(node, "doc_node", None) + and is_stmt(node) + ) + ): + start_col_offset = 0 + else: + start_col_offset = self._line_numbers.from_utf8_col(start_lineno, start_node.col_offset) + + start = (start_lineno, start_col_offset) + + # To match the token-using behaviour, we exclude trailing semicolons and comments. + # This means that for blocks containing multiple statements, we have to use the last one + # instead of the actual node for end_lineno and end_col_offset. + end_lineno = cast(int, end_node.end_lineno) + end_col_offset = cast(int, end_node.end_col_offset) + end_col_offset = self._line_numbers.from_utf8_col(end_lineno, end_col_offset) + end = (end_lineno, end_col_offset) + + return start, end + + def get_text_positions(self, node, padded): + # type: (AstNode, bool) -> Tuple[Tuple[int, int], Tuple[int, int]] + """ + Returns two ``(lineno, col_offset)`` tuples for the start and end of the given node. + If the positions can't be determined, or the nodes don't correspond to any particular text, + returns ``(1, 0)`` for both. + + ``padded`` corresponds to the ``padded`` argument to ``ast.get_source_segment()``. + This means that if ``padded`` is True, the start position will be adjusted to include + leading whitespace if ``node`` is a multiline statement. + """ + if getattr(node, "_broken_positions", None): + # This node was marked in util.annotate_fstring_nodes as having untrustworthy lineno/col_offset. + return (1, 0), (1, 0) + + if supports_tokenless(node): + return self._get_text_positions_tokenless(node, padded) + + return self.asttokens.get_text_positions(node, padded) + + +# Node types that _get_text_positions_tokenless doesn't support. Only relevant for Python 3.8+. +_unsupported_tokenless_types = () # type: Tuple[str, ...] +if sys.version_info[:2] >= (3, 8): + # no lineno + _unsupported_tokenless_types += ("arguments", "Arguments", "withitem") + if sys.version_info[:2] == (3, 8): + # _get_text_positions_tokenless works incorrectly for these types due to bugs in Python 3.8. + _unsupported_tokenless_types += ("arg", "Starred") + # no lineno in 3.8 + _unsupported_tokenless_types += ("Slice", "ExtSlice", "Index", "keyword") + + +def supports_tokenless(node=None): + # type: (Any) -> bool + """ + Returns True if the Python version and the node (if given) are supported by + the ``get_text*`` methods of ``ASTText`` without falling back to ``ASTTokens``. + See ``ASTText`` for why this matters. + + The following cases are not supported: + + - Python 3.7 and earlier + - PyPy + - ``ast.arguments`` / ``astroid.Arguments`` + - ``ast.withitem`` + - ``astroid.Comprehension`` + - ``astroid.AssignName`` inside ``astroid.Arguments`` or ``astroid.ExceptHandler`` + - The following nodes in Python 3.8 only: + - ``ast.arg`` + - ``ast.Starred`` + - ``ast.Slice`` + - ``ast.ExtSlice`` + - ``ast.Index`` + - ``ast.keyword`` + """ + return ( + type(node).__name__ not in _unsupported_tokenless_types + and not ( + # astroid nodes + not isinstance(node, ast.AST) and node is not None and ( + ( + type(node).__name__ == "AssignName" + and type(node.parent).__name__ in ("Arguments", "ExceptHandler") + ) + ) + ) + and sys.version_info[:2] >= (3, 8) + and 'pypy' not in sys.version.lower() + ) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/line_numbers.py b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/line_numbers.py new file mode 100644 index 000000000..aaf76cef6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/line_numbers.py @@ -0,0 +1,76 @@ +# Copyright 2016 Grist Labs, Inc. +# +# 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 bisect +import re +from typing import Dict, List, Tuple + +_line_start_re = re.compile(r'^', re.M) + +class LineNumbers(object): + """ + Class to convert between character offsets in a text string, and pairs (line, column) of 1-based + line and 0-based column numbers, as used by tokens and AST nodes. + + This class expects unicode for input and stores positions in unicode. But it supports + translating to and from utf8 offsets, which are used by ast parsing. + """ + def __init__(self, text): + # type: (str) -> None + # A list of character offsets of each line's first character. + self._line_offsets = [m.start(0) for m in _line_start_re.finditer(text)] + self._text = text + self._text_len = len(text) + self._utf8_offset_cache = {} # type: Dict[int, List[int]] # maps line num to list of char offset for each byte in line + + def from_utf8_col(self, line, utf8_column): + # type: (int, int) -> int + """ + Given a 1-based line number and 0-based utf8 column, returns a 0-based unicode column. + """ + offsets = self._utf8_offset_cache.get(line) + if offsets is None: + end_offset = self._line_offsets[line] if line < len(self._line_offsets) else self._text_len + line_text = self._text[self._line_offsets[line - 1] : end_offset] + + offsets = [i for i,c in enumerate(line_text) for byte in c.encode('utf8')] + offsets.append(len(line_text)) + self._utf8_offset_cache[line] = offsets + + return offsets[max(0, min(len(offsets)-1, utf8_column))] + + def line_to_offset(self, line, column): + # type: (int, int) -> int + """ + Converts 1-based line number and 0-based column to 0-based character offset into text. + """ + line -= 1 + if line >= len(self._line_offsets): + return self._text_len + elif line < 0: + return 0 + else: + return min(self._line_offsets[line] + max(0, column), self._text_len) + + def offset_to_line(self, offset): + # type: (int) -> Tuple[int, int] + """ + Converts 0-based character offset to pair (line, col) of 1-based line and 0-based column + numbers. + """ + offset = max(0, min(self._text_len, offset)) + line_index = bisect.bisect_right(self._line_offsets, offset) - 1 + return (line_index + 1, offset - self._line_offsets[line_index]) + + diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/mark_tokens.py b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/mark_tokens.py new file mode 100644 index 000000000..f5a8ac41c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/mark_tokens.py @@ -0,0 +1,505 @@ +# Copyright 2016 Grist Labs, Inc. +# +# 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 ast +import numbers +import sys +import token +from ast import Module +from typing import Callable, List, Union, cast, Optional, Tuple, TYPE_CHECKING + +import six + +from . import util +from .asttokens import ASTTokens +from .util import AstConstant +from .astroid_compat import astroid_node_classes as nc, BaseContainer as AstroidBaseContainer + +if TYPE_CHECKING: + from .util import AstNode + + +# Mapping of matching braces. To find a token here, look up token[:2]. +_matching_pairs_left = { + (token.OP, '('): (token.OP, ')'), + (token.OP, '['): (token.OP, ']'), + (token.OP, '{'): (token.OP, '}'), +} + +_matching_pairs_right = { + (token.OP, ')'): (token.OP, '('), + (token.OP, ']'): (token.OP, '['), + (token.OP, '}'): (token.OP, '{'), +} + + +class MarkTokens(object): + """ + Helper that visits all nodes in the AST tree and assigns .first_token and .last_token attributes + to each of them. This is the heart of the token-marking logic. + """ + def __init__(self, code): + # type: (ASTTokens) -> None + self._code = code + self._methods = util.NodeMethods() + self._iter_children = None # type: Optional[Callable] + + def visit_tree(self, node): + # type: (Module) -> None + self._iter_children = util.iter_children_func(node) + util.visit_tree(node, self._visit_before_children, self._visit_after_children) + + def _visit_before_children(self, node, parent_token): + # type: (AstNode, Optional[util.Token]) -> Tuple[Optional[util.Token], Optional[util.Token]] + col = getattr(node, 'col_offset', None) + token = self._code.get_token_from_utf8(node.lineno, col) if col is not None else None + + if not token and util.is_module(node): + # We'll assume that a Module node starts at the start of the source code. + token = self._code.get_token(1, 0) + + # Use our own token, or our parent's if we don't have one, to pass to child calls as + # parent_token argument. The second value becomes the token argument of _visit_after_children. + return (token or parent_token, token) + + def _visit_after_children(self, node, parent_token, token): + # type: (AstNode, Optional[util.Token], Optional[util.Token]) -> None + # This processes the node generically first, after all children have been processed. + + # Get the first and last tokens that belong to children. Note how this doesn't assume that we + # iterate through children in order that corresponds to occurrence in source code. This + # assumption can fail (e.g. with return annotations). + first = token + last = None + for child in cast(Callable, self._iter_children)(node): + # astroid slices have especially wrong positions, we don't want them to corrupt their parents. + if util.is_empty_astroid_slice(child): + continue + if not first or child.first_token.index < first.index: + first = child.first_token + if not last or child.last_token.index > last.index: + last = child.last_token + + # If we don't have a first token from _visit_before_children, and there were no children, then + # use the parent's token as the first token. + first = first or parent_token + + # If no children, set last token to the first one. + last = last or first + + # Statements continue to before NEWLINE. This helps cover a few different cases at once. + if util.is_stmt(node): + last = self._find_last_in_stmt(cast(util.Token, last)) + + # Capture any unmatched brackets. + first, last = self._expand_to_matching_pairs(cast(util.Token, first), cast(util.Token, last), node) + + # Give a chance to node-specific methods to adjust. + nfirst, nlast = self._methods.get(self, node.__class__)(node, first, last) + + if (nfirst, nlast) != (first, last): + # If anything changed, expand again to capture any unmatched brackets. + nfirst, nlast = self._expand_to_matching_pairs(nfirst, nlast, node) + + node.first_token = nfirst + node.last_token = nlast + + def _find_last_in_stmt(self, start_token): + # type: (util.Token) -> util.Token + t = start_token + while (not util.match_token(t, token.NEWLINE) and + not util.match_token(t, token.OP, ';') and + not token.ISEOF(t.type)): + t = self._code.next_token(t, include_extra=True) + return self._code.prev_token(t) + + def _expand_to_matching_pairs(self, first_token, last_token, node): + # type: (util.Token, util.Token, AstNode) -> Tuple[util.Token, util.Token] + """ + Scan tokens in [first_token, last_token] range that are between node's children, and for any + unmatched brackets, adjust first/last tokens to include the closing pair. + """ + # We look for opening parens/braces among non-child tokens (i.e. tokens between our actual + # child nodes). If we find any closing ones, we match them to the opens. + to_match_right = [] # type: List[Tuple[int, str]] + to_match_left = [] + for tok in self._code.token_range(first_token, last_token): + tok_info = tok[:2] + if to_match_right and tok_info == to_match_right[-1]: + to_match_right.pop() + elif tok_info in _matching_pairs_left: + to_match_right.append(_matching_pairs_left[tok_info]) + elif tok_info in _matching_pairs_right: + to_match_left.append(_matching_pairs_right[tok_info]) + + # Once done, extend `last_token` to match any unclosed parens/braces. + for match in reversed(to_match_right): + last = self._code.next_token(last_token) + # Allow for trailing commas or colons (allowed in subscripts) before the closing delimiter + while any(util.match_token(last, token.OP, x) for x in (',', ':')): + last = self._code.next_token(last) + # Now check for the actual closing delimiter. + if util.match_token(last, *match): + last_token = last + + # And extend `first_token` to match any unclosed opening parens/braces. + for match in to_match_left: + first = self._code.prev_token(first_token) + if util.match_token(first, *match): + first_token = first + + return (first_token, last_token) + + #---------------------------------------------------------------------- + # Node visitors. Each takes a preliminary first and last tokens, and returns the adjusted pair + # that will actually be assigned. + + def visit_default(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + # pylint: disable=no-self-use + # By default, we don't need to adjust the token we computed earlier. + return (first_token, last_token) + + def handle_comp(self, open_brace, node, first_token, last_token): + # type: (str, AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + # For list/set/dict comprehensions, we only get the token of the first child, so adjust it to + # include the opening brace (the closing brace will be matched automatically). + before = self._code.prev_token(first_token) + util.expect_token(before, token.OP, open_brace) + return (before, last_token) + + # Python 3.8 fixed the starting position of list comprehensions: + # https://bugs.python.org/issue31241 + if sys.version_info < (3, 8): + def visit_listcomp(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + return self.handle_comp('[', node, first_token, last_token) + + if six.PY2: + # We shouldn't do this on PY3 because its SetComp/DictComp already have a correct start. + def visit_setcomp(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + return self.handle_comp('{', node, first_token, last_token) + + def visit_dictcomp(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + return self.handle_comp('{', node, first_token, last_token) + + def visit_comprehension(self, + node, # type: AstNode + first_token, # type: util.Token + last_token, # type: util.Token + ): + # type: (...) -> Tuple[util.Token, util.Token] + # The 'comprehension' node starts with 'for' but we only get first child; we search backwards + # to find the 'for' keyword. + first = self._code.find_token(first_token, token.NAME, 'for', reverse=True) + return (first, last_token) + + def visit_if(self, node, first_token, last_token): + # type: (util.Token, util.Token, util.Token) -> Tuple[util.Token, util.Token] + while first_token.string not in ('if', 'elif'): + first_token = self._code.prev_token(first_token) + return first_token, last_token + + def handle_attr(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + # Attribute node has ".attr" (2 tokens) after the last child. + dot = self._code.find_token(last_token, token.OP, '.') + name = self._code.next_token(dot) + util.expect_token(name, token.NAME) + return (first_token, name) + + visit_attribute = handle_attr + visit_assignattr = handle_attr + visit_delattr = handle_attr + + def handle_def(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + # With astroid, nodes that start with a doc-string can have an empty body, in which case we + # need to adjust the last token to include the doc string. + if not node.body and (getattr(node, 'doc_node', None) or getattr(node, 'doc', None)): # type: ignore[union-attr] + last_token = self._code.find_token(last_token, token.STRING) + + # Include @ from decorator + if first_token.index > 0: + prev = self._code.prev_token(first_token) + if util.match_token(prev, token.OP, '@'): + first_token = prev + return (first_token, last_token) + + visit_classdef = handle_def + visit_functiondef = handle_def + + def handle_following_brackets(self, node, last_token, opening_bracket): + # type: (AstNode, util.Token, str) -> util.Token + # This is for calls and subscripts, which have a pair of brackets + # at the end which may contain no nodes, e.g. foo() or bar[:]. + # We look for the opening bracket and then let the matching pair be found automatically + # Remember that last_token is at the end of all children, + # so we are not worried about encountering a bracket that belongs to a child. + first_child = next(cast(Callable, self._iter_children)(node)) + call_start = self._code.find_token(first_child.last_token, token.OP, opening_bracket) + if call_start.index > last_token.index: + last_token = call_start + return last_token + + def visit_call(self, node, first_token, last_token): + # type: (util.Token, util.Token, util.Token) -> Tuple[util.Token, util.Token] + last_token = self.handle_following_brackets(node, last_token, '(') + + # Handling a python bug with decorators with empty parens, e.g. + # @deco() + # def ... + if util.match_token(first_token, token.OP, '@'): + first_token = self._code.next_token(first_token) + return (first_token, last_token) + + def visit_matchclass(self, node, first_token, last_token): + # type: (util.Token, util.Token, util.Token) -> Tuple[util.Token, util.Token] + last_token = self.handle_following_brackets(node, last_token, '(') + return (first_token, last_token) + + def visit_subscript(self, + node, # type: AstNode + first_token, # type: util.Token + last_token, # type: util.Token + ): + # type: (...) -> Tuple[util.Token, util.Token] + last_token = self.handle_following_brackets(node, last_token, '[') + return (first_token, last_token) + + def visit_slice(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + # consume `:` tokens to the left and right. In Python 3.9, Slice nodes are + # given a col_offset, (and end_col_offset), so this will always start inside + # the slice, even if it is the empty slice. However, in 3.8 and below, this + # will only expand to the full slice if the slice contains a node with a + # col_offset. So x[:] will only get the correct tokens in 3.9, but x[1:] and + # x[:1] will even on earlier versions of Python. + while True: + prev = self._code.prev_token(first_token) + if prev.string != ':': + break + first_token = prev + while True: + next_ = self._code.next_token(last_token) + if next_.string != ':': + break + last_token = next_ + return (first_token, last_token) + + def handle_bare_tuple(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + # A bare tuple doesn't include parens; if there is a trailing comma, make it part of the tuple. + maybe_comma = self._code.next_token(last_token) + if util.match_token(maybe_comma, token.OP, ','): + last_token = maybe_comma + return (first_token, last_token) + + if sys.version_info >= (3, 8): + # In Python3.8 parsed tuples include parentheses when present. + def handle_tuple_nonempty(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + assert isinstance(node, ast.Tuple) or isinstance(node, AstroidBaseContainer) + # It's a bare tuple if the first token belongs to the first child. The first child may + # include extraneous parentheses (which don't create new nodes), so account for those too. + child = node.elts[0] + if TYPE_CHECKING: + child = cast(AstNode, child) + child_first, child_last = self._gobble_parens(child.first_token, child.last_token, True) + if first_token == child_first: + return self.handle_bare_tuple(node, first_token, last_token) + return (first_token, last_token) + else: + # Before python 3.8, parsed tuples do not include parens. + def handle_tuple_nonempty(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + (first_token, last_token) = self.handle_bare_tuple(node, first_token, last_token) + return self._gobble_parens(first_token, last_token, False) + + def visit_tuple(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + assert isinstance(node, ast.Tuple) or isinstance(node, AstroidBaseContainer) + if not node.elts: + # An empty tuple is just "()", and we need no further info. + return (first_token, last_token) + return self.handle_tuple_nonempty(node, first_token, last_token) + + def _gobble_parens(self, first_token, last_token, include_all=False): + # type: (util.Token, util.Token, bool) -> Tuple[util.Token, util.Token] + # Expands a range of tokens to include one or all pairs of surrounding parentheses, and + # returns (first, last) tokens that include these parens. + while first_token.index > 0: + prev = self._code.prev_token(first_token) + next = self._code.next_token(last_token) + if util.match_token(prev, token.OP, '(') and util.match_token(next, token.OP, ')'): + first_token, last_token = prev, next + if include_all: + continue + break + return (first_token, last_token) + + def visit_str(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + return self.handle_str(first_token, last_token) + + def visit_joinedstr(self, + node, # type: AstNode + first_token, # type: util.Token + last_token, # type: util.Token + ): + # type: (...) -> Tuple[util.Token, util.Token] + if sys.version_info < (3, 12): + # Older versions don't tokenize the contents of f-strings + return self.handle_str(first_token, last_token) + + last = first_token + while True: + if util.match_token(last, getattr(token, "FSTRING_START")): + # Python 3.12+ has tokens for the start (e.g. `f"`) and end (`"`) + # of the f-string. We can't just look for the next FSTRING_END + # because f-strings can be nested, e.g. f"{f'{x}'}", so we need + # to treat this like matching balanced parentheses. + count = 1 + while count > 0: + last = self._code.next_token(last) + # mypy complains about token.FSTRING_START and token.FSTRING_END. + if util.match_token(last, getattr(token, "FSTRING_START")): + count += 1 + elif util.match_token(last, getattr(token, "FSTRING_END")): + count -= 1 + last_token = last + last = self._code.next_token(last_token) + elif util.match_token(last, token.STRING): + # Similar to handle_str, we also need to handle adjacent strings. + last_token = last + last = self._code.next_token(last_token) + else: + break + return (first_token, last_token) + + def visit_bytes(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + return self.handle_str(first_token, last_token) + + def handle_str(self, first_token, last_token): + # type: (util.Token, util.Token) -> Tuple[util.Token, util.Token] + # Multiple adjacent STRING tokens form a single string. + last = self._code.next_token(last_token) + while util.match_token(last, token.STRING): + last_token = last + last = self._code.next_token(last_token) + return (first_token, last_token) + + def handle_num(self, + node, # type: AstNode + value, # type: Union[complex, int, numbers.Number] + first_token, # type: util.Token + last_token, # type: util.Token + ): + # type: (...) -> Tuple[util.Token, util.Token] + # A constant like '-1' gets turned into two tokens; this will skip the '-'. + while util.match_token(last_token, token.OP): + last_token = self._code.next_token(last_token) + + if isinstance(value, complex): + # A complex number like -2j cannot be compared directly to 0 + # A complex number like 1-2j is expressed as a binary operation + # so we don't need to worry about it + value = value.imag + + # This makes sure that the - is included + if value < 0 and first_token.type == token.NUMBER: # type: ignore[operator] + first_token = self._code.prev_token(first_token) + return (first_token, last_token) + + def visit_num(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + return self.handle_num(node, cast(ast.Num, node).n, first_token, last_token) + + # In Astroid, the Num and Str nodes are replaced by Const. + def visit_const(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + assert isinstance(node, AstConstant) or isinstance(node, nc.Const) + if isinstance(node.value, numbers.Number): + return self.handle_num(node, node.value, first_token, last_token) + elif isinstance(node.value, (six.text_type, six.binary_type)): + return self.visit_str(node, first_token, last_token) + return (first_token, last_token) + + # In Python >= 3.6, there is a similar class 'Constant' for literals + # In 3.8 it became the type produced by ast.parse + # https://bugs.python.org/issue32892 + visit_constant = visit_const + + def visit_keyword(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + # Until python 3.9 (https://bugs.python.org/issue40141), + # ast.keyword nodes didn't have line info. Astroid has lineno None. + assert isinstance(node, ast.keyword) or isinstance(node, nc.Keyword) + if node.arg is not None and getattr(node, 'lineno', None) is None: + equals = self._code.find_token(first_token, token.OP, '=', reverse=True) + name = self._code.prev_token(equals) + util.expect_token(name, token.NAME, node.arg) + first_token = name + return (first_token, last_token) + + def visit_starred(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + # Astroid has 'Starred' nodes (for "foo(*bar)" type args), but they need to be adjusted. + if not util.match_token(first_token, token.OP, '*'): + star = self._code.prev_token(first_token) + if util.match_token(star, token.OP, '*'): + first_token = star + return (first_token, last_token) + + def visit_assignname(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + # Astroid may turn 'except' clause into AssignName, but we need to adjust it. + if util.match_token(first_token, token.NAME, 'except'): + colon = self._code.find_token(last_token, token.OP, ':') + first_token = last_token = self._code.prev_token(colon) + return (first_token, last_token) + + if six.PY2: + # No need for this on Python3, which already handles 'with' nodes correctly. + def visit_with(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + first = self._code.find_token(first_token, token.NAME, 'with', reverse=True) + return (first, last_token) + + # Async nodes should typically start with the word 'async' + # but Python < 3.7 doesn't put the col_offset there + # AsyncFunctionDef is slightly different because it might have + # decorators before that, which visit_functiondef handles + def handle_async(self, node, first_token, last_token): + # type: (AstNode, util.Token, util.Token) -> Tuple[util.Token, util.Token] + if not first_token.string == 'async': + first_token = self._code.prev_token(first_token) + return (first_token, last_token) + + visit_asyncfor = handle_async + visit_asyncwith = handle_async + + def visit_asyncfunctiondef(self, + node, # type: AstNode + first_token, # type: util.Token + last_token, # type: util.Token + ): + # type: (...) -> Tuple[util.Token, util.Token] + if util.match_token(first_token, token.NAME, 'def'): + # Include the 'async' token + first_token = self._code.prev_token(first_token) + return self.visit_functiondef(node, first_token, last_token) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/py.typed b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/util.py b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/util.py new file mode 100644 index 000000000..cbd309309 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/util.py @@ -0,0 +1,484 @@ +# Copyright 2016 Grist Labs, Inc. +# +# 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 ast +import collections +import io +import sys +import token +import tokenize +from abc import ABCMeta +from ast import Module, expr, AST +from typing import Callable, Dict, Iterable, Iterator, List, Optional, Tuple, Union, cast, Any, TYPE_CHECKING + +from six import iteritems + + +if TYPE_CHECKING: # pragma: no cover + from .astroid_compat import NodeNG + + # Type class used to expand out the definition of AST to include fields added by this library + # It's not actually used for anything other than type checking though! + class EnhancedAST(AST): + # Additional attributes set by mark_tokens + first_token = None # type: Token + last_token = None # type: Token + lineno = 0 # type: int + + AstNode = Union[EnhancedAST, NodeNG] + + if sys.version_info[0] == 2: + TokenInfo = Tuple[int, str, Tuple[int, int], Tuple[int, int], str] + else: + TokenInfo = tokenize.TokenInfo + + +def token_repr(tok_type, string): + # type: (int, Optional[str]) -> str + """Returns a human-friendly representation of a token with the given type and string.""" + # repr() prefixes unicode with 'u' on Python2 but not Python3; strip it out for consistency. + return '%s:%s' % (token.tok_name[tok_type], repr(string).lstrip('u')) + + +class Token(collections.namedtuple('Token', 'type string start end line index startpos endpos')): + """ + TokenInfo is an 8-tuple containing the same 5 fields as the tokens produced by the tokenize + module, and 3 additional ones useful for this module: + + - [0] .type Token type (see token.py) + - [1] .string Token (a string) + - [2] .start Starting (row, column) indices of the token (a 2-tuple of ints) + - [3] .end Ending (row, column) indices of the token (a 2-tuple of ints) + - [4] .line Original line (string) + - [5] .index Index of the token in the list of tokens that it belongs to. + - [6] .startpos Starting character offset into the input text. + - [7] .endpos Ending character offset into the input text. + """ + def __str__(self): + # type: () -> str + return token_repr(self.type, self.string) + + +if sys.version_info >= (3, 6): + AstConstant = ast.Constant +else: + class AstConstant: + value = object() + + +def match_token(token, tok_type, tok_str=None): + # type: (Token, int, Optional[str]) -> bool + """Returns true if token is of the given type and, if a string is given, has that string.""" + return token.type == tok_type and (tok_str is None or token.string == tok_str) + + +def expect_token(token, tok_type, tok_str=None): + # type: (Token, int, Optional[str]) -> None + """ + Verifies that the given token is of the expected type. If tok_str is given, the token string + is verified too. If the token doesn't match, raises an informative ValueError. + """ + if not match_token(token, tok_type, tok_str): + raise ValueError("Expected token %s, got %s on line %s col %s" % ( + token_repr(tok_type, tok_str), str(token), + token.start[0], token.start[1] + 1)) + +# These were previously defined in tokenize.py and distinguishable by being greater than +# token.N_TOKEN. As of python3.7, they are in token.py, and we check for them explicitly. +if sys.version_info >= (3, 7): + def is_non_coding_token(token_type): + # type: (int) -> bool + """ + These are considered non-coding tokens, as they don't affect the syntax tree. + """ + return token_type in (token.NL, token.COMMENT, token.ENCODING) +else: + def is_non_coding_token(token_type): + # type: (int) -> bool + """ + These are considered non-coding tokens, as they don't affect the syntax tree. + """ + return token_type >= token.N_TOKENS + + +def generate_tokens(text): + # type: (str) -> Iterator[TokenInfo] + """ + Generates standard library tokens for the given code. + """ + # tokenize.generate_tokens is technically an undocumented API for Python3, but allows us to use the same API as for + # Python2. See http://stackoverflow.com/a/4952291/328565. + # FIXME: Remove cast once https://github.com/python/typeshed/issues/7003 gets fixed + return tokenize.generate_tokens(cast(Callable[[], str], io.StringIO(text).readline)) + + +def iter_children_func(node): + # type: (AST) -> Callable + """ + Returns a function which yields all direct children of a AST node, + skipping children that are singleton nodes. + The function depends on whether ``node`` is from ``ast`` or from the ``astroid`` module. + """ + return iter_children_astroid if hasattr(node, 'get_children') else iter_children_ast + + +def iter_children_astroid(node, include_joined_str=False): + # type: (NodeNG, bool) -> Union[Iterator, List] + if not include_joined_str and is_joined_str(node): + return [] + + return node.get_children() + + +SINGLETONS = {c for n, c in iteritems(ast.__dict__) if isinstance(c, type) and + issubclass(c, (ast.expr_context, ast.boolop, ast.operator, ast.unaryop, ast.cmpop))} + + +def iter_children_ast(node, include_joined_str=False): + # type: (AST, bool) -> Iterator[Union[AST, expr]] + if not include_joined_str and is_joined_str(node): + return + + if isinstance(node, ast.Dict): + # override the iteration order: instead of , , + # yield keys and values in source order (key1, value1, key2, value2, ...) + for (key, value) in zip(node.keys, node.values): + if key is not None: + yield key + yield value + return + + for child in ast.iter_child_nodes(node): + # Skip singleton children; they don't reflect particular positions in the code and break the + # assumptions about the tree consisting of distinct nodes. Note that collecting classes + # beforehand and checking them in a set is faster than using isinstance each time. + if child.__class__ not in SINGLETONS: + yield child + + +stmt_class_names = {n for n, c in iteritems(ast.__dict__) + if isinstance(c, type) and issubclass(c, ast.stmt)} +expr_class_names = ({n for n, c in iteritems(ast.__dict__) + if isinstance(c, type) and issubclass(c, ast.expr)} | + {'AssignName', 'DelName', 'Const', 'AssignAttr', 'DelAttr'}) + +# These feel hacky compared to isinstance() but allow us to work with both ast and astroid nodes +# in the same way, and without even importing astroid. +def is_expr(node): + # type: (AstNode) -> bool + """Returns whether node is an expression node.""" + return node.__class__.__name__ in expr_class_names + +def is_stmt(node): + # type: (AstNode) -> bool + """Returns whether node is a statement node.""" + return node.__class__.__name__ in stmt_class_names + +def is_module(node): + # type: (AstNode) -> bool + """Returns whether node is a module node.""" + return node.__class__.__name__ == 'Module' + +def is_joined_str(node): + # type: (AstNode) -> bool + """Returns whether node is a JoinedStr node, used to represent f-strings.""" + # At the moment, nodes below JoinedStr have wrong line/col info, and trying to process them only + # leads to errors. + return node.__class__.__name__ == 'JoinedStr' + + +def is_starred(node): + # type: (AstNode) -> bool + """Returns whether node is a starred expression node.""" + return node.__class__.__name__ == 'Starred' + + +def is_slice(node): + # type: (AstNode) -> bool + """Returns whether node represents a slice, e.g. `1:2` in `x[1:2]`""" + # Before 3.9, a tuple containing a slice is an ExtSlice, + # but this was removed in https://bugs.python.org/issue34822 + return ( + node.__class__.__name__ in ('Slice', 'ExtSlice') + or ( + node.__class__.__name__ == 'Tuple' + and any(map(is_slice, cast(ast.Tuple, node).elts)) + ) + ) + + +def is_empty_astroid_slice(node): + # type: (AstNode) -> bool + return ( + node.__class__.__name__ == "Slice" + and not isinstance(node, ast.AST) + and node.lower is node.upper is node.step is None + ) + + +# Sentinel value used by visit_tree(). +_PREVISIT = object() + +def visit_tree(node, previsit, postvisit): + # type: (Module, Callable[[AstNode, Optional[Token]], Tuple[Optional[Token], Optional[Token]]], Optional[Callable[[AstNode, Optional[Token], Optional[Token]], None]]) -> None + """ + Scans the tree under the node depth-first using an explicit stack. It avoids implicit recursion + via the function call stack to avoid hitting 'maximum recursion depth exceeded' error. + + It calls ``previsit()`` and ``postvisit()`` as follows: + + * ``previsit(node, par_value)`` - should return ``(par_value, value)`` + ``par_value`` is as returned from ``previsit()`` of the parent. + + * ``postvisit(node, par_value, value)`` - should return ``value`` + ``par_value`` is as returned from ``previsit()`` of the parent, and ``value`` is as + returned from ``previsit()`` of this node itself. The return ``value`` is ignored except + the one for the root node, which is returned from the overall ``visit_tree()`` call. + + For the initial node, ``par_value`` is None. ``postvisit`` may be None. + """ + if not postvisit: + postvisit = lambda node, pvalue, value: None + + iter_children = iter_children_func(node) + done = set() + ret = None + stack = [(node, None, _PREVISIT)] # type: List[Tuple[AstNode, Optional[Token], Union[Optional[Token], object]]] + while stack: + current, par_value, value = stack.pop() + if value is _PREVISIT: + assert current not in done # protect againt infinite loop in case of a bad tree. + done.add(current) + + pvalue, post_value = previsit(current, par_value) + stack.append((current, par_value, post_value)) + + # Insert all children in reverse order (so that first child ends up on top of the stack). + ins = len(stack) + for n in iter_children(current): + stack.insert(ins, (n, pvalue, _PREVISIT)) + else: + ret = postvisit(current, par_value, cast(Optional[Token], value)) + return ret + + +def walk(node, include_joined_str=False): + # type: (AST, bool) -> Iterator[Union[Module, AstNode]] + """ + Recursively yield all descendant nodes in the tree starting at ``node`` (including ``node`` + itself), using depth-first pre-order traversal (yieling parents before their children). + + This is similar to ``ast.walk()``, but with a different order, and it works for both ``ast`` and + ``astroid`` trees. Also, as ``iter_children()``, it skips singleton nodes generated by ``ast``. + + By default, ``JoinedStr`` (f-string) nodes and their contents are skipped + because they previously couldn't be handled. Set ``include_joined_str`` to True to include them. + """ + iter_children = iter_children_func(node) + done = set() + stack = [node] + while stack: + current = stack.pop() + assert current not in done # protect againt infinite loop in case of a bad tree. + done.add(current) + + yield current + + # Insert all children in reverse order (so that first child ends up on top of the stack). + # This is faster than building a list and reversing it. + ins = len(stack) + for c in iter_children(current, include_joined_str): + stack.insert(ins, c) + + +def replace(text, replacements): + # type: (str, List[Tuple[int, int, str]]) -> str + """ + Replaces multiple slices of text with new values. This is a convenience method for making code + modifications of ranges e.g. as identified by ``ASTTokens.get_text_range(node)``. Replacements is + an iterable of ``(start, end, new_text)`` tuples. + + For example, ``replace("this is a test", [(0, 4, "X"), (8, 9, "THE")])`` produces + ``"X is THE test"``. + """ + p = 0 + parts = [] + for (start, end, new_text) in sorted(replacements): + parts.append(text[p:start]) + parts.append(new_text) + p = end + parts.append(text[p:]) + return ''.join(parts) + + +class NodeMethods(object): + """ + Helper to get `visit_{node_type}` methods given a node's class and cache the results. + """ + def __init__(self): + # type: () -> None + self._cache = {} # type: Dict[Union[ABCMeta, type], Callable[[AstNode, Token, Token], Tuple[Token, Token]]] + + def get(self, obj, cls): + # type: (Any, Union[ABCMeta, type]) -> Callable + """ + Using the lowercase name of the class as node_type, returns `obj.visit_{node_type}`, + or `obj.visit_default` if the type-specific method is not found. + """ + method = self._cache.get(cls) + if not method: + name = "visit_" + cls.__name__.lower() + method = getattr(obj, name, obj.visit_default) + self._cache[cls] = method + return method + + +if sys.version_info[0] == 2: + # Python 2 doesn't support non-ASCII identifiers, and making the real patched_generate_tokens support Python 2 + # means working with raw tuples instead of tokenize.TokenInfo namedtuples. + def patched_generate_tokens(original_tokens): + # type: (Iterable[TokenInfo]) -> Iterator[TokenInfo] + return iter(original_tokens) +else: + def patched_generate_tokens(original_tokens): + # type: (Iterable[TokenInfo]) -> Iterator[TokenInfo] + """ + Fixes tokens yielded by `tokenize.generate_tokens` to handle more non-ASCII characters in identifiers. + Workaround for https://github.com/python/cpython/issues/68382. + Should only be used when tokenizing a string that is known to be valid syntax, + because it assumes that error tokens are not actually errors. + Combines groups of consecutive NAME, NUMBER, and/or ERRORTOKEN tokens into a single NAME token. + """ + group = [] # type: List[tokenize.TokenInfo] + for tok in original_tokens: + if ( + tok.type in (tokenize.NAME, tokenize.ERRORTOKEN, tokenize.NUMBER) + # Only combine tokens if they have no whitespace in between + and (not group or group[-1].end == tok.start) + ): + group.append(tok) + else: + for combined_token in combine_tokens(group): + yield combined_token + group = [] + yield tok + for combined_token in combine_tokens(group): + yield combined_token + + def combine_tokens(group): + # type: (List[tokenize.TokenInfo]) -> List[tokenize.TokenInfo] + if not any(tok.type == tokenize.ERRORTOKEN for tok in group) or len({tok.line for tok in group}) != 1: + return group + return [ + tokenize.TokenInfo( + type=tokenize.NAME, + string="".join(t.string for t in group), + start=group[0].start, + end=group[-1].end, + line=group[0].line, + ) + ] + + +def last_stmt(node): + # type: (ast.AST) -> ast.AST + """ + If the given AST node contains multiple statements, return the last one. + Otherwise, just return the node. + """ + child_stmts = [ + child for child in iter_children_func(node)(node) + if is_stmt(child) or type(child).__name__ in ( + "excepthandler", + "ExceptHandler", + "match_case", + "MatchCase", + "TryExcept", + "TryFinally", + ) + ] + if child_stmts: + return last_stmt(child_stmts[-1]) + return node + + +if sys.version_info[:2] >= (3, 8): + from functools import lru_cache + + @lru_cache(maxsize=None) + def fstring_positions_work(): + # type: () -> bool + """ + The positions attached to nodes inside f-string FormattedValues have some bugs + that were fixed in Python 3.9.7 in https://github.com/python/cpython/pull/27729. + This checks for those bugs more concretely without relying on the Python version. + Specifically this checks: + - Values with a format spec or conversion + - Repeated (i.e. identical-looking) expressions + - f-strings implicitly concatenated over multiple lines. + - Multiline, triple-quoted f-strings. + """ + source = """( + f"a {b}{b} c {d!r} e {f:g} h {i:{j}} k {l:{m:n}}" + f"a {b}{b} c {d!r} e {f:g} h {i:{j}} k {l:{m:n}}" + f"{x + y + z} {x} {y} {z} {z} {z!a} {z:z}" + f''' + {s} {t} + {u} {v} + ''' + )""" + tree = ast.parse(source) + name_nodes = [node for node in ast.walk(tree) if isinstance(node, ast.Name)] + name_positions = [(node.lineno, node.col_offset) for node in name_nodes] + positions_are_unique = len(set(name_positions)) == len(name_positions) + correct_source_segments = all( + ast.get_source_segment(source, node) == node.id + for node in name_nodes + ) + return positions_are_unique and correct_source_segments + + def annotate_fstring_nodes(tree): + # type: (ast.AST) -> None + """ + Add a special attribute `_broken_positions` to nodes inside f-strings + if the lineno/col_offset cannot be trusted. + """ + if sys.version_info >= (3, 12): + # f-strings were weirdly implemented until https://peps.python.org/pep-0701/ + # In Python 3.12, inner nodes have sensible positions. + return + for joinedstr in walk(tree, include_joined_str=True): + if not isinstance(joinedstr, ast.JoinedStr): + continue + for part in joinedstr.values: + # The ast positions of the FormattedValues/Constant nodes span the full f-string, which is weird. + setattr(part, '_broken_positions', True) # use setattr for mypy + + if isinstance(part, ast.FormattedValue): + if not fstring_positions_work(): + for child in walk(part.value): + setattr(child, '_broken_positions', True) + + if part.format_spec: # this is another JoinedStr + # Again, the standard positions span the full f-string. + setattr(part.format_spec, '_broken_positions', True) + +else: + def fstring_positions_work(): + # type: () -> bool + return False + + def annotate_fstring_nodes(_tree): + # type: (ast.AST) -> None + pass diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/version.py b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/version.py new file mode 100644 index 000000000..54499df34 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/asttokens/version.py @@ -0,0 +1 @@ +__version__ = "2.4.1" diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/attr/__init__.py new file mode 100644 index 000000000..9226258a2 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/__init__.py @@ -0,0 +1,134 @@ +# SPDX-License-Identifier: MIT + +""" +Classes Without Boilerplate +""" + +from functools import partial +from typing import Callable + +from . import converters, exceptions, filters, setters, validators +from ._cmp import cmp_using +from ._compat import Protocol +from ._config import get_run_validators, set_run_validators +from ._funcs import asdict, assoc, astuple, evolve, has, resolve_types +from ._make import ( + NOTHING, + Attribute, + Factory, + attrib, + attrs, + fields, + fields_dict, + make_class, + validate, +) +from ._next_gen import define, field, frozen, mutable +from ._version_info import VersionInfo + + +s = attributes = attrs +ib = attr = attrib +dataclass = partial(attrs, auto_attribs=True) # happy Easter ;) + + +class AttrsInstance(Protocol): + pass + + +__all__ = [ + "Attribute", + "AttrsInstance", + "Factory", + "NOTHING", + "asdict", + "assoc", + "astuple", + "attr", + "attrib", + "attributes", + "attrs", + "cmp_using", + "converters", + "define", + "evolve", + "exceptions", + "field", + "fields", + "fields_dict", + "filters", + "frozen", + "get_run_validators", + "has", + "ib", + "make_class", + "mutable", + "resolve_types", + "s", + "set_run_validators", + "setters", + "validate", + "validators", +] + + +def _make_getattr(mod_name: str) -> Callable: + """ + Create a metadata proxy for packaging information that uses *mod_name* in + its warnings and errors. + """ + + def __getattr__(name: str) -> str: + dunder_to_metadata = { + "__title__": "Name", + "__copyright__": "", + "__version__": "version", + "__version_info__": "version", + "__description__": "summary", + "__uri__": "", + "__url__": "", + "__author__": "", + "__email__": "", + "__license__": "license", + } + if name not in dunder_to_metadata: + msg = f"module {mod_name} has no attribute {name}" + raise AttributeError(msg) + + import sys + import warnings + + if sys.version_info < (3, 8): + from importlib_metadata import metadata + else: + from importlib.metadata import metadata + + if name not in ("__version__", "__version_info__"): + warnings.warn( + f"Accessing {mod_name}.{name} is deprecated and will be " + "removed in a future release. Use importlib.metadata directly " + "to query for attrs's packaging metadata.", + DeprecationWarning, + stacklevel=2, + ) + + meta = metadata("attrs") + if name == "__license__": + return "MIT" + if name == "__copyright__": + return "Copyright (c) 2015 Hynek Schlawack" + if name in ("__uri__", "__url__"): + return meta["Project-URL"].split(" ", 1)[-1] + if name == "__version_info__": + return VersionInfo._from_version_string(meta["version"]) + if name == "__author__": + return meta["Author-email"].rsplit(" ", 1)[0] + if name == "__email__": + return meta["Author-email"].rsplit("<", 1)[1][:-1] + + return meta[dunder_to_metadata[name]] + + return __getattr__ + + +__getattr__ = _make_getattr(__name__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/__init__.pyi b/inbm/venv-3.11/lib/python3.11/site-packages/attr/__init__.pyi new file mode 100644 index 000000000..37a208732 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/__init__.pyi @@ -0,0 +1,555 @@ +import enum +import sys + +from typing import ( + Any, + Callable, + Dict, + Generic, + List, + Mapping, + Optional, + Protocol, + Sequence, + Tuple, + Type, + TypeVar, + Union, + overload, +) + +# `import X as X` is required to make these public +from . import converters as converters +from . import exceptions as exceptions +from . import filters as filters +from . import setters as setters +from . import validators as validators +from ._cmp import cmp_using as cmp_using +from ._typing_compat import AttrsInstance_ +from ._version_info import VersionInfo + +if sys.version_info >= (3, 10): + from typing import TypeGuard +else: + from typing_extensions import TypeGuard + +if sys.version_info >= (3, 11): + from typing import dataclass_transform +else: + from typing_extensions import dataclass_transform + +__version__: str +__version_info__: VersionInfo +__title__: str +__description__: str +__url__: str +__uri__: str +__author__: str +__email__: str +__license__: str +__copyright__: str + +_T = TypeVar("_T") +_C = TypeVar("_C", bound=type) + +_EqOrderType = Union[bool, Callable[[Any], Any]] +_ValidatorType = Callable[[Any, "Attribute[_T]", _T], Any] +_ConverterType = Callable[[Any], Any] +_FilterType = Callable[["Attribute[_T]", _T], bool] +_ReprType = Callable[[Any], str] +_ReprArgType = Union[bool, _ReprType] +_OnSetAttrType = Callable[[Any, "Attribute[Any]", Any], Any] +_OnSetAttrArgType = Union[ + _OnSetAttrType, List[_OnSetAttrType], setters._NoOpType +] +_FieldTransformer = Callable[ + [type, List["Attribute[Any]"]], List["Attribute[Any]"] +] +# FIXME: in reality, if multiple validators are passed they must be in a list +# or tuple, but those are invariant and so would prevent subtypes of +# _ValidatorType from working when passed in a list or tuple. +_ValidatorArgType = Union[_ValidatorType[_T], Sequence[_ValidatorType[_T]]] + +# We subclass this here to keep the protocol's qualified name clean. +class AttrsInstance(AttrsInstance_, Protocol): + pass + +_A = TypeVar("_A", bound=type[AttrsInstance]) + +class _Nothing(enum.Enum): + NOTHING = enum.auto() + +NOTHING = _Nothing.NOTHING + +# NOTE: Factory lies about its return type to make this possible: +# `x: List[int] # = Factory(list)` +# Work around mypy issue #4554 in the common case by using an overload. +if sys.version_info >= (3, 8): + from typing import Literal + @overload + def Factory(factory: Callable[[], _T]) -> _T: ... + @overload + def Factory( + factory: Callable[[Any], _T], + takes_self: Literal[True], + ) -> _T: ... + @overload + def Factory( + factory: Callable[[], _T], + takes_self: Literal[False], + ) -> _T: ... + +else: + @overload + def Factory(factory: Callable[[], _T]) -> _T: ... + @overload + def Factory( + factory: Union[Callable[[Any], _T], Callable[[], _T]], + takes_self: bool = ..., + ) -> _T: ... + +class Attribute(Generic[_T]): + name: str + default: Optional[_T] + validator: Optional[_ValidatorType[_T]] + repr: _ReprArgType + cmp: _EqOrderType + eq: _EqOrderType + order: _EqOrderType + hash: Optional[bool] + init: bool + converter: Optional[_ConverterType] + metadata: Dict[Any, Any] + type: Optional[Type[_T]] + kw_only: bool + on_setattr: _OnSetAttrType + alias: Optional[str] + + def evolve(self, **changes: Any) -> "Attribute[Any]": ... + +# NOTE: We had several choices for the annotation to use for type arg: +# 1) Type[_T] +# - Pros: Handles simple cases correctly +# - Cons: Might produce less informative errors in the case of conflicting +# TypeVars e.g. `attr.ib(default='bad', type=int)` +# 2) Callable[..., _T] +# - Pros: Better error messages than #1 for conflicting TypeVars +# - Cons: Terrible error messages for validator checks. +# e.g. attr.ib(type=int, validator=validate_str) +# -> error: Cannot infer function type argument +# 3) type (and do all of the work in the mypy plugin) +# - Pros: Simple here, and we could customize the plugin with our own errors. +# - Cons: Would need to write mypy plugin code to handle all the cases. +# We chose option #1. + +# `attr` lies about its return type to make the following possible: +# attr() -> Any +# attr(8) -> int +# attr(validator=) -> Whatever the callable expects. +# This makes this type of assignments possible: +# x: int = attr(8) +# +# This form catches explicit None or no default but with no other arguments +# returns Any. +@overload +def attrib( + default: None = ..., + validator: None = ..., + repr: _ReprArgType = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + type: None = ..., + converter: None = ..., + factory: None = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + alias: Optional[str] = ..., +) -> Any: ... + +# This form catches an explicit None or no default and infers the type from the +# other arguments. +@overload +def attrib( + default: None = ..., + validator: Optional[_ValidatorArgType[_T]] = ..., + repr: _ReprArgType = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + type: Optional[Type[_T]] = ..., + converter: Optional[_ConverterType] = ..., + factory: Optional[Callable[[], _T]] = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + alias: Optional[str] = ..., +) -> _T: ... + +# This form catches an explicit default argument. +@overload +def attrib( + default: _T, + validator: Optional[_ValidatorArgType[_T]] = ..., + repr: _ReprArgType = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + type: Optional[Type[_T]] = ..., + converter: Optional[_ConverterType] = ..., + factory: Optional[Callable[[], _T]] = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + alias: Optional[str] = ..., +) -> _T: ... + +# This form covers type=non-Type: e.g. forward references (str), Any +@overload +def attrib( + default: Optional[_T] = ..., + validator: Optional[_ValidatorArgType[_T]] = ..., + repr: _ReprArgType = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + type: object = ..., + converter: Optional[_ConverterType] = ..., + factory: Optional[Callable[[], _T]] = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + alias: Optional[str] = ..., +) -> Any: ... +@overload +def field( + *, + default: None = ..., + validator: None = ..., + repr: _ReprArgType = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + converter: None = ..., + factory: None = ..., + kw_only: bool = ..., + eq: Optional[bool] = ..., + order: Optional[bool] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + alias: Optional[str] = ..., + type: Optional[type] = ..., +) -> Any: ... + +# This form catches an explicit None or no default and infers the type from the +# other arguments. +@overload +def field( + *, + default: None = ..., + validator: Optional[_ValidatorArgType[_T]] = ..., + repr: _ReprArgType = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + converter: Optional[_ConverterType] = ..., + factory: Optional[Callable[[], _T]] = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + alias: Optional[str] = ..., + type: Optional[type] = ..., +) -> _T: ... + +# This form catches an explicit default argument. +@overload +def field( + *, + default: _T, + validator: Optional[_ValidatorArgType[_T]] = ..., + repr: _ReprArgType = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + converter: Optional[_ConverterType] = ..., + factory: Optional[Callable[[], _T]] = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + alias: Optional[str] = ..., + type: Optional[type] = ..., +) -> _T: ... + +# This form covers type=non-Type: e.g. forward references (str), Any +@overload +def field( + *, + default: Optional[_T] = ..., + validator: Optional[_ValidatorArgType[_T]] = ..., + repr: _ReprArgType = ..., + hash: Optional[bool] = ..., + init: bool = ..., + metadata: Optional[Mapping[Any, Any]] = ..., + converter: Optional[_ConverterType] = ..., + factory: Optional[Callable[[], _T]] = ..., + kw_only: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + alias: Optional[str] = ..., + type: Optional[type] = ..., +) -> Any: ... +@overload +@dataclass_transform(order_default=True, field_specifiers=(attrib, field)) +def attrs( + maybe_cls: _C, + these: Optional[Dict[str, Any]] = ..., + repr_ns: Optional[str] = ..., + repr: bool = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + auto_detect: bool = ..., + collect_by_mro: bool = ..., + getstate_setstate: Optional[bool] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + field_transformer: Optional[_FieldTransformer] = ..., + match_args: bool = ..., + unsafe_hash: Optional[bool] = ..., +) -> _C: ... +@overload +@dataclass_transform(order_default=True, field_specifiers=(attrib, field)) +def attrs( + maybe_cls: None = ..., + these: Optional[Dict[str, Any]] = ..., + repr_ns: Optional[str] = ..., + repr: bool = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + auto_detect: bool = ..., + collect_by_mro: bool = ..., + getstate_setstate: Optional[bool] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + field_transformer: Optional[_FieldTransformer] = ..., + match_args: bool = ..., + unsafe_hash: Optional[bool] = ..., +) -> Callable[[_C], _C]: ... +@overload +@dataclass_transform(field_specifiers=(attrib, field)) +def define( + maybe_cls: _C, + *, + these: Optional[Dict[str, Any]] = ..., + repr: bool = ..., + unsafe_hash: Optional[bool] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: Optional[bool] = ..., + order: Optional[bool] = ..., + auto_detect: bool = ..., + getstate_setstate: Optional[bool] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + field_transformer: Optional[_FieldTransformer] = ..., + match_args: bool = ..., +) -> _C: ... +@overload +@dataclass_transform(field_specifiers=(attrib, field)) +def define( + maybe_cls: None = ..., + *, + these: Optional[Dict[str, Any]] = ..., + repr: bool = ..., + unsafe_hash: Optional[bool] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: Optional[bool] = ..., + order: Optional[bool] = ..., + auto_detect: bool = ..., + getstate_setstate: Optional[bool] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + field_transformer: Optional[_FieldTransformer] = ..., + match_args: bool = ..., +) -> Callable[[_C], _C]: ... + +mutable = define + +@overload +@dataclass_transform(frozen_default=True, field_specifiers=(attrib, field)) +def frozen( + maybe_cls: _C, + *, + these: Optional[Dict[str, Any]] = ..., + repr: bool = ..., + unsafe_hash: Optional[bool] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: Optional[bool] = ..., + order: Optional[bool] = ..., + auto_detect: bool = ..., + getstate_setstate: Optional[bool] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + field_transformer: Optional[_FieldTransformer] = ..., + match_args: bool = ..., +) -> _C: ... +@overload +@dataclass_transform(frozen_default=True, field_specifiers=(attrib, field)) +def frozen( + maybe_cls: None = ..., + *, + these: Optional[Dict[str, Any]] = ..., + repr: bool = ..., + unsafe_hash: Optional[bool] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: Optional[bool] = ..., + order: Optional[bool] = ..., + auto_detect: bool = ..., + getstate_setstate: Optional[bool] = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + field_transformer: Optional[_FieldTransformer] = ..., + match_args: bool = ..., +) -> Callable[[_C], _C]: ... +def fields(cls: Type[AttrsInstance]) -> Any: ... +def fields_dict(cls: Type[AttrsInstance]) -> Dict[str, Attribute[Any]]: ... +def validate(inst: AttrsInstance) -> None: ... +def resolve_types( + cls: _A, + globalns: Optional[Dict[str, Any]] = ..., + localns: Optional[Dict[str, Any]] = ..., + attribs: Optional[List[Attribute[Any]]] = ..., + include_extras: bool = ..., +) -> _A: ... + +# TODO: add support for returning a proper attrs class from the mypy plugin +# we use Any instead of _CountingAttr so that e.g. `make_class('Foo', +# [attr.ib()])` is valid +def make_class( + name: str, + attrs: Union[List[str], Tuple[str, ...], Dict[str, Any]], + bases: Tuple[type, ...] = ..., + class_body: Optional[Dict[str, Any]] = ..., + repr_ns: Optional[str] = ..., + repr: bool = ..., + cmp: Optional[_EqOrderType] = ..., + hash: Optional[bool] = ..., + init: bool = ..., + slots: bool = ..., + frozen: bool = ..., + weakref_slot: bool = ..., + str: bool = ..., + auto_attribs: bool = ..., + kw_only: bool = ..., + cache_hash: bool = ..., + auto_exc: bool = ..., + eq: Optional[_EqOrderType] = ..., + order: Optional[_EqOrderType] = ..., + collect_by_mro: bool = ..., + on_setattr: Optional[_OnSetAttrArgType] = ..., + field_transformer: Optional[_FieldTransformer] = ..., +) -> type: ... + +# _funcs -- + +# TODO: add support for returning TypedDict from the mypy plugin +# FIXME: asdict/astuple do not honor their factory args. Waiting on one of +# these: +# https://github.com/python/mypy/issues/4236 +# https://github.com/python/typing/issues/253 +# XXX: remember to fix attrs.asdict/astuple too! +def asdict( + inst: AttrsInstance, + recurse: bool = ..., + filter: Optional[_FilterType[Any]] = ..., + dict_factory: Type[Mapping[Any, Any]] = ..., + retain_collection_types: bool = ..., + value_serializer: Optional[ + Callable[[type, Attribute[Any], Any], Any] + ] = ..., + tuple_keys: Optional[bool] = ..., +) -> Dict[str, Any]: ... + +# TODO: add support for returning NamedTuple from the mypy plugin +def astuple( + inst: AttrsInstance, + recurse: bool = ..., + filter: Optional[_FilterType[Any]] = ..., + tuple_factory: Type[Sequence[Any]] = ..., + retain_collection_types: bool = ..., +) -> Tuple[Any, ...]: ... +def has(cls: type) -> TypeGuard[Type[AttrsInstance]]: ... +def assoc(inst: _T, **changes: Any) -> _T: ... +def evolve(inst: _T, **changes: Any) -> _T: ... + +# _config -- + +def set_run_validators(run: bool) -> None: ... +def get_run_validators() -> bool: ... + +# aliases -- + +s = attributes = attrs +ib = attr = attrib +dataclass = attrs # Technically, partial(attrs, auto_attribs=True) ;) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/_cmp.py b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_cmp.py new file mode 100644 index 000000000..a4a35e08f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_cmp.py @@ -0,0 +1,150 @@ +# SPDX-License-Identifier: MIT + + +import functools +import types + +from ._make import _make_ne + + +_operation_names = {"eq": "==", "lt": "<", "le": "<=", "gt": ">", "ge": ">="} + + +def cmp_using( + eq=None, + lt=None, + le=None, + gt=None, + ge=None, + require_same_type=True, + class_name="Comparable", +): + """ + Create a class that can be passed into `attrs.field`'s ``eq``, ``order``, + and ``cmp`` arguments to customize field comparison. + + The resulting class will have a full set of ordering methods if at least + one of ``{lt, le, gt, ge}`` and ``eq`` are provided. + + :param Optional[callable] eq: `callable` used to evaluate equality of two + objects. + :param Optional[callable] lt: `callable` used to evaluate whether one + object is less than another object. + :param Optional[callable] le: `callable` used to evaluate whether one + object is less than or equal to another object. + :param Optional[callable] gt: `callable` used to evaluate whether one + object is greater than another object. + :param Optional[callable] ge: `callable` used to evaluate whether one + object is greater than or equal to another object. + + :param bool require_same_type: When `True`, equality and ordering methods + will return `NotImplemented` if objects are not of the same type. + + :param Optional[str] class_name: Name of class. Defaults to 'Comparable'. + + See `comparison` for more details. + + .. versionadded:: 21.1.0 + """ + + body = { + "__slots__": ["value"], + "__init__": _make_init(), + "_requirements": [], + "_is_comparable_to": _is_comparable_to, + } + + # Add operations. + num_order_functions = 0 + has_eq_function = False + + if eq is not None: + has_eq_function = True + body["__eq__"] = _make_operator("eq", eq) + body["__ne__"] = _make_ne() + + if lt is not None: + num_order_functions += 1 + body["__lt__"] = _make_operator("lt", lt) + + if le is not None: + num_order_functions += 1 + body["__le__"] = _make_operator("le", le) + + if gt is not None: + num_order_functions += 1 + body["__gt__"] = _make_operator("gt", gt) + + if ge is not None: + num_order_functions += 1 + body["__ge__"] = _make_operator("ge", ge) + + type_ = types.new_class( + class_name, (object,), {}, lambda ns: ns.update(body) + ) + + # Add same type requirement. + if require_same_type: + type_._requirements.append(_check_same_type) + + # Add total ordering if at least one operation was defined. + if 0 < num_order_functions < 4: + if not has_eq_function: + # functools.total_ordering requires __eq__ to be defined, + # so raise early error here to keep a nice stack. + msg = "eq must be define is order to complete ordering from lt, le, gt, ge." + raise ValueError(msg) + type_ = functools.total_ordering(type_) + + return type_ + + +def _make_init(): + """ + Create __init__ method. + """ + + def __init__(self, value): + """ + Initialize object with *value*. + """ + self.value = value + + return __init__ + + +def _make_operator(name, func): + """ + Create operator method. + """ + + def method(self, other): + if not self._is_comparable_to(other): + return NotImplemented + + result = func(self.value, other.value) + if result is NotImplemented: + return NotImplemented + + return result + + method.__name__ = f"__{name}__" + method.__doc__ = ( + f"Return a {_operation_names[name]} b. Computed by attrs." + ) + + return method + + +def _is_comparable_to(self, other): + """ + Check whether `other` is comparable to `self`. + """ + return all(func(self, other) for func in self._requirements) + + +def _check_same_type(self, other): + """ + Return True if *self* and *other* are of the same type, False otherwise. + """ + return other.value.__class__ is self.value.__class__ diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/_cmp.pyi b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_cmp.pyi new file mode 100644 index 000000000..f3dcdc1a7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_cmp.pyi @@ -0,0 +1,13 @@ +from typing import Any, Callable, Optional, Type + +_CompareWithType = Callable[[Any, Any], bool] + +def cmp_using( + eq: Optional[_CompareWithType] = ..., + lt: Optional[_CompareWithType] = ..., + le: Optional[_CompareWithType] = ..., + gt: Optional[_CompareWithType] = ..., + ge: Optional[_CompareWithType] = ..., + require_same_type: bool = ..., + class_name: str = ..., +) -> Type: ... diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/_compat.py b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_compat.py new file mode 100644 index 000000000..46b05ca45 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_compat.py @@ -0,0 +1,87 @@ +# SPDX-License-Identifier: MIT + +import inspect +import platform +import sys +import threading + +from collections.abc import Mapping, Sequence # noqa: F401 +from typing import _GenericAlias + + +PYPY = platform.python_implementation() == "PyPy" +PY_3_8_PLUS = sys.version_info[:2] >= (3, 8) +PY_3_9_PLUS = sys.version_info[:2] >= (3, 9) +PY310 = sys.version_info[:2] >= (3, 10) +PY_3_12_PLUS = sys.version_info[:2] >= (3, 12) + + +if sys.version_info < (3, 8): + try: + from typing_extensions import Protocol + except ImportError: # pragma: no cover + Protocol = object +else: + from typing import Protocol # noqa: F401 + + +class _AnnotationExtractor: + """ + Extract type annotations from a callable, returning None whenever there + is none. + """ + + __slots__ = ["sig"] + + def __init__(self, callable): + try: + self.sig = inspect.signature(callable) + except (ValueError, TypeError): # inspect failed + self.sig = None + + def get_first_param_type(self): + """ + Return the type annotation of the first argument if it's not empty. + """ + if not self.sig: + return None + + params = list(self.sig.parameters.values()) + if params and params[0].annotation is not inspect.Parameter.empty: + return params[0].annotation + + return None + + def get_return_type(self): + """ + Return the return type if it's not empty. + """ + if ( + self.sig + and self.sig.return_annotation is not inspect.Signature.empty + ): + return self.sig.return_annotation + + return None + + +# Thread-local global to track attrs instances which are already being repr'd. +# This is needed because there is no other (thread-safe) way to pass info +# about the instances that are already being repr'd through the call stack +# in order to ensure we don't perform infinite recursion. +# +# For instance, if an instance contains a dict which contains that instance, +# we need to know that we're already repr'ing the outside instance from within +# the dict's repr() call. +# +# This lives here rather than in _make.py so that the functions in _make.py +# don't have a direct reference to the thread-local in their globals dict. +# If they have such a reference, it breaks cloudpickle. +repr_context = threading.local() + + +def get_generic_base(cl): + """If this is a generic class (A[str]), return the generic base for it.""" + if cl.__class__ is _GenericAlias: + return cl.__origin__ + return None diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/_config.py b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_config.py new file mode 100644 index 000000000..9c245b146 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_config.py @@ -0,0 +1,31 @@ +# SPDX-License-Identifier: MIT + +__all__ = ["set_run_validators", "get_run_validators"] + +_run_validators = True + + +def set_run_validators(run): + """ + Set whether or not validators are run. By default, they are run. + + .. deprecated:: 21.3.0 It will not be removed, but it also will not be + moved to new ``attrs`` namespace. Use `attrs.validators.set_disabled()` + instead. + """ + if not isinstance(run, bool): + msg = "'run' must be bool." + raise TypeError(msg) + global _run_validators + _run_validators = run + + +def get_run_validators(): + """ + Return whether or not validators are run. + + .. deprecated:: 21.3.0 It will not be removed, but it also will not be + moved to new ``attrs`` namespace. Use `attrs.validators.get_disabled()` + instead. + """ + return _run_validators diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/_funcs.py b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_funcs.py new file mode 100644 index 000000000..a888991d9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_funcs.py @@ -0,0 +1,483 @@ +# SPDX-License-Identifier: MIT + + +import copy + +from ._compat import PY_3_9_PLUS, get_generic_base +from ._make import NOTHING, _obj_setattr, fields +from .exceptions import AttrsAttributeNotFoundError + + +def asdict( + inst, + recurse=True, + filter=None, + dict_factory=dict, + retain_collection_types=False, + value_serializer=None, +): + """ + Return the *attrs* attribute values of *inst* as a dict. + + Optionally recurse into other *attrs*-decorated classes. + + :param inst: Instance of an *attrs*-decorated class. + :param bool recurse: Recurse into classes that are also + *attrs*-decorated. + :param callable filter: A callable whose return code determines whether an + attribute or element is included (``True``) or dropped (``False``). Is + called with the `attrs.Attribute` as the first argument and the + value as the second argument. + :param callable dict_factory: A callable to produce dictionaries from. For + example, to produce ordered dictionaries instead of normal Python + dictionaries, pass in ``collections.OrderedDict``. + :param bool retain_collection_types: Do not convert to ``list`` when + encountering an attribute whose type is ``tuple`` or ``set``. Only + meaningful if ``recurse`` is ``True``. + :param Optional[callable] value_serializer: A hook that is called for every + attribute or dict key/value. It receives the current instance, field + and value and must return the (updated) value. The hook is run *after* + the optional *filter* has been applied. + + :rtype: return type of *dict_factory* + + :raise attrs.exceptions.NotAnAttrsClassError: If *cls* is not an *attrs* + class. + + .. versionadded:: 16.0.0 *dict_factory* + .. versionadded:: 16.1.0 *retain_collection_types* + .. versionadded:: 20.3.0 *value_serializer* + .. versionadded:: 21.3.0 If a dict has a collection for a key, it is + serialized as a tuple. + """ + attrs = fields(inst.__class__) + rv = dict_factory() + for a in attrs: + v = getattr(inst, a.name) + if filter is not None and not filter(a, v): + continue + + if value_serializer is not None: + v = value_serializer(inst, a, v) + + if recurse is True: + if has(v.__class__): + rv[a.name] = asdict( + v, + recurse=True, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + elif isinstance(v, (tuple, list, set, frozenset)): + cf = v.__class__ if retain_collection_types is True else list + items = [ + _asdict_anything( + i, + is_key=False, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + for i in v + ] + try: + rv[a.name] = cf(items) + except TypeError: + if not issubclass(cf, tuple): + raise + # Workaround for TypeError: cf.__new__() missing 1 required + # positional argument (which appears, for a namedturle) + rv[a.name] = cf(*items) + elif isinstance(v, dict): + df = dict_factory + rv[a.name] = df( + ( + _asdict_anything( + kk, + is_key=True, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + _asdict_anything( + vv, + is_key=False, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + ) + for kk, vv in v.items() + ) + else: + rv[a.name] = v + else: + rv[a.name] = v + return rv + + +def _asdict_anything( + val, + is_key, + filter, + dict_factory, + retain_collection_types, + value_serializer, +): + """ + ``asdict`` only works on attrs instances, this works on anything. + """ + if getattr(val.__class__, "__attrs_attrs__", None) is not None: + # Attrs class. + rv = asdict( + val, + recurse=True, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + elif isinstance(val, (tuple, list, set, frozenset)): + if retain_collection_types is True: + cf = val.__class__ + elif is_key: + cf = tuple + else: + cf = list + + rv = cf( + [ + _asdict_anything( + i, + is_key=False, + filter=filter, + dict_factory=dict_factory, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ) + for i in val + ] + ) + elif isinstance(val, dict): + df = dict_factory + rv = df( + ( + _asdict_anything( + kk, + is_key=True, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + _asdict_anything( + vv, + is_key=False, + filter=filter, + dict_factory=df, + retain_collection_types=retain_collection_types, + value_serializer=value_serializer, + ), + ) + for kk, vv in val.items() + ) + else: + rv = val + if value_serializer is not None: + rv = value_serializer(None, None, rv) + + return rv + + +def astuple( + inst, + recurse=True, + filter=None, + tuple_factory=tuple, + retain_collection_types=False, +): + """ + Return the *attrs* attribute values of *inst* as a tuple. + + Optionally recurse into other *attrs*-decorated classes. + + :param inst: Instance of an *attrs*-decorated class. + :param bool recurse: Recurse into classes that are also + *attrs*-decorated. + :param callable filter: A callable whose return code determines whether an + attribute or element is included (``True``) or dropped (``False``). Is + called with the `attrs.Attribute` as the first argument and the + value as the second argument. + :param callable tuple_factory: A callable to produce tuples from. For + example, to produce lists instead of tuples. + :param bool retain_collection_types: Do not convert to ``list`` + or ``dict`` when encountering an attribute which type is + ``tuple``, ``dict`` or ``set``. Only meaningful if ``recurse`` is + ``True``. + + :rtype: return type of *tuple_factory* + + :raise attrs.exceptions.NotAnAttrsClassError: If *cls* is not an *attrs* + class. + + .. versionadded:: 16.2.0 + """ + attrs = fields(inst.__class__) + rv = [] + retain = retain_collection_types # Very long. :/ + for a in attrs: + v = getattr(inst, a.name) + if filter is not None and not filter(a, v): + continue + if recurse is True: + if has(v.__class__): + rv.append( + astuple( + v, + recurse=True, + filter=filter, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + ) + elif isinstance(v, (tuple, list, set, frozenset)): + cf = v.__class__ if retain is True else list + items = [ + astuple( + j, + recurse=True, + filter=filter, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + if has(j.__class__) + else j + for j in v + ] + try: + rv.append(cf(items)) + except TypeError: + if not issubclass(cf, tuple): + raise + # Workaround for TypeError: cf.__new__() missing 1 required + # positional argument (which appears, for a namedturle) + rv.append(cf(*items)) + elif isinstance(v, dict): + df = v.__class__ if retain is True else dict + rv.append( + df( + ( + astuple( + kk, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + if has(kk.__class__) + else kk, + astuple( + vv, + tuple_factory=tuple_factory, + retain_collection_types=retain, + ) + if has(vv.__class__) + else vv, + ) + for kk, vv in v.items() + ) + ) + else: + rv.append(v) + else: + rv.append(v) + + return rv if tuple_factory is list else tuple_factory(rv) + + +def has(cls): + """ + Check whether *cls* is a class with *attrs* attributes. + + :param type cls: Class to introspect. + :raise TypeError: If *cls* is not a class. + + :rtype: bool + """ + attrs = getattr(cls, "__attrs_attrs__", None) + if attrs is not None: + return True + + # No attrs, maybe it's a specialized generic (A[str])? + generic_base = get_generic_base(cls) + if generic_base is not None: + generic_attrs = getattr(generic_base, "__attrs_attrs__", None) + if generic_attrs is not None: + # Stick it on here for speed next time. + cls.__attrs_attrs__ = generic_attrs + return generic_attrs is not None + return False + + +def assoc(inst, **changes): + """ + Copy *inst* and apply *changes*. + + This is different from `evolve` that applies the changes to the arguments + that create the new instance. + + `evolve`'s behavior is preferable, but there are `edge cases`_ where it + doesn't work. Therefore `assoc` is deprecated, but will not be removed. + + .. _`edge cases`: https://github.com/python-attrs/attrs/issues/251 + + :param inst: Instance of a class with *attrs* attributes. + :param changes: Keyword changes in the new copy. + + :return: A copy of inst with *changes* incorporated. + + :raise attrs.exceptions.AttrsAttributeNotFoundError: If *attr_name* + couldn't be found on *cls*. + :raise attrs.exceptions.NotAnAttrsClassError: If *cls* is not an *attrs* + class. + + .. deprecated:: 17.1.0 + Use `attrs.evolve` instead if you can. + This function will not be removed du to the slightly different approach + compared to `attrs.evolve`. + """ + new = copy.copy(inst) + attrs = fields(inst.__class__) + for k, v in changes.items(): + a = getattr(attrs, k, NOTHING) + if a is NOTHING: + msg = f"{k} is not an attrs attribute on {new.__class__}." + raise AttrsAttributeNotFoundError(msg) + _obj_setattr(new, k, v) + return new + + +def evolve(*args, **changes): + """ + Create a new instance, based on the first positional argument with + *changes* applied. + + :param inst: Instance of a class with *attrs* attributes. + :param changes: Keyword changes in the new copy. + + :return: A copy of inst with *changes* incorporated. + + :raise TypeError: If *attr_name* couldn't be found in the class + ``__init__``. + :raise attrs.exceptions.NotAnAttrsClassError: If *cls* is not an *attrs* + class. + + .. versionadded:: 17.1.0 + .. deprecated:: 23.1.0 + It is now deprecated to pass the instance using the keyword argument + *inst*. It will raise a warning until at least April 2024, after which + it will become an error. Always pass the instance as a positional + argument. + """ + # Try to get instance by positional argument first. + # Use changes otherwise and warn it'll break. + if args: + try: + (inst,) = args + except ValueError: + msg = f"evolve() takes 1 positional argument, but {len(args)} were given" + raise TypeError(msg) from None + else: + try: + inst = changes.pop("inst") + except KeyError: + msg = "evolve() missing 1 required positional argument: 'inst'" + raise TypeError(msg) from None + + import warnings + + warnings.warn( + "Passing the instance per keyword argument is deprecated and " + "will stop working in, or after, April 2024.", + DeprecationWarning, + stacklevel=2, + ) + + cls = inst.__class__ + attrs = fields(cls) + for a in attrs: + if not a.init: + continue + attr_name = a.name # To deal with private attributes. + init_name = a.alias + if init_name not in changes: + changes[init_name] = getattr(inst, attr_name) + + return cls(**changes) + + +def resolve_types( + cls, globalns=None, localns=None, attribs=None, include_extras=True +): + """ + Resolve any strings and forward annotations in type annotations. + + This is only required if you need concrete types in `Attribute`'s *type* + field. In other words, you don't need to resolve your types if you only + use them for static type checking. + + With no arguments, names will be looked up in the module in which the class + was created. If this is not what you want, e.g. if the name only exists + inside a method, you may pass *globalns* or *localns* to specify other + dictionaries in which to look up these names. See the docs of + `typing.get_type_hints` for more details. + + :param type cls: Class to resolve. + :param Optional[dict] globalns: Dictionary containing global variables. + :param Optional[dict] localns: Dictionary containing local variables. + :param Optional[list] attribs: List of attribs for the given class. + This is necessary when calling from inside a ``field_transformer`` + since *cls* is not an *attrs* class yet. + :param bool include_extras: Resolve more accurately, if possible. + Pass ``include_extras`` to ``typing.get_hints``, if supported by the + typing module. On supported Python versions (3.9+), this resolves the + types more accurately. + + :raise TypeError: If *cls* is not a class. + :raise attrs.exceptions.NotAnAttrsClassError: If *cls* is not an *attrs* + class and you didn't pass any attribs. + :raise NameError: If types cannot be resolved because of missing variables. + + :returns: *cls* so you can use this function also as a class decorator. + Please note that you have to apply it **after** `attrs.define`. That + means the decorator has to come in the line **before** `attrs.define`. + + .. versionadded:: 20.1.0 + .. versionadded:: 21.1.0 *attribs* + .. versionadded:: 23.1.0 *include_extras* + + """ + # Since calling get_type_hints is expensive we cache whether we've + # done it already. + if getattr(cls, "__attrs_types_resolved__", None) != cls: + import typing + + kwargs = {"globalns": globalns, "localns": localns} + + if PY_3_9_PLUS: + kwargs["include_extras"] = include_extras + + hints = typing.get_type_hints(cls, **kwargs) + for field in fields(cls) if attribs is None else attribs: + if field.name in hints: + # Since fields have been frozen we must work around it. + _obj_setattr(field, "type", hints[field.name]) + # We store the class we resolved so that subclasses know they haven't + # been resolved. + cls.__attrs_types_resolved__ = cls + + # Return the class so you can use it as a decorator too. + return cls diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/_make.py b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_make.py new file mode 100644 index 000000000..10b4eca77 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_make.py @@ -0,0 +1,3119 @@ +# SPDX-License-Identifier: MIT + +import contextlib +import copy +import enum +import functools +import inspect +import itertools +import linecache +import sys +import types +import typing + +from operator import itemgetter + +# We need to import _compat itself in addition to the _compat members to avoid +# having the thread-local in the globals here. +from . import _compat, _config, setters +from ._compat import ( + PY310, + PY_3_8_PLUS, + _AnnotationExtractor, + get_generic_base, +) +from .exceptions import ( + DefaultAlreadySetError, + FrozenInstanceError, + NotAnAttrsClassError, + UnannotatedAttributeError, +) + + +# This is used at least twice, so cache it here. +_obj_setattr = object.__setattr__ +_init_converter_pat = "__attr_converter_%s" +_init_factory_pat = "__attr_factory_%s" +_classvar_prefixes = ( + "typing.ClassVar", + "t.ClassVar", + "ClassVar", + "typing_extensions.ClassVar", +) +# we don't use a double-underscore prefix because that triggers +# name mangling when trying to create a slot for the field +# (when slots=True) +_hash_cache_field = "_attrs_cached_hash" + +_empty_metadata_singleton = types.MappingProxyType({}) + +# Unique object for unequivocal getattr() defaults. +_sentinel = object() + +_ng_default_on_setattr = setters.pipe(setters.convert, setters.validate) + + +class _Nothing(enum.Enum): + """ + Sentinel to indicate the lack of a value when ``None`` is ambiguous. + + If extending attrs, you can use ``typing.Literal[NOTHING]`` to show + that a value may be ``NOTHING``. + + .. versionchanged:: 21.1.0 ``bool(NOTHING)`` is now False. + .. versionchanged:: 22.2.0 ``NOTHING`` is now an ``enum.Enum`` variant. + """ + + NOTHING = enum.auto() + + def __repr__(self): + return "NOTHING" + + def __bool__(self): + return False + + +NOTHING = _Nothing.NOTHING +""" +Sentinel to indicate the lack of a value when ``None`` is ambiguous. +""" + + +class _CacheHashWrapper(int): + """ + An integer subclass that pickles / copies as None + + This is used for non-slots classes with ``cache_hash=True``, to avoid + serializing a potentially (even likely) invalid hash value. Since ``None`` + is the default value for uncalculated hashes, whenever this is copied, + the copy's value for the hash should automatically reset. + + See GH #613 for more details. + """ + + def __reduce__(self, _none_constructor=type(None), _args=()): # noqa: B008 + return _none_constructor, _args + + +def attrib( + default=NOTHING, + validator=None, + repr=True, + cmp=None, + hash=None, + init=True, + metadata=None, + type=None, + converter=None, + factory=None, + kw_only=False, + eq=None, + order=None, + on_setattr=None, + alias=None, +): + """ + Create a new attribute on a class. + + .. warning:: + + Does *not* do anything unless the class is also decorated with `attr.s` + / `attrs.define` / and so on! + + Please consider using `attrs.field` in new code (``attr.ib`` will *never* + go away, though). + + :param default: A value that is used if an *attrs*-generated ``__init__`` + is used and no value is passed while instantiating or the attribute is + excluded using ``init=False``. + + If the value is an instance of `attrs.Factory`, its callable will be + used to construct a new value (useful for mutable data types like lists + or dicts). + + If a default is not set (or set manually to `attrs.NOTHING`), a value + *must* be supplied when instantiating; otherwise a `TypeError` will be + raised. + + The default can also be set using decorator notation as shown below. + + .. seealso:: `defaults` + + :param callable factory: Syntactic sugar for + ``default=attr.Factory(factory)``. + + :param validator: `callable` that is called by *attrs*-generated + ``__init__`` methods after the instance has been initialized. They + receive the initialized instance, the :func:`~attrs.Attribute`, and the + passed value. + + The return value is *not* inspected so the validator has to throw an + exception itself. + + If a `list` is passed, its items are treated as validators and must all + pass. + + Validators can be globally disabled and re-enabled using + `attrs.validators.get_disabled` / `attrs.validators.set_disabled`. + + The validator can also be set using decorator notation as shown below. + + .. seealso:: :ref:`validators` + + :type validator: `callable` or a `list` of `callable`\\ s. + + :param repr: Include this attribute in the generated ``__repr__`` method. + If ``True``, include the attribute; if ``False``, omit it. By default, + the built-in ``repr()`` function is used. To override how the attribute + value is formatted, pass a ``callable`` that takes a single value and + returns a string. Note that the resulting string is used as-is, i.e. it + will be used directly *instead* of calling ``repr()`` (the default). + :type repr: a `bool` or a `callable` to use a custom function. + + :param eq: If ``True`` (default), include this attribute in the generated + ``__eq__`` and ``__ne__`` methods that check two instances for + equality. To override how the attribute value is compared, pass a + ``callable`` that takes a single value and returns the value to be + compared. + + .. seealso:: `comparison` + :type eq: a `bool` or a `callable`. + + :param order: If ``True`` (default), include this attributes in the + generated ``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods. To + override how the attribute value is ordered, pass a ``callable`` that + takes a single value and returns the value to be ordered. + + .. seealso:: `comparison` + :type order: a `bool` or a `callable`. + + :param cmp: Setting *cmp* is equivalent to setting *eq* and *order* to the + same value. Must not be mixed with *eq* or *order*. + + .. seealso:: `comparison` + :type cmp: a `bool` or a `callable`. + + :param bool | None hash: Include this attribute in the generated + ``__hash__`` method. If ``None`` (default), mirror *eq*'s value. This + is the correct behavior according the Python spec. Setting this value + to anything else than ``None`` is *discouraged*. + + .. seealso:: `hashing` + :param bool init: Include this attribute in the generated ``__init__`` + method. It is possible to set this to ``False`` and set a default + value. In that case this attributed is unconditionally initialized + with the specified default value or factory. + + .. seealso:: `init` + :param callable converter: `callable` that is called by *attrs*-generated + ``__init__`` methods to convert attribute's value to the desired + format. It is given the passed-in value, and the returned value will + be used as the new value of the attribute. The value is converted + before being passed to the validator, if any. + + .. seealso:: :ref:`converters` + :param dict | None metadata: An arbitrary mapping, to be used by + third-party components. See `extending-metadata`. + + :param type: The type of the attribute. Nowadays, the preferred method to + specify the type is using a variable annotation (see :pep:`526`). This + argument is provided for backward compatibility. Regardless of the + approach used, the type will be stored on ``Attribute.type``. + + Please note that *attrs* doesn't do anything with this metadata by + itself. You can use it as part of your own code or for `static type + checking `. + :param bool kw_only: Make this attribute keyword-only in the generated + ``__init__`` (if ``init`` is ``False``, this parameter is ignored). + :param on_setattr: Allows to overwrite the *on_setattr* setting from + `attr.s`. If left `None`, the *on_setattr* value from `attr.s` is used. + Set to `attrs.setters.NO_OP` to run **no** `setattr` hooks for this + attribute -- regardless of the setting in `attr.s`. + :type on_setattr: `callable`, or a list of callables, or `None`, or + `attrs.setters.NO_OP` + :param str | None alias: Override this attribute's parameter name in the + generated ``__init__`` method. If left `None`, default to ``name`` + stripped of leading underscores. See `private-attributes`. + + .. versionadded:: 15.2.0 *convert* + .. versionadded:: 16.3.0 *metadata* + .. versionchanged:: 17.1.0 *validator* can be a ``list`` now. + .. versionchanged:: 17.1.0 + *hash* is ``None`` and therefore mirrors *eq* by default. + .. versionadded:: 17.3.0 *type* + .. deprecated:: 17.4.0 *convert* + .. versionadded:: 17.4.0 *converter* as a replacement for the deprecated + *convert* to achieve consistency with other noun-based arguments. + .. versionadded:: 18.1.0 + ``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``. + .. versionadded:: 18.2.0 *kw_only* + .. versionchanged:: 19.2.0 *convert* keyword argument removed. + .. versionchanged:: 19.2.0 *repr* also accepts a custom callable. + .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. + .. versionadded:: 19.2.0 *eq* and *order* + .. versionadded:: 20.1.0 *on_setattr* + .. versionchanged:: 20.3.0 *kw_only* backported to Python 2 + .. versionchanged:: 21.1.0 + *eq*, *order*, and *cmp* also accept a custom callable + .. versionchanged:: 21.1.0 *cmp* undeprecated + .. versionadded:: 22.2.0 *alias* + """ + eq, eq_key, order, order_key = _determine_attrib_eq_order( + cmp, eq, order, True + ) + + if hash is not None and hash is not True and hash is not False: + msg = "Invalid value for hash. Must be True, False, or None." + raise TypeError(msg) + + if factory is not None: + if default is not NOTHING: + msg = ( + "The `default` and `factory` arguments are mutually exclusive." + ) + raise ValueError(msg) + if not callable(factory): + msg = "The `factory` argument must be a callable." + raise ValueError(msg) + default = Factory(factory) + + if metadata is None: + metadata = {} + + # Apply syntactic sugar by auto-wrapping. + if isinstance(on_setattr, (list, tuple)): + on_setattr = setters.pipe(*on_setattr) + + if validator and isinstance(validator, (list, tuple)): + validator = and_(*validator) + + if converter and isinstance(converter, (list, tuple)): + converter = pipe(*converter) + + return _CountingAttr( + default=default, + validator=validator, + repr=repr, + cmp=None, + hash=hash, + init=init, + converter=converter, + metadata=metadata, + type=type, + kw_only=kw_only, + eq=eq, + eq_key=eq_key, + order=order, + order_key=order_key, + on_setattr=on_setattr, + alias=alias, + ) + + +def _compile_and_eval(script, globs, locs=None, filename=""): + """ + "Exec" the script with the given global (globs) and local (locs) variables. + """ + bytecode = compile(script, filename, "exec") + eval(bytecode, globs, locs) + + +def _make_method(name, script, filename, globs): + """ + Create the method with the script given and return the method object. + """ + locs = {} + + # In order of debuggers like PDB being able to step through the code, + # we add a fake linecache entry. + count = 1 + base_filename = filename + while True: + linecache_tuple = ( + len(script), + None, + script.splitlines(True), + filename, + ) + old_val = linecache.cache.setdefault(filename, linecache_tuple) + if old_val == linecache_tuple: + break + + filename = f"{base_filename[:-1]}-{count}>" + count += 1 + + _compile_and_eval(script, globs, locs, filename) + + return locs[name] + + +def _make_attr_tuple_class(cls_name, attr_names): + """ + Create a tuple subclass to hold `Attribute`s for an `attrs` class. + + The subclass is a bare tuple with properties for names. + + class MyClassAttributes(tuple): + __slots__ = () + x = property(itemgetter(0)) + """ + attr_class_name = f"{cls_name}Attributes" + attr_class_template = [ + f"class {attr_class_name}(tuple):", + " __slots__ = ()", + ] + if attr_names: + for i, attr_name in enumerate(attr_names): + attr_class_template.append( + f" {attr_name} = _attrs_property(_attrs_itemgetter({i}))" + ) + else: + attr_class_template.append(" pass") + globs = {"_attrs_itemgetter": itemgetter, "_attrs_property": property} + _compile_and_eval("\n".join(attr_class_template), globs) + return globs[attr_class_name] + + +# Tuple class for extracted attributes from a class definition. +# `base_attrs` is a subset of `attrs`. +_Attributes = _make_attr_tuple_class( + "_Attributes", + [ + # all attributes to build dunder methods for + "attrs", + # attributes that have been inherited + "base_attrs", + # map inherited attributes to their originating classes + "base_attrs_map", + ], +) + + +def _is_class_var(annot): + """ + Check whether *annot* is a typing.ClassVar. + + The string comparison hack is used to avoid evaluating all string + annotations which would put attrs-based classes at a performance + disadvantage compared to plain old classes. + """ + annot = str(annot) + + # Annotation can be quoted. + if annot.startswith(("'", '"')) and annot.endswith(("'", '"')): + annot = annot[1:-1] + + return annot.startswith(_classvar_prefixes) + + +def _has_own_attribute(cls, attrib_name): + """ + Check whether *cls* defines *attrib_name* (and doesn't just inherit it). + """ + attr = getattr(cls, attrib_name, _sentinel) + if attr is _sentinel: + return False + + for base_cls in cls.__mro__[1:]: + a = getattr(base_cls, attrib_name, None) + if attr is a: + return False + + return True + + +def _get_annotations(cls): + """ + Get annotations for *cls*. + """ + if _has_own_attribute(cls, "__annotations__"): + return cls.__annotations__ + + return {} + + +def _collect_base_attrs(cls, taken_attr_names): + """ + Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. + """ + base_attrs = [] + base_attr_map = {} # A dictionary of base attrs to their classes. + + # Traverse the MRO and collect attributes. + for base_cls in reversed(cls.__mro__[1:-1]): + for a in getattr(base_cls, "__attrs_attrs__", []): + if a.inherited or a.name in taken_attr_names: + continue + + a = a.evolve(inherited=True) # noqa: PLW2901 + base_attrs.append(a) + base_attr_map[a.name] = base_cls + + # For each name, only keep the freshest definition i.e. the furthest at the + # back. base_attr_map is fine because it gets overwritten with every new + # instance. + filtered = [] + seen = set() + for a in reversed(base_attrs): + if a.name in seen: + continue + filtered.insert(0, a) + seen.add(a.name) + + return filtered, base_attr_map + + +def _collect_base_attrs_broken(cls, taken_attr_names): + """ + Collect attr.ibs from base classes of *cls*, except *taken_attr_names*. + + N.B. *taken_attr_names* will be mutated. + + Adhere to the old incorrect behavior. + + Notably it collects from the front and considers inherited attributes which + leads to the buggy behavior reported in #428. + """ + base_attrs = [] + base_attr_map = {} # A dictionary of base attrs to their classes. + + # Traverse the MRO and collect attributes. + for base_cls in cls.__mro__[1:-1]: + for a in getattr(base_cls, "__attrs_attrs__", []): + if a.name in taken_attr_names: + continue + + a = a.evolve(inherited=True) # noqa: PLW2901 + taken_attr_names.add(a.name) + base_attrs.append(a) + base_attr_map[a.name] = base_cls + + return base_attrs, base_attr_map + + +def _transform_attrs( + cls, these, auto_attribs, kw_only, collect_by_mro, field_transformer +): + """ + Transform all `_CountingAttr`s on a class into `Attribute`s. + + If *these* is passed, use that and don't look for them on the class. + + *collect_by_mro* is True, collect them in the correct MRO order, otherwise + use the old -- incorrect -- order. See #428. + + Return an `_Attributes`. + """ + cd = cls.__dict__ + anns = _get_annotations(cls) + + if these is not None: + ca_list = list(these.items()) + elif auto_attribs is True: + ca_names = { + name + for name, attr in cd.items() + if isinstance(attr, _CountingAttr) + } + ca_list = [] + annot_names = set() + for attr_name, type in anns.items(): + if _is_class_var(type): + continue + annot_names.add(attr_name) + a = cd.get(attr_name, NOTHING) + + if not isinstance(a, _CountingAttr): + a = attrib() if a is NOTHING else attrib(default=a) + ca_list.append((attr_name, a)) + + unannotated = ca_names - annot_names + if len(unannotated) > 0: + raise UnannotatedAttributeError( + "The following `attr.ib`s lack a type annotation: " + + ", ".join( + sorted(unannotated, key=lambda n: cd.get(n).counter) + ) + + "." + ) + else: + ca_list = sorted( + ( + (name, attr) + for name, attr in cd.items() + if isinstance(attr, _CountingAttr) + ), + key=lambda e: e[1].counter, + ) + + own_attrs = [ + Attribute.from_counting_attr( + name=attr_name, ca=ca, type=anns.get(attr_name) + ) + for attr_name, ca in ca_list + ] + + if collect_by_mro: + base_attrs, base_attr_map = _collect_base_attrs( + cls, {a.name for a in own_attrs} + ) + else: + base_attrs, base_attr_map = _collect_base_attrs_broken( + cls, {a.name for a in own_attrs} + ) + + if kw_only: + own_attrs = [a.evolve(kw_only=True) for a in own_attrs] + base_attrs = [a.evolve(kw_only=True) for a in base_attrs] + + attrs = base_attrs + own_attrs + + # Mandatory vs non-mandatory attr order only matters when they are part of + # the __init__ signature and when they aren't kw_only (which are moved to + # the end and can be mandatory or non-mandatory in any order, as they will + # be specified as keyword args anyway). Check the order of those attrs: + had_default = False + for a in (a for a in attrs if a.init is not False and a.kw_only is False): + if had_default is True and a.default is NOTHING: + msg = f"No mandatory attributes allowed after an attribute with a default value or factory. Attribute in question: {a!r}" + raise ValueError(msg) + + if had_default is False and a.default is not NOTHING: + had_default = True + + if field_transformer is not None: + attrs = field_transformer(cls, attrs) + + # Resolve default field alias after executing field_transformer. + # This allows field_transformer to differentiate between explicit vs + # default aliases and supply their own defaults. + attrs = [ + a.evolve(alias=_default_init_alias_for(a.name)) if not a.alias else a + for a in attrs + ] + + # Create AttrsClass *after* applying the field_transformer since it may + # add or remove attributes! + attr_names = [a.name for a in attrs] + AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names) + + return _Attributes((AttrsClass(attrs), base_attrs, base_attr_map)) + + +def _make_cached_property_getattr( + cached_properties, + original_getattr, + cls, +): + lines = [ + # Wrapped to get `__class__` into closure cell for super() + # (It will be replaced with the newly constructed class after construction). + "def wrapper():", + " __class__ = _cls", + " def __getattr__(self, item, cached_properties=cached_properties, original_getattr=original_getattr, _cached_setattr_get=_cached_setattr_get):", + " func = cached_properties.get(item)", + " if func is not None:", + " result = func(self)", + " _setter = _cached_setattr_get(self)", + " _setter(item, result)", + " return result", + ] + if original_getattr is not None: + lines.append( + " return original_getattr(self, item)", + ) + else: + lines.extend( + [ + " if hasattr(super(), '__getattr__'):", + " return super().__getattr__(item)", + " original_error = f\"'{self.__class__.__name__}' object has no attribute '{item}'\"", + " raise AttributeError(original_error)", + ] + ) + + lines.extend( + [ + " return __getattr__", + "__getattr__ = wrapper()", + ] + ) + + unique_filename = _generate_unique_filename(cls, "getattr") + + glob = { + "cached_properties": cached_properties, + "_cached_setattr_get": _obj_setattr.__get__, + "_cls": cls, + "original_getattr": original_getattr, + } + + return _make_method( + "__getattr__", + "\n".join(lines), + unique_filename, + glob, + ) + + +def _frozen_setattrs(self, name, value): + """ + Attached to frozen classes as __setattr__. + """ + if isinstance(self, BaseException) and name in ( + "__cause__", + "__context__", + "__traceback__", + ): + BaseException.__setattr__(self, name, value) + return + + raise FrozenInstanceError() + + +def _frozen_delattrs(self, name): + """ + Attached to frozen classes as __delattr__. + """ + raise FrozenInstanceError() + + +class _ClassBuilder: + """ + Iteratively build *one* class. + """ + + __slots__ = ( + "_attr_names", + "_attrs", + "_base_attr_map", + "_base_names", + "_cache_hash", + "_cls", + "_cls_dict", + "_delete_attribs", + "_frozen", + "_has_pre_init", + "_pre_init_has_args", + "_has_post_init", + "_is_exc", + "_on_setattr", + "_slots", + "_weakref_slot", + "_wrote_own_setattr", + "_has_custom_setattr", + ) + + def __init__( + self, + cls, + these, + slots, + frozen, + weakref_slot, + getstate_setstate, + auto_attribs, + kw_only, + cache_hash, + is_exc, + collect_by_mro, + on_setattr, + has_custom_setattr, + field_transformer, + ): + attrs, base_attrs, base_map = _transform_attrs( + cls, + these, + auto_attribs, + kw_only, + collect_by_mro, + field_transformer, + ) + + self._cls = cls + self._cls_dict = dict(cls.__dict__) if slots else {} + self._attrs = attrs + self._base_names = {a.name for a in base_attrs} + self._base_attr_map = base_map + self._attr_names = tuple(a.name for a in attrs) + self._slots = slots + self._frozen = frozen + self._weakref_slot = weakref_slot + self._cache_hash = cache_hash + self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False)) + self._pre_init_has_args = False + if self._has_pre_init: + # Check if the pre init method has more arguments than just `self` + # We want to pass arguments if pre init expects arguments + pre_init_func = cls.__attrs_pre_init__ + pre_init_signature = inspect.signature(pre_init_func) + self._pre_init_has_args = len(pre_init_signature.parameters) > 1 + self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False)) + self._delete_attribs = not bool(these) + self._is_exc = is_exc + self._on_setattr = on_setattr + + self._has_custom_setattr = has_custom_setattr + self._wrote_own_setattr = False + + self._cls_dict["__attrs_attrs__"] = self._attrs + + if frozen: + self._cls_dict["__setattr__"] = _frozen_setattrs + self._cls_dict["__delattr__"] = _frozen_delattrs + + self._wrote_own_setattr = True + elif on_setattr in ( + _ng_default_on_setattr, + setters.validate, + setters.convert, + ): + has_validator = has_converter = False + for a in attrs: + if a.validator is not None: + has_validator = True + if a.converter is not None: + has_converter = True + + if has_validator and has_converter: + break + if ( + ( + on_setattr == _ng_default_on_setattr + and not (has_validator or has_converter) + ) + or (on_setattr == setters.validate and not has_validator) + or (on_setattr == setters.convert and not has_converter) + ): + # If class-level on_setattr is set to convert + validate, but + # there's no field to convert or validate, pretend like there's + # no on_setattr. + self._on_setattr = None + + if getstate_setstate: + ( + self._cls_dict["__getstate__"], + self._cls_dict["__setstate__"], + ) = self._make_getstate_setstate() + + def __repr__(self): + return f"<_ClassBuilder(cls={self._cls.__name__})>" + + if PY310: + import abc + + def build_class(self): + """ + Finalize class based on the accumulated configuration. + + Builder cannot be used after calling this method. + """ + if self._slots is True: + return self._create_slots_class() + + return self.abc.update_abstractmethods( + self._patch_original_class() + ) + + else: + + def build_class(self): + """ + Finalize class based on the accumulated configuration. + + Builder cannot be used after calling this method. + """ + if self._slots is True: + return self._create_slots_class() + + return self._patch_original_class() + + def _patch_original_class(self): + """ + Apply accumulated methods and return the class. + """ + cls = self._cls + base_names = self._base_names + + # Clean class of attribute definitions (`attr.ib()`s). + if self._delete_attribs: + for name in self._attr_names: + if ( + name not in base_names + and getattr(cls, name, _sentinel) is not _sentinel + ): + # An AttributeError can happen if a base class defines a + # class variable and we want to set an attribute with the + # same name by using only a type annotation. + with contextlib.suppress(AttributeError): + delattr(cls, name) + + # Attach our dunder methods. + for name, value in self._cls_dict.items(): + setattr(cls, name, value) + + # If we've inherited an attrs __setattr__ and don't write our own, + # reset it to object's. + if not self._wrote_own_setattr and getattr( + cls, "__attrs_own_setattr__", False + ): + cls.__attrs_own_setattr__ = False + + if not self._has_custom_setattr: + cls.__setattr__ = _obj_setattr + + return cls + + def _create_slots_class(self): + """ + Build and return a new class with a `__slots__` attribute. + """ + cd = { + k: v + for k, v in self._cls_dict.items() + if k not in (*tuple(self._attr_names), "__dict__", "__weakref__") + } + + # If our class doesn't have its own implementation of __setattr__ + # (either from the user or by us), check the bases, if one of them has + # an attrs-made __setattr__, that needs to be reset. We don't walk the + # MRO because we only care about our immediate base classes. + # XXX: This can be confused by subclassing a slotted attrs class with + # XXX: a non-attrs class and subclass the resulting class with an attrs + # XXX: class. See `test_slotted_confused` for details. For now that's + # XXX: OK with us. + if not self._wrote_own_setattr: + cd["__attrs_own_setattr__"] = False + + if not self._has_custom_setattr: + for base_cls in self._cls.__bases__: + if base_cls.__dict__.get("__attrs_own_setattr__", False): + cd["__setattr__"] = _obj_setattr + break + + # Traverse the MRO to collect existing slots + # and check for an existing __weakref__. + existing_slots = {} + weakref_inherited = False + for base_cls in self._cls.__mro__[1:-1]: + if base_cls.__dict__.get("__weakref__", None) is not None: + weakref_inherited = True + existing_slots.update( + { + name: getattr(base_cls, name) + for name in getattr(base_cls, "__slots__", []) + } + ) + + base_names = set(self._base_names) + + names = self._attr_names + if ( + self._weakref_slot + and "__weakref__" not in getattr(self._cls, "__slots__", ()) + and "__weakref__" not in names + and not weakref_inherited + ): + names += ("__weakref__",) + + if PY_3_8_PLUS: + cached_properties = { + name: cached_property.func + for name, cached_property in cd.items() + if isinstance(cached_property, functools.cached_property) + } + else: + # `functools.cached_property` was introduced in 3.8. + # So can't be used before this. + cached_properties = {} + + # Collect methods with a `__class__` reference that are shadowed in the new class. + # To know to update them. + additional_closure_functions_to_update = [] + if cached_properties: + # Add cached properties to names for slotting. + names += tuple(cached_properties.keys()) + + for name in cached_properties: + # Clear out function from class to avoid clashing. + del cd[name] + + class_annotations = _get_annotations(self._cls) + for name, func in cached_properties.items(): + annotation = inspect.signature(func).return_annotation + if annotation is not inspect.Parameter.empty: + class_annotations[name] = annotation + + original_getattr = cd.get("__getattr__") + if original_getattr is not None: + additional_closure_functions_to_update.append(original_getattr) + + cd["__getattr__"] = _make_cached_property_getattr( + cached_properties, original_getattr, self._cls + ) + + # We only add the names of attributes that aren't inherited. + # Setting __slots__ to inherited attributes wastes memory. + slot_names = [name for name in names if name not in base_names] + + # There are slots for attributes from current class + # that are defined in parent classes. + # As their descriptors may be overridden by a child class, + # we collect them here and update the class dict + reused_slots = { + slot: slot_descriptor + for slot, slot_descriptor in existing_slots.items() + if slot in slot_names + } + slot_names = [name for name in slot_names if name not in reused_slots] + cd.update(reused_slots) + if self._cache_hash: + slot_names.append(_hash_cache_field) + + cd["__slots__"] = tuple(slot_names) + + cd["__qualname__"] = self._cls.__qualname__ + + # Create new class based on old class and our methods. + cls = type(self._cls)(self._cls.__name__, self._cls.__bases__, cd) + + # The following is a fix for + # . + # If a method mentions `__class__` or uses the no-arg super(), the + # compiler will bake a reference to the class in the method itself + # as `method.__closure__`. Since we replace the class with a + # clone, we rewrite these references so it keeps working. + for item in itertools.chain( + cls.__dict__.values(), additional_closure_functions_to_update + ): + if isinstance(item, (classmethod, staticmethod)): + # Class- and staticmethods hide their functions inside. + # These might need to be rewritten as well. + closure_cells = getattr(item.__func__, "__closure__", None) + elif isinstance(item, property): + # Workaround for property `super()` shortcut (PY3-only). + # There is no universal way for other descriptors. + closure_cells = getattr(item.fget, "__closure__", None) + else: + closure_cells = getattr(item, "__closure__", None) + + if not closure_cells: # Catch None or the empty list. + continue + for cell in closure_cells: + try: + match = cell.cell_contents is self._cls + except ValueError: # noqa: PERF203 + # ValueError: Cell is empty + pass + else: + if match: + cell.cell_contents = cls + return cls + + def add_repr(self, ns): + self._cls_dict["__repr__"] = self._add_method_dunders( + _make_repr(self._attrs, ns, self._cls) + ) + return self + + def add_str(self): + repr = self._cls_dict.get("__repr__") + if repr is None: + msg = "__str__ can only be generated if a __repr__ exists." + raise ValueError(msg) + + def __str__(self): + return self.__repr__() + + self._cls_dict["__str__"] = self._add_method_dunders(__str__) + return self + + def _make_getstate_setstate(self): + """ + Create custom __setstate__ and __getstate__ methods. + """ + # __weakref__ is not writable. + state_attr_names = tuple( + an for an in self._attr_names if an != "__weakref__" + ) + + def slots_getstate(self): + """ + Automatically created by attrs. + """ + return {name: getattr(self, name) for name in state_attr_names} + + hash_caching_enabled = self._cache_hash + + def slots_setstate(self, state): + """ + Automatically created by attrs. + """ + __bound_setattr = _obj_setattr.__get__(self) + if isinstance(state, tuple): + # Backward compatibility with attrs instances pickled with + # attrs versions before v22.2.0 which stored tuples. + for name, value in zip(state_attr_names, state): + __bound_setattr(name, value) + else: + for name in state_attr_names: + if name in state: + __bound_setattr(name, state[name]) + + # The hash code cache is not included when the object is + # serialized, but it still needs to be initialized to None to + # indicate that the first call to __hash__ should be a cache + # miss. + if hash_caching_enabled: + __bound_setattr(_hash_cache_field, None) + + return slots_getstate, slots_setstate + + def make_unhashable(self): + self._cls_dict["__hash__"] = None + return self + + def add_hash(self): + self._cls_dict["__hash__"] = self._add_method_dunders( + _make_hash( + self._cls, + self._attrs, + frozen=self._frozen, + cache_hash=self._cache_hash, + ) + ) + + return self + + def add_init(self): + self._cls_dict["__init__"] = self._add_method_dunders( + _make_init( + self._cls, + self._attrs, + self._has_pre_init, + self._pre_init_has_args, + self._has_post_init, + self._frozen, + self._slots, + self._cache_hash, + self._base_attr_map, + self._is_exc, + self._on_setattr, + attrs_init=False, + ) + ) + + return self + + def add_match_args(self): + self._cls_dict["__match_args__"] = tuple( + field.name + for field in self._attrs + if field.init and not field.kw_only + ) + + def add_attrs_init(self): + self._cls_dict["__attrs_init__"] = self._add_method_dunders( + _make_init( + self._cls, + self._attrs, + self._has_pre_init, + self._pre_init_has_args, + self._has_post_init, + self._frozen, + self._slots, + self._cache_hash, + self._base_attr_map, + self._is_exc, + self._on_setattr, + attrs_init=True, + ) + ) + + return self + + def add_eq(self): + cd = self._cls_dict + + cd["__eq__"] = self._add_method_dunders( + _make_eq(self._cls, self._attrs) + ) + cd["__ne__"] = self._add_method_dunders(_make_ne()) + + return self + + def add_order(self): + cd = self._cls_dict + + cd["__lt__"], cd["__le__"], cd["__gt__"], cd["__ge__"] = ( + self._add_method_dunders(meth) + for meth in _make_order(self._cls, self._attrs) + ) + + return self + + def add_setattr(self): + if self._frozen: + return self + + sa_attrs = {} + for a in self._attrs: + on_setattr = a.on_setattr or self._on_setattr + if on_setattr and on_setattr is not setters.NO_OP: + sa_attrs[a.name] = a, on_setattr + + if not sa_attrs: + return self + + if self._has_custom_setattr: + # We need to write a __setattr__ but there already is one! + msg = "Can't combine custom __setattr__ with on_setattr hooks." + raise ValueError(msg) + + # docstring comes from _add_method_dunders + def __setattr__(self, name, val): + try: + a, hook = sa_attrs[name] + except KeyError: + nval = val + else: + nval = hook(self, a, val) + + _obj_setattr(self, name, nval) + + self._cls_dict["__attrs_own_setattr__"] = True + self._cls_dict["__setattr__"] = self._add_method_dunders(__setattr__) + self._wrote_own_setattr = True + + return self + + def _add_method_dunders(self, method): + """ + Add __module__ and __qualname__ to a *method* if possible. + """ + with contextlib.suppress(AttributeError): + method.__module__ = self._cls.__module__ + + with contextlib.suppress(AttributeError): + method.__qualname__ = f"{self._cls.__qualname__}.{method.__name__}" + + with contextlib.suppress(AttributeError): + method.__doc__ = ( + "Method generated by attrs for class " + f"{self._cls.__qualname__}." + ) + + return method + + +def _determine_attrs_eq_order(cmp, eq, order, default_eq): + """ + Validate the combination of *cmp*, *eq*, and *order*. Derive the effective + values of eq and order. If *eq* is None, set it to *default_eq*. + """ + if cmp is not None and any((eq is not None, order is not None)): + msg = "Don't mix `cmp` with `eq' and `order`." + raise ValueError(msg) + + # cmp takes precedence due to bw-compatibility. + if cmp is not None: + return cmp, cmp + + # If left None, equality is set to the specified default and ordering + # mirrors equality. + if eq is None: + eq = default_eq + + if order is None: + order = eq + + if eq is False and order is True: + msg = "`order` can only be True if `eq` is True too." + raise ValueError(msg) + + return eq, order + + +def _determine_attrib_eq_order(cmp, eq, order, default_eq): + """ + Validate the combination of *cmp*, *eq*, and *order*. Derive the effective + values of eq and order. If *eq* is None, set it to *default_eq*. + """ + if cmp is not None and any((eq is not None, order is not None)): + msg = "Don't mix `cmp` with `eq' and `order`." + raise ValueError(msg) + + def decide_callable_or_boolean(value): + """ + Decide whether a key function is used. + """ + if callable(value): + value, key = True, value + else: + key = None + return value, key + + # cmp takes precedence due to bw-compatibility. + if cmp is not None: + cmp, cmp_key = decide_callable_or_boolean(cmp) + return cmp, cmp_key, cmp, cmp_key + + # If left None, equality is set to the specified default and ordering + # mirrors equality. + if eq is None: + eq, eq_key = default_eq, None + else: + eq, eq_key = decide_callable_or_boolean(eq) + + if order is None: + order, order_key = eq, eq_key + else: + order, order_key = decide_callable_or_boolean(order) + + if eq is False and order is True: + msg = "`order` can only be True if `eq` is True too." + raise ValueError(msg) + + return eq, eq_key, order, order_key + + +def _determine_whether_to_implement( + cls, flag, auto_detect, dunders, default=True +): + """ + Check whether we should implement a set of methods for *cls*. + + *flag* is the argument passed into @attr.s like 'init', *auto_detect* the + same as passed into @attr.s and *dunders* is a tuple of attribute names + whose presence signal that the user has implemented it themselves. + + Return *default* if no reason for either for or against is found. + """ + if flag is True or flag is False: + return flag + + if flag is None and auto_detect is False: + return default + + # Logically, flag is None and auto_detect is True here. + for dunder in dunders: + if _has_own_attribute(cls, dunder): + return False + + return default + + +def attrs( + maybe_cls=None, + these=None, + repr_ns=None, + repr=None, + cmp=None, + hash=None, + init=None, + slots=False, + frozen=False, + weakref_slot=True, + str=False, + auto_attribs=False, + kw_only=False, + cache_hash=False, + auto_exc=False, + eq=None, + order=None, + auto_detect=False, + collect_by_mro=False, + getstate_setstate=None, + on_setattr=None, + field_transformer=None, + match_args=True, + unsafe_hash=None, +): + r""" + A class decorator that adds :term:`dunder methods` according to the + specified attributes using `attr.ib` or the *these* argument. + + Please consider using `attrs.define` / `attrs.frozen` in new code + (``attr.s`` will *never* go away, though). + + :param these: A dictionary of name to `attr.ib` mappings. This is useful + to avoid the definition of your attributes within the class body + because you can't (e.g. if you want to add ``__repr__`` methods to + Django models) or don't want to. + + If *these* is not ``None``, *attrs* will *not* search the class body + for attributes and will *not* remove any attributes from it. + + The order is deduced from the order of the attributes inside *these*. + + :type these: `dict` of `str` to `attr.ib` + + :param str repr_ns: When using nested classes, there's no way in Python 2 + to automatically detect that. Therefore it's possible to set the + namespace explicitly for a more meaningful ``repr`` output. + :param bool auto_detect: Instead of setting the *init*, *repr*, *eq*, + *order*, and *hash* arguments explicitly, assume they are set to + ``True`` **unless any** of the involved methods for one of the + arguments is implemented in the *current* class (i.e. it is *not* + inherited from some base class). + + So for example by implementing ``__eq__`` on a class yourself, *attrs* + will deduce ``eq=False`` and will create *neither* ``__eq__`` *nor* + ``__ne__`` (but Python classes come with a sensible ``__ne__`` by + default, so it *should* be enough to only implement ``__eq__`` in most + cases). + + .. warning:: + + If you prevent *attrs* from creating the ordering methods for you + (``order=False``, e.g. by implementing ``__le__``), it becomes + *your* responsibility to make sure its ordering is sound. The best + way is to use the `functools.total_ordering` decorator. + + + Passing ``True`` or ``False`` to *init*, *repr*, *eq*, *order*, *cmp*, + or *hash* overrides whatever *auto_detect* would determine. + + :param bool repr: Create a ``__repr__`` method with a human readable + representation of *attrs* attributes.. + :param bool str: Create a ``__str__`` method that is identical to + ``__repr__``. This is usually not necessary except for `Exception`\ s. + :param bool | None eq: If ``True`` or ``None`` (default), add ``__eq__`` + and ``__ne__`` methods that check two instances for equality. + + They compare the instances as if they were tuples of their *attrs* + attributes if and only if the types of both classes are *identical*! + + .. seealso:: `comparison` + :param bool | None order: If ``True``, add ``__lt__``, ``__le__``, + ``__gt__``, and ``__ge__`` methods that behave like *eq* above and + allow instances to be ordered. If ``None`` (default) mirror value of + *eq*. + + .. seealso:: `comparison` + :param bool | None cmp: Setting *cmp* is equivalent to setting *eq* and + *order* to the same value. Must not be mixed with *eq* or *order*. + + .. seealso:: `comparison` + :param bool | None unsafe_hash: If ``None`` (default), the ``__hash__`` + method is generated according how *eq* and *frozen* are set. + + 1. If *both* are True, *attrs* will generate a ``__hash__`` for you. + 2. If *eq* is True and *frozen* is False, ``__hash__`` will be set to + None, marking it unhashable (which it is). + 3. If *eq* is False, ``__hash__`` will be left untouched meaning the + ``__hash__`` method of the base class will be used (if base class is + ``object``, this means it will fall back to id-based hashing.). + + Although not recommended, you can decide for yourself and force *attrs* + to create one (e.g. if the class is immutable even though you didn't + freeze it programmatically) by passing ``True`` or not. Both of these + cases are rather special and should be used carefully. + + .. seealso:: + + - Our documentation on `hashing`, + - Python's documentation on `object.__hash__`, + - and the `GitHub issue that led to the default \ + behavior `_ for + more details. + + :param bool | None hash: Alias for *unsafe_hash*. *unsafe_hash* takes + precedence. + :param bool init: Create a ``__init__`` method that initializes the *attrs* + attributes. Leading underscores are stripped for the argument name. If + a ``__attrs_pre_init__`` method exists on the class, it will be called + before the class is initialized. If a ``__attrs_post_init__`` method + exists on the class, it will be called after the class is fully + initialized. + + If ``init`` is ``False``, an ``__attrs_init__`` method will be injected + instead. This allows you to define a custom ``__init__`` method that + can do pre-init work such as ``super().__init__()``, and then call + ``__attrs_init__()`` and ``__attrs_post_init__()``. + + .. seealso:: `init` + :param bool slots: Create a :term:`slotted class ` that's + more memory-efficient. Slotted classes are generally superior to the + default dict classes, but have some gotchas you should know about, so + we encourage you to read the :term:`glossary entry `. + :param bool frozen: Make instances immutable after initialization. If + someone attempts to modify a frozen instance, + `attrs.exceptions.FrozenInstanceError` is raised. + + .. note:: + + 1. This is achieved by installing a custom ``__setattr__`` method + on your class, so you can't implement your own. + + 2. True immutability is impossible in Python. + + 3. This *does* have a minor a runtime performance `impact + ` when initializing new instances. In other words: + ``__init__`` is slightly slower with ``frozen=True``. + + 4. If a class is frozen, you cannot modify ``self`` in + ``__attrs_post_init__`` or a self-written ``__init__``. You can + circumvent that limitation by using ``object.__setattr__(self, + "attribute_name", value)``. + + 5. Subclasses of a frozen class are frozen too. + + :param bool weakref_slot: Make instances weak-referenceable. This has no + effect unless ``slots`` is also enabled. + :param bool auto_attribs: If ``True``, collect :pep:`526`-annotated + attributes from the class body. + + In this case, you **must** annotate every field. If *attrs* encounters + a field that is set to an `attr.ib` but lacks a type annotation, an + `attr.exceptions.UnannotatedAttributeError` is raised. Use + ``field_name: typing.Any = attr.ib(...)`` if you don't want to set a + type. + + If you assign a value to those attributes (e.g. ``x: int = 42``), that + value becomes the default value like if it were passed using + ``attr.ib(default=42)``. Passing an instance of `attrs.Factory` also + works as expected in most cases (see warning below). + + Attributes annotated as `typing.ClassVar`, and attributes that are + neither annotated nor set to an `attr.ib` are **ignored**. + + .. warning:: + For features that use the attribute name to create decorators (e.g. + :ref:`validators `), you still *must* assign `attr.ib` + to them. Otherwise Python will either not find the name or try to + use the default value to call e.g. ``validator`` on it. + + These errors can be quite confusing and probably the most common bug + report on our bug tracker. + + :param bool kw_only: Make all attributes keyword-only in the generated + ``__init__`` (if ``init`` is ``False``, this parameter is ignored). + :param bool cache_hash: Ensure that the object's hash code is computed only + once and stored on the object. If this is set to ``True``, hashing + must be either explicitly or implicitly enabled for this class. If the + hash code is cached, avoid any reassignments of fields involved in hash + code computation or mutations of the objects those fields point to + after object creation. If such changes occur, the behavior of the + object's hash code is undefined. + :param bool auto_exc: If the class subclasses `BaseException` (which + implicitly includes any subclass of any exception), the following + happens to behave like a well-behaved Python exceptions class: + + - the values for *eq*, *order*, and *hash* are ignored and the + instances compare and hash by the instance's ids (N.B. *attrs* will + *not* remove existing implementations of ``__hash__`` or the equality + methods. It just won't add own ones.), + - all attributes that are either passed into ``__init__`` or have a + default value are additionally available as a tuple in the ``args`` + attribute, + - the value of *str* is ignored leaving ``__str__`` to base classes. + :param bool collect_by_mro: Setting this to `True` fixes the way *attrs* + collects attributes from base classes. The default behavior is + incorrect in certain cases of multiple inheritance. It should be on by + default but is kept off for backward-compatibility. + + .. seealso:: + Issue `#428 `_ + + :param bool | None getstate_setstate: + .. note:: + This is usually only interesting for slotted classes and you should + probably just set *auto_detect* to `True`. + + If `True`, ``__getstate__`` and ``__setstate__`` are generated and + attached to the class. This is necessary for slotted classes to be + pickleable. If left `None`, it's `True` by default for slotted classes + and ``False`` for dict classes. + + If *auto_detect* is `True`, and *getstate_setstate* is left `None`, and + **either** ``__getstate__`` or ``__setstate__`` is detected directly on + the class (i.e. not inherited), it is set to `False` (this is usually + what you want). + + :param on_setattr: A callable that is run whenever the user attempts to set + an attribute (either by assignment like ``i.x = 42`` or by using + `setattr` like ``setattr(i, "x", 42)``). It receives the same arguments + as validators: the instance, the attribute that is being modified, and + the new value. + + If no exception is raised, the attribute is set to the return value of + the callable. + + If a list of callables is passed, they're automatically wrapped in an + `attrs.setters.pipe`. + :type on_setattr: `callable`, or a list of callables, or `None`, or + `attrs.setters.NO_OP` + + :param callable | None field_transformer: + A function that is called with the original class object and all fields + right before *attrs* finalizes the class. You can use this, e.g., to + automatically add converters or validators to fields based on their + types. + + .. seealso:: `transform-fields` + + :param bool match_args: + If `True` (default), set ``__match_args__`` on the class to support + :pep:`634` (Structural Pattern Matching). It is a tuple of all + non-keyword-only ``__init__`` parameter names on Python 3.10 and later. + Ignored on older Python versions. + + .. versionadded:: 16.0.0 *slots* + .. versionadded:: 16.1.0 *frozen* + .. versionadded:: 16.3.0 *str* + .. versionadded:: 16.3.0 Support for ``__attrs_post_init__``. + .. versionchanged:: 17.1.0 + *hash* supports ``None`` as value which is also the default now. + .. versionadded:: 17.3.0 *auto_attribs* + .. versionchanged:: 18.1.0 + If *these* is passed, no attributes are deleted from the class body. + .. versionchanged:: 18.1.0 If *these* is ordered, the order is retained. + .. versionadded:: 18.2.0 *weakref_slot* + .. deprecated:: 18.2.0 + ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now raise a + `DeprecationWarning` if the classes compared are subclasses of + each other. ``__eq`` and ``__ne__`` never tried to compared subclasses + to each other. + .. versionchanged:: 19.2.0 + ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now do not consider + subclasses comparable anymore. + .. versionadded:: 18.2.0 *kw_only* + .. versionadded:: 18.2.0 *cache_hash* + .. versionadded:: 19.1.0 *auto_exc* + .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01. + .. versionadded:: 19.2.0 *eq* and *order* + .. versionadded:: 20.1.0 *auto_detect* + .. versionadded:: 20.1.0 *collect_by_mro* + .. versionadded:: 20.1.0 *getstate_setstate* + .. versionadded:: 20.1.0 *on_setattr* + .. versionadded:: 20.3.0 *field_transformer* + .. versionchanged:: 21.1.0 + ``init=False`` injects ``__attrs_init__`` + .. versionchanged:: 21.1.0 Support for ``__attrs_pre_init__`` + .. versionchanged:: 21.1.0 *cmp* undeprecated + .. versionadded:: 21.3.0 *match_args* + .. versionadded:: 22.2.0 + *unsafe_hash* as an alias for *hash* (for :pep:`681` compliance). + """ + eq_, order_ = _determine_attrs_eq_order(cmp, eq, order, None) + + # unsafe_hash takes precedence due to PEP 681. + if unsafe_hash is not None: + hash = unsafe_hash + + if isinstance(on_setattr, (list, tuple)): + on_setattr = setters.pipe(*on_setattr) + + def wrap(cls): + is_frozen = frozen or _has_frozen_base_class(cls) + is_exc = auto_exc is True and issubclass(cls, BaseException) + has_own_setattr = auto_detect and _has_own_attribute( + cls, "__setattr__" + ) + + if has_own_setattr and is_frozen: + msg = "Can't freeze a class with a custom __setattr__." + raise ValueError(msg) + + builder = _ClassBuilder( + cls, + these, + slots, + is_frozen, + weakref_slot, + _determine_whether_to_implement( + cls, + getstate_setstate, + auto_detect, + ("__getstate__", "__setstate__"), + default=slots, + ), + auto_attribs, + kw_only, + cache_hash, + is_exc, + collect_by_mro, + on_setattr, + has_own_setattr, + field_transformer, + ) + if _determine_whether_to_implement( + cls, repr, auto_detect, ("__repr__",) + ): + builder.add_repr(repr_ns) + if str is True: + builder.add_str() + + eq = _determine_whether_to_implement( + cls, eq_, auto_detect, ("__eq__", "__ne__") + ) + if not is_exc and eq is True: + builder.add_eq() + if not is_exc and _determine_whether_to_implement( + cls, order_, auto_detect, ("__lt__", "__le__", "__gt__", "__ge__") + ): + builder.add_order() + + builder.add_setattr() + + nonlocal hash + if ( + hash is None + and auto_detect is True + and _has_own_attribute(cls, "__hash__") + ): + hash = False + + if hash is not True and hash is not False and hash is not None: + # Can't use `hash in` because 1 == True for example. + msg = "Invalid value for hash. Must be True, False, or None." + raise TypeError(msg) + + if hash is False or (hash is None and eq is False) or is_exc: + # Don't do anything. Should fall back to __object__'s __hash__ + # which is by id. + if cache_hash: + msg = "Invalid value for cache_hash. To use hash caching, hashing must be either explicitly or implicitly enabled." + raise TypeError(msg) + elif hash is True or ( + hash is None and eq is True and is_frozen is True + ): + # Build a __hash__ if told so, or if it's safe. + builder.add_hash() + else: + # Raise TypeError on attempts to hash. + if cache_hash: + msg = "Invalid value for cache_hash. To use hash caching, hashing must be either explicitly or implicitly enabled." + raise TypeError(msg) + builder.make_unhashable() + + if _determine_whether_to_implement( + cls, init, auto_detect, ("__init__",) + ): + builder.add_init() + else: + builder.add_attrs_init() + if cache_hash: + msg = "Invalid value for cache_hash. To use hash caching, init must be True." + raise TypeError(msg) + + if ( + PY310 + and match_args + and not _has_own_attribute(cls, "__match_args__") + ): + builder.add_match_args() + + return builder.build_class() + + # maybe_cls's type depends on the usage of the decorator. It's a class + # if it's used as `@attrs` but ``None`` if used as `@attrs()`. + if maybe_cls is None: + return wrap + + return wrap(maybe_cls) + + +_attrs = attrs +""" +Internal alias so we can use it in functions that take an argument called +*attrs*. +""" + + +def _has_frozen_base_class(cls): + """ + Check whether *cls* has a frozen ancestor by looking at its + __setattr__. + """ + return cls.__setattr__ is _frozen_setattrs + + +def _generate_unique_filename(cls, func_name): + """ + Create a "filename" suitable for a function being generated. + """ + return ( + f"" + ) + + +def _make_hash(cls, attrs, frozen, cache_hash): + attrs = tuple( + a for a in attrs if a.hash is True or (a.hash is None and a.eq is True) + ) + + tab = " " + + unique_filename = _generate_unique_filename(cls, "hash") + type_hash = hash(unique_filename) + # If eq is custom generated, we need to include the functions in globs + globs = {} + + hash_def = "def __hash__(self" + hash_func = "hash((" + closing_braces = "))" + if not cache_hash: + hash_def += "):" + else: + hash_def += ", *" + + hash_def += ", _cache_wrapper=__import__('attr._make')._make._CacheHashWrapper):" + hash_func = "_cache_wrapper(" + hash_func + closing_braces += ")" + + method_lines = [hash_def] + + def append_hash_computation_lines(prefix, indent): + """ + Generate the code for actually computing the hash code. + Below this will either be returned directly or used to compute + a value which is then cached, depending on the value of cache_hash + """ + + method_lines.extend( + [ + indent + prefix + hash_func, + indent + f" {type_hash},", + ] + ) + + for a in attrs: + if a.eq_key: + cmp_name = f"_{a.name}_key" + globs[cmp_name] = a.eq_key + method_lines.append( + indent + f" {cmp_name}(self.{a.name})," + ) + else: + method_lines.append(indent + f" self.{a.name},") + + method_lines.append(indent + " " + closing_braces) + + if cache_hash: + method_lines.append(tab + f"if self.{_hash_cache_field} is None:") + if frozen: + append_hash_computation_lines( + f"object.__setattr__(self, '{_hash_cache_field}', ", tab * 2 + ) + method_lines.append(tab * 2 + ")") # close __setattr__ + else: + append_hash_computation_lines( + f"self.{_hash_cache_field} = ", tab * 2 + ) + method_lines.append(tab + f"return self.{_hash_cache_field}") + else: + append_hash_computation_lines("return ", tab) + + script = "\n".join(method_lines) + return _make_method("__hash__", script, unique_filename, globs) + + +def _add_hash(cls, attrs): + """ + Add a hash method to *cls*. + """ + cls.__hash__ = _make_hash(cls, attrs, frozen=False, cache_hash=False) + return cls + + +def _make_ne(): + """ + Create __ne__ method. + """ + + def __ne__(self, other): + """ + Check equality and either forward a NotImplemented or + return the result negated. + """ + result = self.__eq__(other) + if result is NotImplemented: + return NotImplemented + + return not result + + return __ne__ + + +def _make_eq(cls, attrs): + """ + Create __eq__ method for *cls* with *attrs*. + """ + attrs = [a for a in attrs if a.eq] + + unique_filename = _generate_unique_filename(cls, "eq") + lines = [ + "def __eq__(self, other):", + " if other.__class__ is not self.__class__:", + " return NotImplemented", + ] + + # We can't just do a big self.x = other.x and... clause due to + # irregularities like nan == nan is false but (nan,) == (nan,) is true. + globs = {} + if attrs: + lines.append(" return (") + others = [" ) == ("] + for a in attrs: + if a.eq_key: + cmp_name = f"_{a.name}_key" + # Add the key function to the global namespace + # of the evaluated function. + globs[cmp_name] = a.eq_key + lines.append(f" {cmp_name}(self.{a.name}),") + others.append(f" {cmp_name}(other.{a.name}),") + else: + lines.append(f" self.{a.name},") + others.append(f" other.{a.name},") + + lines += [*others, " )"] + else: + lines.append(" return True") + + script = "\n".join(lines) + + return _make_method("__eq__", script, unique_filename, globs) + + +def _make_order(cls, attrs): + """ + Create ordering methods for *cls* with *attrs*. + """ + attrs = [a for a in attrs if a.order] + + def attrs_to_tuple(obj): + """ + Save us some typing. + """ + return tuple( + key(value) if key else value + for value, key in ( + (getattr(obj, a.name), a.order_key) for a in attrs + ) + ) + + def __lt__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) < attrs_to_tuple(other) + + return NotImplemented + + def __le__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) <= attrs_to_tuple(other) + + return NotImplemented + + def __gt__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) > attrs_to_tuple(other) + + return NotImplemented + + def __ge__(self, other): + """ + Automatically created by attrs. + """ + if other.__class__ is self.__class__: + return attrs_to_tuple(self) >= attrs_to_tuple(other) + + return NotImplemented + + return __lt__, __le__, __gt__, __ge__ + + +def _add_eq(cls, attrs=None): + """ + Add equality methods to *cls* with *attrs*. + """ + if attrs is None: + attrs = cls.__attrs_attrs__ + + cls.__eq__ = _make_eq(cls, attrs) + cls.__ne__ = _make_ne() + + return cls + + +def _make_repr(attrs, ns, cls): + unique_filename = _generate_unique_filename(cls, "repr") + # Figure out which attributes to include, and which function to use to + # format them. The a.repr value can be either bool or a custom + # callable. + attr_names_with_reprs = tuple( + (a.name, (repr if a.repr is True else a.repr), a.init) + for a in attrs + if a.repr is not False + ) + globs = { + name + "_repr": r for name, r, _ in attr_names_with_reprs if r != repr + } + globs["_compat"] = _compat + globs["AttributeError"] = AttributeError + globs["NOTHING"] = NOTHING + attribute_fragments = [] + for name, r, i in attr_names_with_reprs: + accessor = ( + "self." + name if i else 'getattr(self, "' + name + '", NOTHING)' + ) + fragment = ( + "%s={%s!r}" % (name, accessor) + if r == repr + else "%s={%s_repr(%s)}" % (name, name, accessor) + ) + attribute_fragments.append(fragment) + repr_fragment = ", ".join(attribute_fragments) + + if ns is None: + cls_name_fragment = '{self.__class__.__qualname__.rsplit(">.", 1)[-1]}' + else: + cls_name_fragment = ns + ".{self.__class__.__name__}" + + lines = [ + "def __repr__(self):", + " try:", + " already_repring = _compat.repr_context.already_repring", + " except AttributeError:", + " already_repring = {id(self),}", + " _compat.repr_context.already_repring = already_repring", + " else:", + " if id(self) in already_repring:", + " return '...'", + " else:", + " already_repring.add(id(self))", + " try:", + f" return f'{cls_name_fragment}({repr_fragment})'", + " finally:", + " already_repring.remove(id(self))", + ] + + return _make_method( + "__repr__", "\n".join(lines), unique_filename, globs=globs + ) + + +def _add_repr(cls, ns=None, attrs=None): + """ + Add a repr method to *cls*. + """ + if attrs is None: + attrs = cls.__attrs_attrs__ + + cls.__repr__ = _make_repr(attrs, ns, cls) + return cls + + +def fields(cls): + """ + Return the tuple of *attrs* attributes for a class. + + The tuple also allows accessing the fields by their names (see below for + examples). + + :param type cls: Class to introspect. + + :raise TypeError: If *cls* is not a class. + :raise attrs.exceptions.NotAnAttrsClassError: If *cls* is not an *attrs* + class. + + :rtype: tuple (with name accessors) of `attrs.Attribute` + + .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields + by name. + .. versionchanged:: 23.1.0 Add support for generic classes. + """ + generic_base = get_generic_base(cls) + + if generic_base is None and not isinstance(cls, type): + msg = "Passed object must be a class." + raise TypeError(msg) + + attrs = getattr(cls, "__attrs_attrs__", None) + + if attrs is None: + if generic_base is not None: + attrs = getattr(generic_base, "__attrs_attrs__", None) + if attrs is not None: + # Even though this is global state, stick it on here to speed + # it up. We rely on `cls` being cached for this to be + # efficient. + cls.__attrs_attrs__ = attrs + return attrs + msg = f"{cls!r} is not an attrs-decorated class." + raise NotAnAttrsClassError(msg) + + return attrs + + +def fields_dict(cls): + """ + Return an ordered dictionary of *attrs* attributes for a class, whose + keys are the attribute names. + + :param type cls: Class to introspect. + + :raise TypeError: If *cls* is not a class. + :raise attrs.exceptions.NotAnAttrsClassError: If *cls* is not an *attrs* + class. + + :rtype: dict + + .. versionadded:: 18.1.0 + """ + if not isinstance(cls, type): + msg = "Passed object must be a class." + raise TypeError(msg) + attrs = getattr(cls, "__attrs_attrs__", None) + if attrs is None: + msg = f"{cls!r} is not an attrs-decorated class." + raise NotAnAttrsClassError(msg) + return {a.name: a for a in attrs} + + +def validate(inst): + """ + Validate all attributes on *inst* that have a validator. + + Leaves all exceptions through. + + :param inst: Instance of a class with *attrs* attributes. + """ + if _config._run_validators is False: + return + + for a in fields(inst.__class__): + v = a.validator + if v is not None: + v(inst, a, getattr(inst, a.name)) + + +def _is_slot_cls(cls): + return "__slots__" in cls.__dict__ + + +def _is_slot_attr(a_name, base_attr_map): + """ + Check if the attribute name comes from a slot class. + """ + return a_name in base_attr_map and _is_slot_cls(base_attr_map[a_name]) + + +def _make_init( + cls, + attrs, + pre_init, + pre_init_has_args, + post_init, + frozen, + slots, + cache_hash, + base_attr_map, + is_exc, + cls_on_setattr, + attrs_init, +): + has_cls_on_setattr = ( + cls_on_setattr is not None and cls_on_setattr is not setters.NO_OP + ) + + if frozen and has_cls_on_setattr: + msg = "Frozen classes can't use on_setattr." + raise ValueError(msg) + + needs_cached_setattr = cache_hash or frozen + filtered_attrs = [] + attr_dict = {} + for a in attrs: + if not a.init and a.default is NOTHING: + continue + + filtered_attrs.append(a) + attr_dict[a.name] = a + + if a.on_setattr is not None: + if frozen is True: + msg = "Frozen classes can't use on_setattr." + raise ValueError(msg) + + needs_cached_setattr = True + elif has_cls_on_setattr and a.on_setattr is not setters.NO_OP: + needs_cached_setattr = True + + unique_filename = _generate_unique_filename(cls, "init") + + script, globs, annotations = _attrs_to_init_script( + filtered_attrs, + frozen, + slots, + pre_init, + pre_init_has_args, + post_init, + cache_hash, + base_attr_map, + is_exc, + needs_cached_setattr, + has_cls_on_setattr, + attrs_init, + ) + if cls.__module__ in sys.modules: + # This makes typing.get_type_hints(CLS.__init__) resolve string types. + globs.update(sys.modules[cls.__module__].__dict__) + + globs.update({"NOTHING": NOTHING, "attr_dict": attr_dict}) + + if needs_cached_setattr: + # Save the lookup overhead in __init__ if we need to circumvent + # setattr hooks. + globs["_cached_setattr_get"] = _obj_setattr.__get__ + + init = _make_method( + "__attrs_init__" if attrs_init else "__init__", + script, + unique_filename, + globs, + ) + init.__annotations__ = annotations + + return init + + +def _setattr(attr_name, value_var, has_on_setattr): + """ + Use the cached object.setattr to set *attr_name* to *value_var*. + """ + return f"_setattr('{attr_name}', {value_var})" + + +def _setattr_with_converter(attr_name, value_var, has_on_setattr): + """ + Use the cached object.setattr to set *attr_name* to *value_var*, but run + its converter first. + """ + return "_setattr('%s', %s(%s))" % ( + attr_name, + _init_converter_pat % (attr_name,), + value_var, + ) + + +def _assign(attr_name, value, has_on_setattr): + """ + Unless *attr_name* has an on_setattr hook, use normal assignment. Otherwise + relegate to _setattr. + """ + if has_on_setattr: + return _setattr(attr_name, value, True) + + return f"self.{attr_name} = {value}" + + +def _assign_with_converter(attr_name, value_var, has_on_setattr): + """ + Unless *attr_name* has an on_setattr hook, use normal assignment after + conversion. Otherwise relegate to _setattr_with_converter. + """ + if has_on_setattr: + return _setattr_with_converter(attr_name, value_var, True) + + return "self.%s = %s(%s)" % ( + attr_name, + _init_converter_pat % (attr_name,), + value_var, + ) + + +def _attrs_to_init_script( + attrs, + frozen, + slots, + pre_init, + pre_init_has_args, + post_init, + cache_hash, + base_attr_map, + is_exc, + needs_cached_setattr, + has_cls_on_setattr, + attrs_init, +): + """ + Return a script of an initializer for *attrs* and a dict of globals. + + The globals are expected by the generated script. + + If *frozen* is True, we cannot set the attributes directly so we use + a cached ``object.__setattr__``. + """ + lines = [] + if pre_init: + lines.append("self.__attrs_pre_init__()") + + if needs_cached_setattr: + lines.append( + # Circumvent the __setattr__ descriptor to save one lookup per + # assignment. + # Note _setattr will be used again below if cache_hash is True + "_setattr = _cached_setattr_get(self)" + ) + + if frozen is True: + if slots is True: + fmt_setter = _setattr + fmt_setter_with_converter = _setattr_with_converter + else: + # Dict frozen classes assign directly to __dict__. + # But only if the attribute doesn't come from an ancestor slot + # class. + # Note _inst_dict will be used again below if cache_hash is True + lines.append("_inst_dict = self.__dict__") + + def fmt_setter(attr_name, value_var, has_on_setattr): + if _is_slot_attr(attr_name, base_attr_map): + return _setattr(attr_name, value_var, has_on_setattr) + + return f"_inst_dict['{attr_name}'] = {value_var}" + + def fmt_setter_with_converter( + attr_name, value_var, has_on_setattr + ): + if has_on_setattr or _is_slot_attr(attr_name, base_attr_map): + return _setattr_with_converter( + attr_name, value_var, has_on_setattr + ) + + return "_inst_dict['%s'] = %s(%s)" % ( + attr_name, + _init_converter_pat % (attr_name,), + value_var, + ) + + else: + # Not frozen. + fmt_setter = _assign + fmt_setter_with_converter = _assign_with_converter + + args = [] + kw_only_args = [] + attrs_to_validate = [] + + # This is a dictionary of names to validator and converter callables. + # Injecting this into __init__ globals lets us avoid lookups. + names_for_globals = {} + annotations = {"return": None} + + for a in attrs: + if a.validator: + attrs_to_validate.append(a) + + attr_name = a.name + has_on_setattr = a.on_setattr is not None or ( + a.on_setattr is not setters.NO_OP and has_cls_on_setattr + ) + # a.alias is set to maybe-mangled attr_name in _ClassBuilder if not + # explicitly provided + arg_name = a.alias + + has_factory = isinstance(a.default, Factory) + maybe_self = "self" if has_factory and a.default.takes_self else "" + + if a.init is False: + if has_factory: + init_factory_name = _init_factory_pat % (a.name,) + if a.converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, + init_factory_name + f"({maybe_self})", + has_on_setattr, + ) + ) + conv_name = _init_converter_pat % (a.name,) + names_for_globals[conv_name] = a.converter + else: + lines.append( + fmt_setter( + attr_name, + init_factory_name + f"({maybe_self})", + has_on_setattr, + ) + ) + names_for_globals[init_factory_name] = a.default.factory + elif a.converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, + f"attr_dict['{attr_name}'].default", + has_on_setattr, + ) + ) + conv_name = _init_converter_pat % (a.name,) + names_for_globals[conv_name] = a.converter + else: + lines.append( + fmt_setter( + attr_name, + f"attr_dict['{attr_name}'].default", + has_on_setattr, + ) + ) + elif a.default is not NOTHING and not has_factory: + arg = f"{arg_name}=attr_dict['{attr_name}'].default" + if a.kw_only: + kw_only_args.append(arg) + else: + args.append(arg) + + if a.converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, arg_name, has_on_setattr + ) + ) + names_for_globals[ + _init_converter_pat % (a.name,) + ] = a.converter + else: + lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) + + elif has_factory: + arg = f"{arg_name}=NOTHING" + if a.kw_only: + kw_only_args.append(arg) + else: + args.append(arg) + lines.append(f"if {arg_name} is not NOTHING:") + + init_factory_name = _init_factory_pat % (a.name,) + if a.converter is not None: + lines.append( + " " + + fmt_setter_with_converter( + attr_name, arg_name, has_on_setattr + ) + ) + lines.append("else:") + lines.append( + " " + + fmt_setter_with_converter( + attr_name, + init_factory_name + "(" + maybe_self + ")", + has_on_setattr, + ) + ) + names_for_globals[ + _init_converter_pat % (a.name,) + ] = a.converter + else: + lines.append( + " " + fmt_setter(attr_name, arg_name, has_on_setattr) + ) + lines.append("else:") + lines.append( + " " + + fmt_setter( + attr_name, + init_factory_name + "(" + maybe_self + ")", + has_on_setattr, + ) + ) + names_for_globals[init_factory_name] = a.default.factory + else: + if a.kw_only: + kw_only_args.append(arg_name) + else: + args.append(arg_name) + + if a.converter is not None: + lines.append( + fmt_setter_with_converter( + attr_name, arg_name, has_on_setattr + ) + ) + names_for_globals[ + _init_converter_pat % (a.name,) + ] = a.converter + else: + lines.append(fmt_setter(attr_name, arg_name, has_on_setattr)) + + if a.init is True: + if a.type is not None and a.converter is None: + annotations[arg_name] = a.type + elif a.converter is not None: + # Try to get the type from the converter. + t = _AnnotationExtractor(a.converter).get_first_param_type() + if t: + annotations[arg_name] = t + + if attrs_to_validate: # we can skip this if there are no validators. + names_for_globals["_config"] = _config + lines.append("if _config._run_validators is True:") + for a in attrs_to_validate: + val_name = "__attr_validator_" + a.name + attr_name = "__attr_" + a.name + lines.append(f" {val_name}(self, {attr_name}, self.{a.name})") + names_for_globals[val_name] = a.validator + names_for_globals[attr_name] = a + + if post_init: + lines.append("self.__attrs_post_init__()") + + # because this is set only after __attrs_post_init__ is called, a crash + # will result if post-init tries to access the hash code. This seemed + # preferable to setting this beforehand, in which case alteration to + # field values during post-init combined with post-init accessing the + # hash code would result in silent bugs. + if cache_hash: + if frozen: + if slots: # noqa: SIM108 + # if frozen and slots, then _setattr defined above + init_hash_cache = "_setattr('%s', %s)" + else: + # if frozen and not slots, then _inst_dict defined above + init_hash_cache = "_inst_dict['%s'] = %s" + else: + init_hash_cache = "self.%s = %s" + lines.append(init_hash_cache % (_hash_cache_field, "None")) + + # For exceptions we rely on BaseException.__init__ for proper + # initialization. + if is_exc: + vals = ",".join(f"self.{a.name}" for a in attrs if a.init) + + lines.append(f"BaseException.__init__(self, {vals})") + + args = ", ".join(args) + pre_init_args = args + if kw_only_args: + args += "%s*, %s" % ( + ", " if args else "", # leading comma + ", ".join(kw_only_args), # kw_only args + ) + pre_init_kw_only_args = ", ".join( + ["%s=%s" % (kw_arg, kw_arg) for kw_arg in kw_only_args] + ) + pre_init_args += ( + ", " if pre_init_args else "" + ) # handle only kwargs and no regular args + pre_init_args += pre_init_kw_only_args + + if pre_init and pre_init_has_args: + # If pre init method has arguments, pass same arguments as `__init__` + lines[0] = "self.__attrs_pre_init__(%s)" % pre_init_args + + return ( + "def %s(self, %s):\n %s\n" + % ( + ("__attrs_init__" if attrs_init else "__init__"), + args, + "\n ".join(lines) if lines else "pass", + ), + names_for_globals, + annotations, + ) + + +def _default_init_alias_for(name: str) -> str: + """ + The default __init__ parameter name for a field. + + This performs private-name adjustment via leading-unscore stripping, + and is the default value of Attribute.alias if not provided. + """ + + return name.lstrip("_") + + +class Attribute: + """ + *Read-only* representation of an attribute. + + .. warning:: + + You should never instantiate this class yourself. + + The class has *all* arguments of `attr.ib` (except for ``factory`` + which is only syntactic sugar for ``default=Factory(...)`` plus the + following: + + - ``name`` (`str`): The name of the attribute. + - ``alias`` (`str`): The __init__ parameter name of the attribute, after + any explicit overrides and default private-attribute-name handling. + - ``inherited`` (`bool`): Whether or not that attribute has been inherited + from a base class. + - ``eq_key`` and ``order_key`` (`typing.Callable` or `None`): The callables + that are used for comparing and ordering objects by this attribute, + respectively. These are set by passing a callable to `attr.ib`'s ``eq``, + ``order``, or ``cmp`` arguments. See also :ref:`comparison customization + `. + + Instances of this class are frequently used for introspection purposes + like: + + - `fields` returns a tuple of them. + - Validators get them passed as the first argument. + - The :ref:`field transformer ` hook receives a list of + them. + - The ``alias`` property exposes the __init__ parameter name of the field, + with any overrides and default private-attribute handling applied. + + + .. versionadded:: 20.1.0 *inherited* + .. versionadded:: 20.1.0 *on_setattr* + .. versionchanged:: 20.2.0 *inherited* is not taken into account for + equality checks and hashing anymore. + .. versionadded:: 21.1.0 *eq_key* and *order_key* + .. versionadded:: 22.2.0 *alias* + + For the full version history of the fields, see `attr.ib`. + """ + + __slots__ = ( + "name", + "default", + "validator", + "repr", + "eq", + "eq_key", + "order", + "order_key", + "hash", + "init", + "metadata", + "type", + "converter", + "kw_only", + "inherited", + "on_setattr", + "alias", + ) + + def __init__( + self, + name, + default, + validator, + repr, + cmp, # XXX: unused, remove along with other cmp code. + hash, + init, + inherited, + metadata=None, + type=None, + converter=None, + kw_only=False, + eq=None, + eq_key=None, + order=None, + order_key=None, + on_setattr=None, + alias=None, + ): + eq, eq_key, order, order_key = _determine_attrib_eq_order( + cmp, eq_key or eq, order_key or order, True + ) + + # Cache this descriptor here to speed things up later. + bound_setattr = _obj_setattr.__get__(self) + + # Despite the big red warning, people *do* instantiate `Attribute` + # themselves. + bound_setattr("name", name) + bound_setattr("default", default) + bound_setattr("validator", validator) + bound_setattr("repr", repr) + bound_setattr("eq", eq) + bound_setattr("eq_key", eq_key) + bound_setattr("order", order) + bound_setattr("order_key", order_key) + bound_setattr("hash", hash) + bound_setattr("init", init) + bound_setattr("converter", converter) + bound_setattr( + "metadata", + ( + types.MappingProxyType(dict(metadata)) # Shallow copy + if metadata + else _empty_metadata_singleton + ), + ) + bound_setattr("type", type) + bound_setattr("kw_only", kw_only) + bound_setattr("inherited", inherited) + bound_setattr("on_setattr", on_setattr) + bound_setattr("alias", alias) + + def __setattr__(self, name, value): + raise FrozenInstanceError() + + @classmethod + def from_counting_attr(cls, name, ca, type=None): + # type holds the annotated value. deal with conflicts: + if type is None: + type = ca.type + elif ca.type is not None: + msg = "Type annotation and type argument cannot both be present" + raise ValueError(msg) + inst_dict = { + k: getattr(ca, k) + for k in Attribute.__slots__ + if k + not in ( + "name", + "validator", + "default", + "type", + "inherited", + ) # exclude methods and deprecated alias + } + return cls( + name=name, + validator=ca._validator, + default=ca._default, + type=type, + cmp=None, + inherited=False, + **inst_dict, + ) + + # Don't use attrs.evolve since fields(Attribute) doesn't work + def evolve(self, **changes): + """ + Copy *self* and apply *changes*. + + This works similarly to `attrs.evolve` but that function does not work + with `Attribute`. + + It is mainly meant to be used for `transform-fields`. + + .. versionadded:: 20.3.0 + """ + new = copy.copy(self) + + new._setattrs(changes.items()) + + return new + + # Don't use _add_pickle since fields(Attribute) doesn't work + def __getstate__(self): + """ + Play nice with pickle. + """ + return tuple( + getattr(self, name) if name != "metadata" else dict(self.metadata) + for name in self.__slots__ + ) + + def __setstate__(self, state): + """ + Play nice with pickle. + """ + self._setattrs(zip(self.__slots__, state)) + + def _setattrs(self, name_values_pairs): + bound_setattr = _obj_setattr.__get__(self) + for name, value in name_values_pairs: + if name != "metadata": + bound_setattr(name, value) + else: + bound_setattr( + name, + types.MappingProxyType(dict(value)) + if value + else _empty_metadata_singleton, + ) + + +_a = [ + Attribute( + name=name, + default=NOTHING, + validator=None, + repr=True, + cmp=None, + eq=True, + order=False, + hash=(name != "metadata"), + init=True, + inherited=False, + alias=_default_init_alias_for(name), + ) + for name in Attribute.__slots__ +] + +Attribute = _add_hash( + _add_eq( + _add_repr(Attribute, attrs=_a), + attrs=[a for a in _a if a.name != "inherited"], + ), + attrs=[a for a in _a if a.hash and a.name != "inherited"], +) + + +class _CountingAttr: + """ + Intermediate representation of attributes that uses a counter to preserve + the order in which the attributes have been defined. + + *Internal* data structure of the attrs library. Running into is most + likely the result of a bug like a forgotten `@attr.s` decorator. + """ + + __slots__ = ( + "counter", + "_default", + "repr", + "eq", + "eq_key", + "order", + "order_key", + "hash", + "init", + "metadata", + "_validator", + "converter", + "type", + "kw_only", + "on_setattr", + "alias", + ) + __attrs_attrs__ = ( + *tuple( + Attribute( + name=name, + alias=_default_init_alias_for(name), + default=NOTHING, + validator=None, + repr=True, + cmp=None, + hash=True, + init=True, + kw_only=False, + eq=True, + eq_key=None, + order=False, + order_key=None, + inherited=False, + on_setattr=None, + ) + for name in ( + "counter", + "_default", + "repr", + "eq", + "order", + "hash", + "init", + "on_setattr", + "alias", + ) + ), + Attribute( + name="metadata", + alias="metadata", + default=None, + validator=None, + repr=True, + cmp=None, + hash=False, + init=True, + kw_only=False, + eq=True, + eq_key=None, + order=False, + order_key=None, + inherited=False, + on_setattr=None, + ), + ) + cls_counter = 0 + + def __init__( + self, + default, + validator, + repr, + cmp, + hash, + init, + converter, + metadata, + type, + kw_only, + eq, + eq_key, + order, + order_key, + on_setattr, + alias, + ): + _CountingAttr.cls_counter += 1 + self.counter = _CountingAttr.cls_counter + self._default = default + self._validator = validator + self.converter = converter + self.repr = repr + self.eq = eq + self.eq_key = eq_key + self.order = order + self.order_key = order_key + self.hash = hash + self.init = init + self.metadata = metadata + self.type = type + self.kw_only = kw_only + self.on_setattr = on_setattr + self.alias = alias + + def validator(self, meth): + """ + Decorator that adds *meth* to the list of validators. + + Returns *meth* unchanged. + + .. versionadded:: 17.1.0 + """ + if self._validator is None: + self._validator = meth + else: + self._validator = and_(self._validator, meth) + return meth + + def default(self, meth): + """ + Decorator that allows to set the default for an attribute. + + Returns *meth* unchanged. + + :raises DefaultAlreadySetError: If default has been set before. + + .. versionadded:: 17.1.0 + """ + if self._default is not NOTHING: + raise DefaultAlreadySetError() + + self._default = Factory(meth, takes_self=True) + + return meth + + +_CountingAttr = _add_eq(_add_repr(_CountingAttr)) + + +class Factory: + """ + Stores a factory callable. + + If passed as the default value to `attrs.field`, the factory is used to + generate a new value. + + :param callable factory: A callable that takes either none or exactly one + mandatory positional argument depending on *takes_self*. + :param bool takes_self: Pass the partially initialized instance that is + being initialized as a positional argument. + + .. versionadded:: 17.1.0 *takes_self* + """ + + __slots__ = ("factory", "takes_self") + + def __init__(self, factory, takes_self=False): + self.factory = factory + self.takes_self = takes_self + + def __getstate__(self): + """ + Play nice with pickle. + """ + return tuple(getattr(self, name) for name in self.__slots__) + + def __setstate__(self, state): + """ + Play nice with pickle. + """ + for name, value in zip(self.__slots__, state): + setattr(self, name, value) + + +_f = [ + Attribute( + name=name, + default=NOTHING, + validator=None, + repr=True, + cmp=None, + eq=True, + order=False, + hash=True, + init=True, + inherited=False, + ) + for name in Factory.__slots__ +] + +Factory = _add_hash(_add_eq(_add_repr(Factory, attrs=_f), attrs=_f), attrs=_f) + + +def make_class( + name, attrs, bases=(object,), class_body=None, **attributes_arguments +): + r""" + A quick way to create a new class called *name* with *attrs*. + + :param str name: The name for the new class. + + :param attrs: A list of names or a dictionary of mappings of names to + `attr.ib`\ s / `attrs.field`\ s. + + The order is deduced from the order of the names or attributes inside + *attrs*. Otherwise the order of the definition of the attributes is + used. + :type attrs: `list` or `dict` + + :param tuple bases: Classes that the new class will subclass. + + :param dict class_body: An optional dictionary of class attributes for the new class. + + :param attributes_arguments: Passed unmodified to `attr.s`. + + :return: A new class with *attrs*. + :rtype: type + + .. versionadded:: 17.1.0 *bases* + .. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained. + .. versionchanged:: 23.2.0 *class_body* + """ + if isinstance(attrs, dict): + cls_dict = attrs + elif isinstance(attrs, (list, tuple)): + cls_dict = {a: attrib() for a in attrs} + else: + msg = "attrs argument must be a dict or a list." + raise TypeError(msg) + + pre_init = cls_dict.pop("__attrs_pre_init__", None) + post_init = cls_dict.pop("__attrs_post_init__", None) + user_init = cls_dict.pop("__init__", None) + + body = {} + if class_body is not None: + body.update(class_body) + if pre_init is not None: + body["__attrs_pre_init__"] = pre_init + if post_init is not None: + body["__attrs_post_init__"] = post_init + if user_init is not None: + body["__init__"] = user_init + + type_ = types.new_class(name, bases, {}, lambda ns: ns.update(body)) + + # For pickling to work, the __module__ variable needs to be set to the + # frame where the class is created. Bypass this step in environments where + # sys._getframe is not defined (Jython for example) or sys._getframe is not + # defined for arguments greater than 0 (IronPython). + with contextlib.suppress(AttributeError, ValueError): + type_.__module__ = sys._getframe(1).f_globals.get( + "__name__", "__main__" + ) + + # We do it here for proper warnings with meaningful stacklevel. + cmp = attributes_arguments.pop("cmp", None) + ( + attributes_arguments["eq"], + attributes_arguments["order"], + ) = _determine_attrs_eq_order( + cmp, + attributes_arguments.get("eq"), + attributes_arguments.get("order"), + True, + ) + + return _attrs(these=cls_dict, **attributes_arguments)(type_) + + +# These are required by within this module so we define them here and merely +# import into .validators / .converters. + + +@attrs(slots=True, hash=True) +class _AndValidator: + """ + Compose many validators to a single one. + """ + + _validators = attrib() + + def __call__(self, inst, attr, value): + for v in self._validators: + v(inst, attr, value) + + +def and_(*validators): + """ + A validator that composes multiple validators into one. + + When called on a value, it runs all wrapped validators. + + :param callables validators: Arbitrary number of validators. + + .. versionadded:: 17.1.0 + """ + vals = [] + for validator in validators: + vals.extend( + validator._validators + if isinstance(validator, _AndValidator) + else [validator] + ) + + return _AndValidator(tuple(vals)) + + +def pipe(*converters): + """ + A converter that composes multiple converters into one. + + When called on a value, it runs all wrapped converters, returning the + *last* value. + + Type annotations will be inferred from the wrapped converters', if + they have any. + + :param callables converters: Arbitrary number of converters. + + .. versionadded:: 20.1.0 + """ + + def pipe_converter(val): + for converter in converters: + val = converter(val) + + return val + + if not converters: + # If the converter list is empty, pipe_converter is the identity. + A = typing.TypeVar("A") + pipe_converter.__annotations__ = {"val": A, "return": A} + else: + # Get parameter type from first converter. + t = _AnnotationExtractor(converters[0]).get_first_param_type() + if t: + pipe_converter.__annotations__["val"] = t + + # Get return type from last converter. + rt = _AnnotationExtractor(converters[-1]).get_return_type() + if rt: + pipe_converter.__annotations__["return"] = rt + + return pipe_converter diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/_next_gen.py b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_next_gen.py new file mode 100644 index 000000000..1fb9f259b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_next_gen.py @@ -0,0 +1,229 @@ +# SPDX-License-Identifier: MIT + +""" +These are keyword-only APIs that call `attr.s` and `attr.ib` with different +default values. +""" + + +from functools import partial + +from . import setters +from ._funcs import asdict as _asdict +from ._funcs import astuple as _astuple +from ._make import ( + NOTHING, + _frozen_setattrs, + _ng_default_on_setattr, + attrib, + attrs, +) +from .exceptions import UnannotatedAttributeError + + +def define( + maybe_cls=None, + *, + these=None, + repr=None, + unsafe_hash=None, + hash=None, + init=None, + slots=True, + frozen=False, + weakref_slot=True, + str=False, + auto_attribs=None, + kw_only=False, + cache_hash=False, + auto_exc=True, + eq=None, + order=False, + auto_detect=True, + getstate_setstate=None, + on_setattr=None, + field_transformer=None, + match_args=True, +): + r""" + Define an *attrs* class. + + Differences to the classic `attr.s` that it uses underneath: + + - Automatically detect whether or not *auto_attribs* should be `True` (c.f. + *auto_attribs* parameter). + - Converters and validators run when attributes are set by default -- if + *frozen* is `False`. + - *slots=True* + + .. caution:: + + Usually this has only upsides and few visible effects in everyday + programming. But it *can* lead to some surprising behaviors, so please + make sure to read :term:`slotted classes`. + - *auto_exc=True* + - *auto_detect=True* + - *order=False* + - Some options that were only relevant on Python 2 or were kept around for + backwards-compatibility have been removed. + + Please note that these are all defaults and you can change them as you + wish. + + :param Optional[bool] auto_attribs: If set to `True` or `False`, it behaves + exactly like `attr.s`. If left `None`, `attr.s` will try to guess: + + 1. If any attributes are annotated and no unannotated `attrs.fields`\ s + are found, it assumes *auto_attribs=True*. + 2. Otherwise it assumes *auto_attribs=False* and tries to collect + `attrs.fields`\ s. + + For now, please refer to `attr.s` for the rest of the parameters. + + .. versionadded:: 20.1.0 + .. versionchanged:: 21.3.0 Converters are also run ``on_setattr``. + .. versionadded:: 22.2.0 + *unsafe_hash* as an alias for *hash* (for :pep:`681` compliance). + """ + + def do_it(cls, auto_attribs): + return attrs( + maybe_cls=cls, + these=these, + repr=repr, + hash=hash, + unsafe_hash=unsafe_hash, + init=init, + slots=slots, + frozen=frozen, + weakref_slot=weakref_slot, + str=str, + auto_attribs=auto_attribs, + kw_only=kw_only, + cache_hash=cache_hash, + auto_exc=auto_exc, + eq=eq, + order=order, + auto_detect=auto_detect, + collect_by_mro=True, + getstate_setstate=getstate_setstate, + on_setattr=on_setattr, + field_transformer=field_transformer, + match_args=match_args, + ) + + def wrap(cls): + """ + Making this a wrapper ensures this code runs during class creation. + + We also ensure that frozen-ness of classes is inherited. + """ + nonlocal frozen, on_setattr + + had_on_setattr = on_setattr not in (None, setters.NO_OP) + + # By default, mutable classes convert & validate on setattr. + if frozen is False and on_setattr is None: + on_setattr = _ng_default_on_setattr + + # However, if we subclass a frozen class, we inherit the immutability + # and disable on_setattr. + for base_cls in cls.__bases__: + if base_cls.__setattr__ is _frozen_setattrs: + if had_on_setattr: + msg = "Frozen classes can't use on_setattr (frozen-ness was inherited)." + raise ValueError(msg) + + on_setattr = setters.NO_OP + break + + if auto_attribs is not None: + return do_it(cls, auto_attribs) + + try: + return do_it(cls, True) + except UnannotatedAttributeError: + return do_it(cls, False) + + # maybe_cls's type depends on the usage of the decorator. It's a class + # if it's used as `@attrs` but ``None`` if used as `@attrs()`. + if maybe_cls is None: + return wrap + + return wrap(maybe_cls) + + +mutable = define +frozen = partial(define, frozen=True, on_setattr=None) + + +def field( + *, + default=NOTHING, + validator=None, + repr=True, + hash=None, + init=True, + metadata=None, + type=None, + converter=None, + factory=None, + kw_only=False, + eq=None, + order=None, + on_setattr=None, + alias=None, +): + """ + Identical to `attr.ib`, except keyword-only and with some arguments + removed. + + .. versionadded:: 23.1.0 + The *type* parameter has been re-added; mostly for `attrs.make_class`. + Please note that type checkers ignore this metadata. + .. versionadded:: 20.1.0 + """ + return attrib( + default=default, + validator=validator, + repr=repr, + hash=hash, + init=init, + metadata=metadata, + type=type, + converter=converter, + factory=factory, + kw_only=kw_only, + eq=eq, + order=order, + on_setattr=on_setattr, + alias=alias, + ) + + +def asdict(inst, *, recurse=True, filter=None, value_serializer=None): + """ + Same as `attr.asdict`, except that collections types are always retained + and dict is always used as *dict_factory*. + + .. versionadded:: 21.3.0 + """ + return _asdict( + inst=inst, + recurse=recurse, + filter=filter, + value_serializer=value_serializer, + retain_collection_types=True, + ) + + +def astuple(inst, *, recurse=True, filter=None): + """ + Same as `attr.astuple`, except that collections types are always retained + and `tuple` is always used as the *tuple_factory*. + + .. versionadded:: 21.3.0 + """ + return _astuple( + inst=inst, recurse=recurse, filter=filter, retain_collection_types=True + ) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/_typing_compat.pyi b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_typing_compat.pyi new file mode 100644 index 000000000..ca7b71e90 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_typing_compat.pyi @@ -0,0 +1,15 @@ +from typing import Any, ClassVar, Protocol + +# MYPY is a special constant in mypy which works the same way as `TYPE_CHECKING`. +MYPY = False + +if MYPY: + # A protocol to be able to statically accept an attrs class. + class AttrsInstance_(Protocol): + __attrs_attrs__: ClassVar[Any] + +else: + # For type checkers without plug-in support use an empty protocol that + # will (hopefully) be combined into a union. + class AttrsInstance_(Protocol): + pass diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/_version_info.py b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_version_info.py new file mode 100644 index 000000000..51a1312f9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_version_info.py @@ -0,0 +1,86 @@ +# SPDX-License-Identifier: MIT + + +from functools import total_ordering + +from ._funcs import astuple +from ._make import attrib, attrs + + +@total_ordering +@attrs(eq=False, order=False, slots=True, frozen=True) +class VersionInfo: + """ + A version object that can be compared to tuple of length 1--4: + + >>> attr.VersionInfo(19, 1, 0, "final") <= (19, 2) + True + >>> attr.VersionInfo(19, 1, 0, "final") < (19, 1, 1) + True + >>> vi = attr.VersionInfo(19, 2, 0, "final") + >>> vi < (19, 1, 1) + False + >>> vi < (19,) + False + >>> vi == (19, 2,) + True + >>> vi == (19, 2, 1) + False + + .. versionadded:: 19.2 + """ + + year = attrib(type=int) + minor = attrib(type=int) + micro = attrib(type=int) + releaselevel = attrib(type=str) + + @classmethod + def _from_version_string(cls, s): + """ + Parse *s* and return a _VersionInfo. + """ + v = s.split(".") + if len(v) == 3: + v.append("final") + + return cls( + year=int(v[0]), minor=int(v[1]), micro=int(v[2]), releaselevel=v[3] + ) + + def _ensure_tuple(self, other): + """ + Ensure *other* is a tuple of a valid length. + + Returns a possibly transformed *other* and ourselves as a tuple of + the same length as *other*. + """ + + if self.__class__ is other.__class__: + other = astuple(other) + + if not isinstance(other, tuple): + raise NotImplementedError + + if not (1 <= len(other) <= 4): + raise NotImplementedError + + return astuple(self)[: len(other)], other + + def __eq__(self, other): + try: + us, them = self._ensure_tuple(other) + except NotImplementedError: + return NotImplemented + + return us == them + + def __lt__(self, other): + try: + us, them = self._ensure_tuple(other) + except NotImplementedError: + return NotImplemented + + # Since alphabetically "dev0" < "final" < "post1" < "post2", we don't + # have to do anything special with releaselevel for now. + return us < them diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/_version_info.pyi b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_version_info.pyi new file mode 100644 index 000000000..45ced0863 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/_version_info.pyi @@ -0,0 +1,9 @@ +class VersionInfo: + @property + def year(self) -> int: ... + @property + def minor(self) -> int: ... + @property + def micro(self) -> int: ... + @property + def releaselevel(self) -> str: ... diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/converters.py b/inbm/venv-3.11/lib/python3.11/site-packages/attr/converters.py new file mode 100644 index 000000000..2bf4c902a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/converters.py @@ -0,0 +1,144 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly useful converters. +""" + + +import typing + +from ._compat import _AnnotationExtractor +from ._make import NOTHING, Factory, pipe + + +__all__ = [ + "default_if_none", + "optional", + "pipe", + "to_bool", +] + + +def optional(converter): + """ + A converter that allows an attribute to be optional. An optional attribute + is one which can be set to ``None``. + + Type annotations will be inferred from the wrapped converter's, if it + has any. + + :param callable converter: the converter that is used for non-``None`` + values. + + .. versionadded:: 17.1.0 + """ + + def optional_converter(val): + if val is None: + return None + return converter(val) + + xtr = _AnnotationExtractor(converter) + + t = xtr.get_first_param_type() + if t: + optional_converter.__annotations__["val"] = typing.Optional[t] + + rt = xtr.get_return_type() + if rt: + optional_converter.__annotations__["return"] = typing.Optional[rt] + + return optional_converter + + +def default_if_none(default=NOTHING, factory=None): + """ + A converter that allows to replace ``None`` values by *default* or the + result of *factory*. + + :param default: Value to be used if ``None`` is passed. Passing an instance + of `attrs.Factory` is supported, however the ``takes_self`` option + is *not*. + :param callable factory: A callable that takes no parameters whose result + is used if ``None`` is passed. + + :raises TypeError: If **neither** *default* or *factory* is passed. + :raises TypeError: If **both** *default* and *factory* are passed. + :raises ValueError: If an instance of `attrs.Factory` is passed with + ``takes_self=True``. + + .. versionadded:: 18.2.0 + """ + if default is NOTHING and factory is None: + msg = "Must pass either `default` or `factory`." + raise TypeError(msg) + + if default is not NOTHING and factory is not None: + msg = "Must pass either `default` or `factory` but not both." + raise TypeError(msg) + + if factory is not None: + default = Factory(factory) + + if isinstance(default, Factory): + if default.takes_self: + msg = "`takes_self` is not supported by default_if_none." + raise ValueError(msg) + + def default_if_none_converter(val): + if val is not None: + return val + + return default.factory() + + else: + + def default_if_none_converter(val): + if val is not None: + return val + + return default + + return default_if_none_converter + + +def to_bool(val): + """ + Convert "boolean" strings (e.g., from env. vars.) to real booleans. + + Values mapping to :code:`True`: + + - :code:`True` + - :code:`"true"` / :code:`"t"` + - :code:`"yes"` / :code:`"y"` + - :code:`"on"` + - :code:`"1"` + - :code:`1` + + Values mapping to :code:`False`: + + - :code:`False` + - :code:`"false"` / :code:`"f"` + - :code:`"no"` / :code:`"n"` + - :code:`"off"` + - :code:`"0"` + - :code:`0` + + :raises ValueError: for any other value. + + .. versionadded:: 21.3.0 + """ + if isinstance(val, str): + val = val.lower() + truthy = {True, "true", "t", "yes", "y", "on", "1", 1} + falsy = {False, "false", "f", "no", "n", "off", "0", 0} + try: + if val in truthy: + return True + if val in falsy: + return False + except TypeError: + # Raised when "val" is not hashable (e.g., lists) + pass + msg = f"Cannot convert value to bool: {val}" + raise ValueError(msg) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/converters.pyi b/inbm/venv-3.11/lib/python3.11/site-packages/attr/converters.pyi new file mode 100644 index 000000000..5abb49f6d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/converters.pyi @@ -0,0 +1,13 @@ +from typing import Callable, TypeVar, overload + +from . import _ConverterType + +_T = TypeVar("_T") + +def pipe(*validators: _ConverterType) -> _ConverterType: ... +def optional(converter: _ConverterType) -> _ConverterType: ... +@overload +def default_if_none(default: _T) -> _ConverterType: ... +@overload +def default_if_none(*, factory: Callable[[], _T]) -> _ConverterType: ... +def to_bool(val: str) -> bool: ... diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/exceptions.py b/inbm/venv-3.11/lib/python3.11/site-packages/attr/exceptions.py new file mode 100644 index 000000000..3b7abb815 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/exceptions.py @@ -0,0 +1,95 @@ +# SPDX-License-Identifier: MIT + +from __future__ import annotations + +from typing import ClassVar + + +class FrozenError(AttributeError): + """ + A frozen/immutable instance or attribute have been attempted to be + modified. + + It mirrors the behavior of ``namedtuples`` by using the same error message + and subclassing `AttributeError`. + + .. versionadded:: 20.1.0 + """ + + msg = "can't set attribute" + args: ClassVar[tuple[str]] = [msg] + + +class FrozenInstanceError(FrozenError): + """ + A frozen instance has been attempted to be modified. + + .. versionadded:: 16.1.0 + """ + + +class FrozenAttributeError(FrozenError): + """ + A frozen attribute has been attempted to be modified. + + .. versionadded:: 20.1.0 + """ + + +class AttrsAttributeNotFoundError(ValueError): + """ + An *attrs* function couldn't find an attribute that the user asked for. + + .. versionadded:: 16.2.0 + """ + + +class NotAnAttrsClassError(ValueError): + """ + A non-*attrs* class has been passed into an *attrs* function. + + .. versionadded:: 16.2.0 + """ + + +class DefaultAlreadySetError(RuntimeError): + """ + A default has been set when defining the field and is attempted to be reset + using the decorator. + + .. versionadded:: 17.1.0 + """ + + +class UnannotatedAttributeError(RuntimeError): + """ + A class with ``auto_attribs=True`` has a field without a type annotation. + + .. versionadded:: 17.3.0 + """ + + +class PythonTooOldError(RuntimeError): + """ + It was attempted to use an *attrs* feature that requires a newer Python + version. + + .. versionadded:: 18.2.0 + """ + + +class NotCallableError(TypeError): + """ + A field requiring a callable has been set with a value that is not + callable. + + .. versionadded:: 19.2.0 + """ + + def __init__(self, msg, value): + super(TypeError, self).__init__(msg, value) + self.msg = msg + self.value = value + + def __str__(self): + return str(self.msg) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/exceptions.pyi b/inbm/venv-3.11/lib/python3.11/site-packages/attr/exceptions.pyi new file mode 100644 index 000000000..f2680118b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/exceptions.pyi @@ -0,0 +1,17 @@ +from typing import Any + +class FrozenError(AttributeError): + msg: str = ... + +class FrozenInstanceError(FrozenError): ... +class FrozenAttributeError(FrozenError): ... +class AttrsAttributeNotFoundError(ValueError): ... +class NotAnAttrsClassError(ValueError): ... +class DefaultAlreadySetError(RuntimeError): ... +class UnannotatedAttributeError(RuntimeError): ... +class PythonTooOldError(RuntimeError): ... + +class NotCallableError(TypeError): + msg: str = ... + value: Any = ... + def __init__(self, msg: str, value: Any) -> None: ... diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/filters.py b/inbm/venv-3.11/lib/python3.11/site-packages/attr/filters.py new file mode 100644 index 000000000..a1e40c98d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/filters.py @@ -0,0 +1,66 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly useful filters for `attr.asdict`. +""" + +from ._make import Attribute + + +def _split_what(what): + """ + Returns a tuple of `frozenset`s of classes and attributes. + """ + return ( + frozenset(cls for cls in what if isinstance(cls, type)), + frozenset(cls for cls in what if isinstance(cls, str)), + frozenset(cls for cls in what if isinstance(cls, Attribute)), + ) + + +def include(*what): + """ + Include *what*. + + :param what: What to include. + :type what: `list` of classes `type`, field names `str` or + `attrs.Attribute`\\ s + + :rtype: `callable` + + .. versionchanged:: 23.1.0 Accept strings with field names. + """ + cls, names, attrs = _split_what(what) + + def include_(attribute, value): + return ( + value.__class__ in cls + or attribute.name in names + or attribute in attrs + ) + + return include_ + + +def exclude(*what): + """ + Exclude *what*. + + :param what: What to exclude. + :type what: `list` of classes `type`, field names `str` or + `attrs.Attribute`\\ s. + + :rtype: `callable` + + .. versionchanged:: 23.3.0 Accept field name string as input argument + """ + cls, names, attrs = _split_what(what) + + def exclude_(attribute, value): + return not ( + value.__class__ in cls + or attribute.name in names + or attribute in attrs + ) + + return exclude_ diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/filters.pyi b/inbm/venv-3.11/lib/python3.11/site-packages/attr/filters.pyi new file mode 100644 index 000000000..8a02fa0fc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/filters.pyi @@ -0,0 +1,6 @@ +from typing import Any, Union + +from . import Attribute, _FilterType + +def include(*what: Union[type, str, Attribute[Any]]) -> _FilterType[Any]: ... +def exclude(*what: Union[type, str, Attribute[Any]]) -> _FilterType[Any]: ... diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/py.typed b/inbm/venv-3.11/lib/python3.11/site-packages/attr/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/setters.py b/inbm/venv-3.11/lib/python3.11/site-packages/attr/setters.py new file mode 100644 index 000000000..12ed6750d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/setters.py @@ -0,0 +1,73 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly used hooks for on_setattr. +""" + + +from . import _config +from .exceptions import FrozenAttributeError + + +def pipe(*setters): + """ + Run all *setters* and return the return value of the last one. + + .. versionadded:: 20.1.0 + """ + + def wrapped_pipe(instance, attrib, new_value): + rv = new_value + + for setter in setters: + rv = setter(instance, attrib, rv) + + return rv + + return wrapped_pipe + + +def frozen(_, __, ___): + """ + Prevent an attribute to be modified. + + .. versionadded:: 20.1.0 + """ + raise FrozenAttributeError() + + +def validate(instance, attrib, new_value): + """ + Run *attrib*'s validator on *new_value* if it has one. + + .. versionadded:: 20.1.0 + """ + if _config._run_validators is False: + return new_value + + v = attrib.validator + if not v: + return new_value + + v(instance, attrib, new_value) + + return new_value + + +def convert(instance, attrib, new_value): + """ + Run *attrib*'s converter -- if it has one -- on *new_value* and return the + result. + + .. versionadded:: 20.1.0 + """ + c = attrib.converter + if c: + return c(new_value) + + return new_value + + +# Sentinel for disabling class-wide *on_setattr* hooks for certain attributes. +# autodata stopped working, so the docstring is inlined in the API docs. +NO_OP = object() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/setters.pyi b/inbm/venv-3.11/lib/python3.11/site-packages/attr/setters.pyi new file mode 100644 index 000000000..72f7ce476 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/setters.pyi @@ -0,0 +1,19 @@ +from typing import Any, NewType, NoReturn, TypeVar + +from . import Attribute, _OnSetAttrType + +_T = TypeVar("_T") + +def frozen( + instance: Any, attribute: Attribute[Any], new_value: Any +) -> NoReturn: ... +def pipe(*setters: _OnSetAttrType) -> _OnSetAttrType: ... +def validate(instance: Any, attribute: Attribute[_T], new_value: _T) -> _T: ... + +# convert is allowed to return Any, because they can be chained using pipe. +def convert( + instance: Any, attribute: Attribute[Any], new_value: Any +) -> Any: ... + +_NoOpType = NewType("_NoOpType", object) +NO_OP: _NoOpType diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/validators.py b/inbm/venv-3.11/lib/python3.11/site-packages/attr/validators.py new file mode 100644 index 000000000..34d6b761d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/validators.py @@ -0,0 +1,681 @@ +# SPDX-License-Identifier: MIT + +""" +Commonly useful validators. +""" + + +import operator +import re + +from contextlib import contextmanager +from re import Pattern + +from ._config import get_run_validators, set_run_validators +from ._make import _AndValidator, and_, attrib, attrs +from .converters import default_if_none +from .exceptions import NotCallableError + + +__all__ = [ + "and_", + "deep_iterable", + "deep_mapping", + "disabled", + "ge", + "get_disabled", + "gt", + "in_", + "instance_of", + "is_callable", + "le", + "lt", + "matches_re", + "max_len", + "min_len", + "not_", + "optional", + "provides", + "set_disabled", +] + + +def set_disabled(disabled): + """ + Globally disable or enable running validators. + + By default, they are run. + + :param disabled: If ``True``, disable running all validators. + :type disabled: bool + + .. warning:: + + This function is not thread-safe! + + .. versionadded:: 21.3.0 + """ + set_run_validators(not disabled) + + +def get_disabled(): + """ + Return a bool indicating whether validators are currently disabled or not. + + :return: ``True`` if validators are currently disabled. + :rtype: bool + + .. versionadded:: 21.3.0 + """ + return not get_run_validators() + + +@contextmanager +def disabled(): + """ + Context manager that disables running validators within its context. + + .. warning:: + + This context manager is not thread-safe! + + .. versionadded:: 21.3.0 + """ + set_run_validators(False) + try: + yield + finally: + set_run_validators(True) + + +@attrs(repr=False, slots=True, hash=True) +class _InstanceOfValidator: + type = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not isinstance(value, self.type): + msg = "'{name}' must be {type!r} (got {value!r} that is a {actual!r}).".format( + name=attr.name, + type=self.type, + actual=value.__class__, + value=value, + ) + raise TypeError( + msg, + attr, + self.type, + value, + ) + + def __repr__(self): + return f"" + + +def instance_of(type): + """ + A validator that raises a `TypeError` if the initializer is called + with a wrong type for this particular attribute (checks are performed using + `isinstance` therefore it's also valid to pass a tuple of types). + + :param type: The type to check for. + :type type: type or tuple of type + + :raises TypeError: With a human readable error message, the attribute + (of type `attrs.Attribute`), the expected type, and the value it + got. + """ + return _InstanceOfValidator(type) + + +@attrs(repr=False, frozen=True, slots=True) +class _MatchesReValidator: + pattern = attrib() + match_func = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not self.match_func(value): + msg = "'{name}' must match regex {pattern!r} ({value!r} doesn't)".format( + name=attr.name, pattern=self.pattern.pattern, value=value + ) + raise ValueError( + msg, + attr, + self.pattern, + value, + ) + + def __repr__(self): + return f"" + + +def matches_re(regex, flags=0, func=None): + r""" + A validator that raises `ValueError` if the initializer is called + with a string that doesn't match *regex*. + + :param regex: a regex string or precompiled pattern to match against + :param int flags: flags that will be passed to the underlying re function + (default 0) + :param callable func: which underlying `re` function to call. Valid options + are `re.fullmatch`, `re.search`, and `re.match`; the default ``None`` + means `re.fullmatch`. For performance reasons, the pattern is always + precompiled using `re.compile`. + + .. versionadded:: 19.2.0 + .. versionchanged:: 21.3.0 *regex* can be a pre-compiled pattern. + """ + valid_funcs = (re.fullmatch, None, re.search, re.match) + if func not in valid_funcs: + msg = "'func' must be one of {}.".format( + ", ".join( + sorted(e and e.__name__ or "None" for e in set(valid_funcs)) + ) + ) + raise ValueError(msg) + + if isinstance(regex, Pattern): + if flags: + msg = "'flags' can only be used with a string pattern; pass flags to re.compile() instead" + raise TypeError(msg) + pattern = regex + else: + pattern = re.compile(regex, flags) + + if func is re.match: + match_func = pattern.match + elif func is re.search: + match_func = pattern.search + else: + match_func = pattern.fullmatch + + return _MatchesReValidator(pattern, match_func) + + +@attrs(repr=False, slots=True, hash=True) +class _ProvidesValidator: + interface = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not self.interface.providedBy(value): + msg = "'{name}' must provide {interface!r} which {value!r} doesn't.".format( + name=attr.name, interface=self.interface, value=value + ) + raise TypeError( + msg, + attr, + self.interface, + value, + ) + + def __repr__(self): + return f"" + + +def provides(interface): + """ + A validator that raises a `TypeError` if the initializer is called + with an object that does not provide the requested *interface* (checks are + performed using ``interface.providedBy(value)`` (see `zope.interface + `_). + + :param interface: The interface to check for. + :type interface: ``zope.interface.Interface`` + + :raises TypeError: With a human readable error message, the attribute + (of type `attrs.Attribute`), the expected interface, and the + value it got. + + .. deprecated:: 23.1.0 + """ + import warnings + + warnings.warn( + "attrs's zope-interface support is deprecated and will be removed in, " + "or after, April 2024.", + DeprecationWarning, + stacklevel=2, + ) + return _ProvidesValidator(interface) + + +@attrs(repr=False, slots=True, hash=True) +class _OptionalValidator: + validator = attrib() + + def __call__(self, inst, attr, value): + if value is None: + return + + self.validator(inst, attr, value) + + def __repr__(self): + return f"" + + +def optional(validator): + """ + A validator that makes an attribute optional. An optional attribute is one + which can be set to ``None`` in addition to satisfying the requirements of + the sub-validator. + + :param Callable | tuple[Callable] | list[Callable] validator: A validator + (or validators) that is used for non-``None`` values. + + .. versionadded:: 15.1.0 + .. versionchanged:: 17.1.0 *validator* can be a list of validators. + .. versionchanged:: 23.1.0 *validator* can also be a tuple of validators. + """ + if isinstance(validator, (list, tuple)): + return _OptionalValidator(_AndValidator(validator)) + + return _OptionalValidator(validator) + + +@attrs(repr=False, slots=True, hash=True) +class _InValidator: + options = attrib() + + def __call__(self, inst, attr, value): + try: + in_options = value in self.options + except TypeError: # e.g. `1 in "abc"` + in_options = False + + if not in_options: + msg = f"'{attr.name}' must be in {self.options!r} (got {value!r})" + raise ValueError( + msg, + attr, + self.options, + value, + ) + + def __repr__(self): + return f"" + + +def in_(options): + """ + A validator that raises a `ValueError` if the initializer is called + with a value that does not belong in the options provided. The check is + performed using ``value in options``. + + :param options: Allowed options. + :type options: list, tuple, `enum.Enum`, ... + + :raises ValueError: With a human readable error message, the attribute (of + type `attrs.Attribute`), the expected options, and the value it + got. + + .. versionadded:: 17.1.0 + .. versionchanged:: 22.1.0 + The ValueError was incomplete until now and only contained the human + readable error message. Now it contains all the information that has + been promised since 17.1.0. + """ + return _InValidator(options) + + +@attrs(repr=False, slots=False, hash=True) +class _IsCallableValidator: + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not callable(value): + message = ( + "'{name}' must be callable " + "(got {value!r} that is a {actual!r})." + ) + raise NotCallableError( + msg=message.format( + name=attr.name, value=value, actual=value.__class__ + ), + value=value, + ) + + def __repr__(self): + return "" + + +def is_callable(): + """ + A validator that raises a `attrs.exceptions.NotCallableError` if the + initializer is called with a value for this particular attribute + that is not callable. + + .. versionadded:: 19.1.0 + + :raises attrs.exceptions.NotCallableError: With a human readable error + message containing the attribute (`attrs.Attribute`) name, + and the value it got. + """ + return _IsCallableValidator() + + +@attrs(repr=False, slots=True, hash=True) +class _DeepIterable: + member_validator = attrib(validator=is_callable()) + iterable_validator = attrib( + default=None, validator=optional(is_callable()) + ) + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if self.iterable_validator is not None: + self.iterable_validator(inst, attr, value) + + for member in value: + self.member_validator(inst, attr, member) + + def __repr__(self): + iterable_identifier = ( + "" + if self.iterable_validator is None + else f" {self.iterable_validator!r}" + ) + return ( + f"" + ) + + +def deep_iterable(member_validator, iterable_validator=None): + """ + A validator that performs deep validation of an iterable. + + :param member_validator: Validator(s) to apply to iterable members + :param iterable_validator: Validator to apply to iterable itself + (optional) + + .. versionadded:: 19.1.0 + + :raises TypeError: if any sub-validators fail + """ + if isinstance(member_validator, (list, tuple)): + member_validator = and_(*member_validator) + return _DeepIterable(member_validator, iterable_validator) + + +@attrs(repr=False, slots=True, hash=True) +class _DeepMapping: + key_validator = attrib(validator=is_callable()) + value_validator = attrib(validator=is_callable()) + mapping_validator = attrib(default=None, validator=optional(is_callable())) + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if self.mapping_validator is not None: + self.mapping_validator(inst, attr, value) + + for key in value: + self.key_validator(inst, attr, key) + self.value_validator(inst, attr, value[key]) + + def __repr__(self): + return ( + "" + ).format(key=self.key_validator, value=self.value_validator) + + +def deep_mapping(key_validator, value_validator, mapping_validator=None): + """ + A validator that performs deep validation of a dictionary. + + :param key_validator: Validator to apply to dictionary keys + :param value_validator: Validator to apply to dictionary values + :param mapping_validator: Validator to apply to top-level mapping + attribute (optional) + + .. versionadded:: 19.1.0 + + :raises TypeError: if any sub-validators fail + """ + return _DeepMapping(key_validator, value_validator, mapping_validator) + + +@attrs(repr=False, frozen=True, slots=True) +class _NumberValidator: + bound = attrib() + compare_op = attrib() + compare_func = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not self.compare_func(value, self.bound): + msg = f"'{attr.name}' must be {self.compare_op} {self.bound}: {value}" + raise ValueError(msg) + + def __repr__(self): + return f"" + + +def lt(val): + """ + A validator that raises `ValueError` if the initializer is called + with a number larger or equal to *val*. + + :param val: Exclusive upper bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, "<", operator.lt) + + +def le(val): + """ + A validator that raises `ValueError` if the initializer is called + with a number greater than *val*. + + :param val: Inclusive upper bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, "<=", operator.le) + + +def ge(val): + """ + A validator that raises `ValueError` if the initializer is called + with a number smaller than *val*. + + :param val: Inclusive lower bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, ">=", operator.ge) + + +def gt(val): + """ + A validator that raises `ValueError` if the initializer is called + with a number smaller or equal to *val*. + + :param val: Exclusive lower bound for values + + .. versionadded:: 21.3.0 + """ + return _NumberValidator(val, ">", operator.gt) + + +@attrs(repr=False, frozen=True, slots=True) +class _MaxLengthValidator: + max_length = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if len(value) > self.max_length: + msg = f"Length of '{attr.name}' must be <= {self.max_length}: {len(value)}" + raise ValueError(msg) + + def __repr__(self): + return f"" + + +def max_len(length): + """ + A validator that raises `ValueError` if the initializer is called + with a string or iterable that is longer than *length*. + + :param int length: Maximum length of the string or iterable + + .. versionadded:: 21.3.0 + """ + return _MaxLengthValidator(length) + + +@attrs(repr=False, frozen=True, slots=True) +class _MinLengthValidator: + min_length = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if len(value) < self.min_length: + msg = f"Length of '{attr.name}' must be >= {self.min_length}: {len(value)}" + raise ValueError(msg) + + def __repr__(self): + return f"" + + +def min_len(length): + """ + A validator that raises `ValueError` if the initializer is called + with a string or iterable that is shorter than *length*. + + :param int length: Minimum length of the string or iterable + + .. versionadded:: 22.1.0 + """ + return _MinLengthValidator(length) + + +@attrs(repr=False, slots=True, hash=True) +class _SubclassOfValidator: + type = attrib() + + def __call__(self, inst, attr, value): + """ + We use a callable class to be able to change the ``__repr__``. + """ + if not issubclass(value, self.type): + msg = f"'{attr.name}' must be a subclass of {self.type!r} (got {value!r})." + raise TypeError( + msg, + attr, + self.type, + value, + ) + + def __repr__(self): + return f"" + + +def _subclass_of(type): + """ + A validator that raises a `TypeError` if the initializer is called + with a wrong type for this particular attribute (checks are performed using + `issubclass` therefore it's also valid to pass a tuple of types). + + :param type: The type to check for. + :type type: type or tuple of types + + :raises TypeError: With a human readable error message, the attribute + (of type `attrs.Attribute`), the expected type, and the value it + got. + """ + return _SubclassOfValidator(type) + + +@attrs(repr=False, slots=True, hash=True) +class _NotValidator: + validator = attrib() + msg = attrib( + converter=default_if_none( + "not_ validator child '{validator!r}' " + "did not raise a captured error" + ) + ) + exc_types = attrib( + validator=deep_iterable( + member_validator=_subclass_of(Exception), + iterable_validator=instance_of(tuple), + ), + ) + + def __call__(self, inst, attr, value): + try: + self.validator(inst, attr, value) + except self.exc_types: + pass # suppress error to invert validity + else: + raise ValueError( + self.msg.format( + validator=self.validator, + exc_types=self.exc_types, + ), + attr, + self.validator, + value, + self.exc_types, + ) + + def __repr__(self): + return ( + "" + ).format( + what=self.validator, + exc_types=self.exc_types, + ) + + +def not_(validator, *, msg=None, exc_types=(ValueError, TypeError)): + """ + A validator that wraps and logically 'inverts' the validator passed to it. + It will raise a `ValueError` if the provided validator *doesn't* raise a + `ValueError` or `TypeError` (by default), and will suppress the exception + if the provided validator *does*. + + Intended to be used with existing validators to compose logic without + needing to create inverted variants, for example, ``not_(in_(...))``. + + :param validator: A validator to be logically inverted. + :param msg: Message to raise if validator fails. + Formatted with keys ``exc_types`` and ``validator``. + :type msg: str + :param exc_types: Exception type(s) to capture. + Other types raised by child validators will not be intercepted and + pass through. + + :raises ValueError: With a human readable error message, + the attribute (of type `attrs.Attribute`), + the validator that failed to raise an exception, + the value it got, + and the expected exception types. + + .. versionadded:: 22.2.0 + """ + try: + exc_types = tuple(exc_types) + except TypeError: + exc_types = (exc_types,) + return _NotValidator(validator, msg, exc_types) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attr/validators.pyi b/inbm/venv-3.11/lib/python3.11/site-packages/attr/validators.pyi new file mode 100644 index 000000000..d194a75ab --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attr/validators.pyi @@ -0,0 +1,88 @@ +from typing import ( + Any, + AnyStr, + Callable, + Container, + ContextManager, + Iterable, + List, + Mapping, + Match, + Optional, + Pattern, + Tuple, + Type, + TypeVar, + Union, + overload, +) + +from . import _ValidatorType +from . import _ValidatorArgType + +_T = TypeVar("_T") +_T1 = TypeVar("_T1") +_T2 = TypeVar("_T2") +_T3 = TypeVar("_T3") +_I = TypeVar("_I", bound=Iterable) +_K = TypeVar("_K") +_V = TypeVar("_V") +_M = TypeVar("_M", bound=Mapping) + +def set_disabled(run: bool) -> None: ... +def get_disabled() -> bool: ... +def disabled() -> ContextManager[None]: ... + +# To be more precise on instance_of use some overloads. +# If there are more than 3 items in the tuple then we fall back to Any +@overload +def instance_of(type: Type[_T]) -> _ValidatorType[_T]: ... +@overload +def instance_of(type: Tuple[Type[_T]]) -> _ValidatorType[_T]: ... +@overload +def instance_of( + type: Tuple[Type[_T1], Type[_T2]] +) -> _ValidatorType[Union[_T1, _T2]]: ... +@overload +def instance_of( + type: Tuple[Type[_T1], Type[_T2], Type[_T3]] +) -> _ValidatorType[Union[_T1, _T2, _T3]]: ... +@overload +def instance_of(type: Tuple[type, ...]) -> _ValidatorType[Any]: ... +def provides(interface: Any) -> _ValidatorType[Any]: ... +def optional( + validator: Union[ + _ValidatorType[_T], List[_ValidatorType[_T]], Tuple[_ValidatorType[_T]] + ] +) -> _ValidatorType[Optional[_T]]: ... +def in_(options: Container[_T]) -> _ValidatorType[_T]: ... +def and_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ... +def matches_re( + regex: Union[Pattern[AnyStr], AnyStr], + flags: int = ..., + func: Optional[ + Callable[[AnyStr, AnyStr, int], Optional[Match[AnyStr]]] + ] = ..., +) -> _ValidatorType[AnyStr]: ... +def deep_iterable( + member_validator: _ValidatorArgType[_T], + iterable_validator: Optional[_ValidatorType[_I]] = ..., +) -> _ValidatorType[_I]: ... +def deep_mapping( + key_validator: _ValidatorType[_K], + value_validator: _ValidatorType[_V], + mapping_validator: Optional[_ValidatorType[_M]] = ..., +) -> _ValidatorType[_M]: ... +def is_callable() -> _ValidatorType[_T]: ... +def lt(val: _T) -> _ValidatorType[_T]: ... +def le(val: _T) -> _ValidatorType[_T]: ... +def ge(val: _T) -> _ValidatorType[_T]: ... +def gt(val: _T) -> _ValidatorType[_T]: ... +def max_len(length: int) -> _ValidatorType[_T]: ... +def min_len(length: int) -> _ValidatorType[_T]: ... +def not_( + validator: _ValidatorType[_T], + *, + msg: Optional[str] = None, + exc_types: Union[Type[Exception], Iterable[Type[Exception]]] = ..., +) -> _ValidatorType[_T]: ... diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attrs-23.2.0.dist-info/INSTALLER b/inbm/venv-3.11/lib/python3.11/site-packages/attrs-23.2.0.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attrs-23.2.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attrs-23.2.0.dist-info/METADATA b/inbm/venv-3.11/lib/python3.11/site-packages/attrs-23.2.0.dist-info/METADATA new file mode 100644 index 000000000..c20be76c7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attrs-23.2.0.dist-info/METADATA @@ -0,0 +1,202 @@ +Metadata-Version: 2.1 +Name: attrs +Version: 23.2.0 +Summary: Classes Without Boilerplate +Project-URL: Documentation, https://www.attrs.org/ +Project-URL: Changelog, https://www.attrs.org/en/stable/changelog.html +Project-URL: GitHub, https://github.com/python-attrs/attrs +Project-URL: Funding, https://github.com/sponsors/hynek +Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=pypi +Author-email: Hynek Schlawack +License-Expression: MIT +License-File: LICENSE +Keywords: attribute,boilerplate,class +Classifier: Development Status :: 5 - Production/Stable +Classifier: License :: OSI Approved :: MIT License +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 :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Typing :: Typed +Requires-Python: >=3.7 +Requires-Dist: importlib-metadata; python_version < '3.8' +Provides-Extra: cov +Requires-Dist: attrs[tests]; extra == 'cov' +Requires-Dist: coverage[toml]>=5.3; extra == 'cov' +Provides-Extra: dev +Requires-Dist: attrs[tests]; extra == 'dev' +Requires-Dist: pre-commit; extra == 'dev' +Provides-Extra: docs +Requires-Dist: furo; extra == 'docs' +Requires-Dist: myst-parser; extra == 'docs' +Requires-Dist: sphinx; extra == 'docs' +Requires-Dist: sphinx-notfound-page; extra == 'docs' +Requires-Dist: sphinxcontrib-towncrier; extra == 'docs' +Requires-Dist: towncrier; extra == 'docs' +Requires-Dist: zope-interface; extra == 'docs' +Provides-Extra: tests +Requires-Dist: attrs[tests-no-zope]; extra == 'tests' +Requires-Dist: zope-interface; extra == 'tests' +Provides-Extra: tests-mypy +Requires-Dist: mypy>=1.6; (platform_python_implementation == 'CPython' and python_version >= '3.8') and extra == 'tests-mypy' +Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.8') and extra == 'tests-mypy' +Provides-Extra: tests-no-zope +Requires-Dist: attrs[tests-mypy]; extra == 'tests-no-zope' +Requires-Dist: cloudpickle; (platform_python_implementation == 'CPython') and extra == 'tests-no-zope' +Requires-Dist: hypothesis; extra == 'tests-no-zope' +Requires-Dist: pympler; extra == 'tests-no-zope' +Requires-Dist: pytest-xdist[psutil]; extra == 'tests-no-zope' +Requires-Dist: pytest>=4.3.0; extra == 'tests-no-zope' +Description-Content-Type: text/markdown + +

+ + attrs + +

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

+ + + +

+ +

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

+ + + +## Example + +*attrs* gives you a class decorator and a way to declaratively define the attributes on that class: + + + +```pycon +>>> from attrs import asdict, define, make_class, Factory + +>>> @define +... class SomeClass: +... a_number: int = 42 +... list_of_numbers: list[int] = Factory(list) +... +... def hard_math(self, another_number): +... return self.a_number + sum(self.list_of_numbers) * another_number + + +>>> sc = SomeClass(1, [1, 2, 3]) +>>> sc +SomeClass(a_number=1, list_of_numbers=[1, 2, 3]) + +>>> sc.hard_math(3) +19 +>>> sc == SomeClass(1, [1, 2, 3]) +True +>>> sc != SomeClass(2, [3, 2, 1]) +True + +>>> asdict(sc) +{'a_number': 1, 'list_of_numbers': [1, 2, 3]} + +>>> SomeClass() +SomeClass(a_number=42, list_of_numbers=[]) + +>>> C = make_class("C", ["a", "b"]) +>>> C("foo", "bar") +C(a='foo', b='bar') +``` + +After *declaring* your attributes, *attrs* gives you: + +- a concise and explicit overview of the class's attributes, +- a nice human-readable `__repr__`, +- equality-checking methods, +- an initializer, +- and much more, + +*without* writing dull boilerplate code again and again and *without* runtime performance penalties. + +**Hate type annotations**!? +No problem! +Types are entirely **optional** with *attrs*. +Simply assign `attrs.field()` to the attributes instead of annotating them with types. + +--- + +This example uses *attrs*'s modern APIs that have been introduced in version 20.1.0, and the *attrs* package import name that has been added in version 21.3.0. +The classic APIs (`@attr.s`, `attr.ib`, plus their serious-business aliases) and the `attr` package import name will remain **indefinitely**. + +Please check out [*On The Core API Names*](https://www.attrs.org/en/latest/names.html) for a more in-depth explanation. + + +## Data Classes + +On the tin, *attrs* might remind you of `dataclasses` (and indeed, `dataclasses` [are a descendant](https://hynek.me/articles/import-attrs/) of *attrs*). +In practice it does a lot more and is more flexible. +For instance it allows you to define [special handling of NumPy arrays for equality checks](https://www.attrs.org/en/stable/comparison.html#customization), allows more ways to [plug into the initialization process](https://www.attrs.org/en/stable/init.html#hooking-yourself-into-initialization), and allows for stepping through the generated methods using a debugger. + +For more details, please refer to our [comparison page](https://www.attrs.org/en/stable/why.html#data-classes). + + +## Project Information + +- [**Changelog**](https://www.attrs.org/en/stable/changelog.html) +- [**Documentation**](https://www.attrs.org/) +- [**PyPI**](https://pypi.org/project/attrs/) +- [**Source Code**](https://github.com/python-attrs/attrs) +- [**Contributing**](https://github.com/python-attrs/attrs/blob/main/.github/CONTRIBUTING.md) +- [**Third-party Extensions**](https://github.com/python-attrs/attrs/wiki/Extensions-to-attrs) +- **Get Help**: please use the `python-attrs` tag on [StackOverflow](https://stackoverflow.com/questions/tagged/python-attrs) + + +### *attrs* for Enterprise + +Available as part of the Tidelift Subscription. + +The maintainers of *attrs* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications. +Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use. +[Learn more.](https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=referral&utm_campaign=enterprise&utm_term=repo) + +## Release Information + +### Changes + +- The type annotation for `attrs.resolve_types()` is now correct. + [#1141](https://github.com/python-attrs/attrs/issues/1141) +- Type stubs now use `typing.dataclass_transform` to decorate dataclass-like decorators, instead of the non-standard `__dataclass_transform__` special form, which is only supported by Pyright. + [#1158](https://github.com/python-attrs/attrs/issues/1158) +- Fixed serialization of namedtuple fields using `attrs.asdict/astuple()` with `retain_collection_types=True`. + [#1165](https://github.com/python-attrs/attrs/issues/1165) +- `attrs.AttrsInstance` is now a `typing.Protocol` in both type hints and code. + This allows you to subclass it along with another `Protocol`. + [#1172](https://github.com/python-attrs/attrs/issues/1172) +- If *attrs* detects that `__attrs_pre_init__` accepts more than just `self`, it will call it with the same arguments as `__init__` was called. + This allows you to, for example, pass arguments to `super().__init__()`. + [#1187](https://github.com/python-attrs/attrs/issues/1187) +- Slotted classes now transform `functools.cached_property` decorated methods to support equivalent semantics. + [#1200](https://github.com/python-attrs/attrs/issues/1200) +- Added *class_body* argument to `attrs.make_class()` to provide additional attributes for newly created classes. + It is, for example, now possible to attach methods. + [#1203](https://github.com/python-attrs/attrs/issues/1203) + + +--- + +[Full changelog](https://www.attrs.org/en/stable/changelog.html) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attrs-23.2.0.dist-info/RECORD b/inbm/venv-3.11/lib/python3.11/site-packages/attrs-23.2.0.dist-info/RECORD new file mode 100644 index 000000000..08fba2a9a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attrs-23.2.0.dist-info/RECORD @@ -0,0 +1,55 @@ +attr/__init__.py,sha256=WlXJN6ICB0Y_HZ0lmuTUgia0kuSdn2p67d4N6cYxNZM,3307 +attr/__init__.pyi,sha256=u08EujYHy_rSyebNn-I9Xv2S_cXmtA9xWGc0cBsyl18,16976 +attr/__pycache__/__init__.cpython-311.pyc,, +attr/__pycache__/_cmp.cpython-311.pyc,, +attr/__pycache__/_compat.cpython-311.pyc,, +attr/__pycache__/_config.cpython-311.pyc,, +attr/__pycache__/_funcs.cpython-311.pyc,, +attr/__pycache__/_make.cpython-311.pyc,, +attr/__pycache__/_next_gen.cpython-311.pyc,, +attr/__pycache__/_version_info.cpython-311.pyc,, +attr/__pycache__/converters.cpython-311.pyc,, +attr/__pycache__/exceptions.cpython-311.pyc,, +attr/__pycache__/filters.cpython-311.pyc,, +attr/__pycache__/setters.cpython-311.pyc,, +attr/__pycache__/validators.cpython-311.pyc,, +attr/_cmp.py,sha256=OQZlWdFX74z18adGEUp40Ojqm0NNu1Flqnv2JE8B2ng,4025 +attr/_cmp.pyi,sha256=sGQmOM0w3_K4-X8cTXR7g0Hqr290E8PTObA9JQxWQqc,399 +attr/_compat.py,sha256=QmRyxii295wcQfaugWqxuIumAPsNQ2-RUF82QZPqMKw,2540 +attr/_config.py,sha256=z81Vt-GeT_2taxs1XZfmHx9TWlSxjPb6eZH1LTGsS54,843 +attr/_funcs.py,sha256=VBTUFKLklsmqxys3qWSTK_Ac9Z4s0mAJWwgW9nA7Llk,17173 +attr/_make.py,sha256=LnVy2e0HygoqaZknhC19z7JmOt7qGkAadf2LZgWVJWI,101923 +attr/_next_gen.py,sha256=as1voi8siAI_o2OQG8YIiZvmn0G7-S3_j_774rnoZ_g,6203 +attr/_typing_compat.pyi,sha256=XDP54TUn-ZKhD62TOQebmzrwFyomhUCoGRpclb6alRA,469 +attr/_version_info.py,sha256=exSqb3b5E-fMSsgZAlEw9XcLpEgobPORCZpcaEglAM4,2121 +attr/_version_info.pyi,sha256=x_M3L3WuB7r_ULXAWjx959udKQ4HLB8l-hsc1FDGNvk,209 +attr/converters.py,sha256=Kyw5MY0yfnUR_RwN1Vydf0EiE---htDxOgSc_-NYL6A,3622 +attr/converters.pyi,sha256=jKlpHBEt6HVKJvgrMFJRrHq8p61GXg4-Nd5RZWKJX7M,406 +attr/exceptions.py,sha256=HRFq4iybmv7-DcZwyjl6M1euM2YeJVK_hFxuaBGAngI,1977 +attr/exceptions.pyi,sha256=zZq8bCUnKAy9mDtBEw42ZhPhAUIHoTKedDQInJD883M,539 +attr/filters.py,sha256=9pYvXqdg6mtLvKIIb56oALRMoHFnQTcGCO4EXTc1qyM,1470 +attr/filters.pyi,sha256=0mRCjLKxdcvAo0vD-Cr81HfRXXCp9j_cAXjOoAHtPGM,225 +attr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +attr/setters.py,sha256=pbCZQ-pE6ZxjDqZfWWUhUFefXtpekIU4qS_YDMLPQ50,1400 +attr/setters.pyi,sha256=pyY8TVNBu8TWhOldv_RxHzmGvdgFQH981db70r0fn5I,567 +attr/validators.py,sha256=LGVpbiNg_KGzYrKUD5JPiZkx8TMfynDZGoQoLJNCIMo,19676 +attr/validators.pyi,sha256=167Dl9nt7NUhE9wht1I-buo039qyUT1nEUT_nKjSWr4,2580 +attrs-23.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +attrs-23.2.0.dist-info/METADATA,sha256=WwvG7OHyKjEPpyFUZCCYt1n0E_CcqdRb7bliGEdcm-A,9531 +attrs-23.2.0.dist-info/RECORD,, +attrs-23.2.0.dist-info/WHEEL,sha256=mRYSEL3Ih6g5a_CVMIcwiF__0Ae4_gLYh01YFNwiq1k,87 +attrs-23.2.0.dist-info/licenses/LICENSE,sha256=iCEVyV38KvHutnFPjsbVy8q_Znyv-HKfQkINpj9xTp8,1109 +attrs/__init__.py,sha256=9_5waVbFs7rLqtXZ73tNDrxhezyZ8VZeX4BbvQ3EeJw,1039 +attrs/__init__.pyi,sha256=s_ajQ_U14DOsOz0JbmAKDOi46B3v2PcdO0UAV1MY6Ek,2168 +attrs/__pycache__/__init__.cpython-311.pyc,, +attrs/__pycache__/converters.cpython-311.pyc,, +attrs/__pycache__/exceptions.cpython-311.pyc,, +attrs/__pycache__/filters.cpython-311.pyc,, +attrs/__pycache__/setters.cpython-311.pyc,, +attrs/__pycache__/validators.cpython-311.pyc,, +attrs/converters.py,sha256=8kQljrVwfSTRu8INwEk8SI0eGrzmWftsT7rM0EqyohM,76 +attrs/exceptions.py,sha256=ACCCmg19-vDFaDPY9vFl199SPXCQMN_bENs4DALjzms,76 +attrs/filters.py,sha256=VOUMZug9uEU6dUuA0dF1jInUK0PL3fLgP0VBS5d-CDE,73 +attrs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +attrs/setters.py,sha256=eL1YidYQV3T2h9_SYIZSZR1FAcHGb1TuCTy0E0Lv2SU,73 +attrs/validators.py,sha256=xcy6wD5TtTkdCG1f4XWbocPSO0faBjk5IfVJfP6SUj0,76 diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attrs-23.2.0.dist-info/WHEEL b/inbm/venv-3.11/lib/python3.11/site-packages/attrs-23.2.0.dist-info/WHEEL new file mode 100644 index 000000000..2860816ab --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attrs-23.2.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: hatchling 1.21.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attrs-23.2.0.dist-info/licenses/LICENSE b/inbm/venv-3.11/lib/python3.11/site-packages/attrs-23.2.0.dist-info/licenses/LICENSE new file mode 100644 index 000000000..2bd6453d2 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attrs-23.2.0.dist-info/licenses/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Hynek Schlawack and the attrs contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attrs/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/attrs/__init__.py new file mode 100644 index 000000000..0c2481561 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attrs/__init__.py @@ -0,0 +1,65 @@ +# SPDX-License-Identifier: MIT + +from attr import ( + NOTHING, + Attribute, + AttrsInstance, + Factory, + _make_getattr, + assoc, + cmp_using, + define, + evolve, + field, + fields, + fields_dict, + frozen, + has, + make_class, + mutable, + resolve_types, + validate, +) +from attr._next_gen import asdict, astuple + +from . import converters, exceptions, filters, setters, validators + + +__all__ = [ + "__author__", + "__copyright__", + "__description__", + "__doc__", + "__email__", + "__license__", + "__title__", + "__url__", + "__version__", + "__version_info__", + "asdict", + "assoc", + "astuple", + "Attribute", + "AttrsInstance", + "cmp_using", + "converters", + "define", + "evolve", + "exceptions", + "Factory", + "field", + "fields_dict", + "fields", + "filters", + "frozen", + "has", + "make_class", + "mutable", + "NOTHING", + "resolve_types", + "setters", + "validate", + "validators", +] + +__getattr__ = _make_getattr(__name__) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attrs/__init__.pyi b/inbm/venv-3.11/lib/python3.11/site-packages/attrs/__init__.pyi new file mode 100644 index 000000000..9372cfea1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attrs/__init__.pyi @@ -0,0 +1,67 @@ +from typing import ( + Any, + Callable, + Dict, + Mapping, + Optional, + Sequence, + Tuple, + Type, +) + +# Because we need to type our own stuff, we have to make everything from +# attr explicitly public too. +from attr import __author__ as __author__ +from attr import __copyright__ as __copyright__ +from attr import __description__ as __description__ +from attr import __email__ as __email__ +from attr import __license__ as __license__ +from attr import __title__ as __title__ +from attr import __url__ as __url__ +from attr import __version__ as __version__ +from attr import __version_info__ as __version_info__ +from attr import _FilterType +from attr import assoc as assoc +from attr import Attribute as Attribute +from attr import AttrsInstance as AttrsInstance +from attr import cmp_using as cmp_using +from attr import converters as converters +from attr import define as define +from attr import evolve as evolve +from attr import exceptions as exceptions +from attr import Factory as Factory +from attr import field as field +from attr import fields as fields +from attr import fields_dict as fields_dict +from attr import filters as filters +from attr import frozen as frozen +from attr import has as has +from attr import make_class as make_class +from attr import mutable as mutable +from attr import NOTHING as NOTHING +from attr import resolve_types as resolve_types +from attr import setters as setters +from attr import validate as validate +from attr import validators as validators + +# TODO: see definition of attr.asdict/astuple +def asdict( + inst: AttrsInstance, + recurse: bool = ..., + filter: Optional[_FilterType[Any]] = ..., + dict_factory: Type[Mapping[Any, Any]] = ..., + retain_collection_types: bool = ..., + value_serializer: Optional[ + Callable[[type, Attribute[Any], Any], Any] + ] = ..., + tuple_keys: bool = ..., +) -> Dict[str, Any]: ... + +# TODO: add support for returning NamedTuple from the mypy plugin +def astuple( + inst: AttrsInstance, + recurse: bool = ..., + filter: Optional[_FilterType[Any]] = ..., + tuple_factory: Type[Sequence[Any]] = ..., + retain_collection_types: bool = ..., +) -> Tuple[Any, ...]: ... diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attrs/converters.py b/inbm/venv-3.11/lib/python3.11/site-packages/attrs/converters.py new file mode 100644 index 000000000..7821f6c02 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attrs/converters.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.converters import * # noqa: F403 diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attrs/exceptions.py b/inbm/venv-3.11/lib/python3.11/site-packages/attrs/exceptions.py new file mode 100644 index 000000000..3323f9d21 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attrs/exceptions.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.exceptions import * # noqa: F403 diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attrs/filters.py b/inbm/venv-3.11/lib/python3.11/site-packages/attrs/filters.py new file mode 100644 index 000000000..3080f4839 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attrs/filters.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.filters import * # noqa: F403 diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attrs/py.typed b/inbm/venv-3.11/lib/python3.11/site-packages/attrs/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attrs/setters.py b/inbm/venv-3.11/lib/python3.11/site-packages/attrs/setters.py new file mode 100644 index 000000000..f3d73bb79 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attrs/setters.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.setters import * # noqa: F403 diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/attrs/validators.py b/inbm/venv-3.11/lib/python3.11/site-packages/attrs/validators.py new file mode 100644 index 000000000..037e124f2 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/attrs/validators.py @@ -0,0 +1,3 @@ +# SPDX-License-Identifier: MIT + +from attr.validators import * # noqa: F403 diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/INSTALLER b/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/LICENSE b/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/LICENSE new file mode 100644 index 000000000..0a64774ea --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/LICENSE @@ -0,0 +1,21 @@ +This package contains a modified version of ca-bundle.crt: + +ca-bundle.crt -- Bundle of CA Root Certificates + +Certificate data from Mozilla as of: Thu Nov 3 19:04:19 2011# +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/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/METADATA b/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/METADATA new file mode 100644 index 000000000..07f4991b7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/METADATA @@ -0,0 +1,69 @@ +Metadata-Version: 2.1 +Name: certifi +Version: 2023.7.22 +Summary: Python package for providing Mozilla's CA Bundle. +Home-page: https://github.com/certifi/python-certifi +Author: Kenneth Reitz +Author-email: me@kennethreitz.com +License: MPL-2.0 +Project-URL: Source, https://github.com/certifi/python-certifi +Platform: UNKNOWN +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.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Requires-Python: >=3.6 +License-File: LICENSE + +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/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/RECORD b/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/RECORD new file mode 100644 index 000000000..36cf845f1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/RECORD @@ -0,0 +1,15 @@ +certifi-2023.7.22.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +certifi-2023.7.22.dist-info/LICENSE,sha256=oC9sY4-fuE0G93ZMOrCF2K9-2luTwWbaVDEkeQd8b7A,1052 +certifi-2023.7.22.dist-info/METADATA,sha256=oyc8gd32SOVo0IGolt8-bR7FnZ9Z99GoHoGE6ACcvFA,2191 +certifi-2023.7.22.dist-info/RECORD,, +certifi-2023.7.22.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +certifi-2023.7.22.dist-info/WHEEL,sha256=ewwEueio1C2XeHTvT17n8dZUJgOvyCWCt0WVNLClP9o,92 +certifi-2023.7.22.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8 +certifi/__init__.py,sha256=L_j-d0kYuA_MzA2_2hraF1ovf6KT6DTquRdV3paQwOk,94 +certifi/__main__.py,sha256=xBBoj905TUWBLRGANOcf7oi6e-3dMP4cEoG9OyMs11g,243 +certifi/__pycache__/__init__.cpython-311.pyc,, +certifi/__pycache__/__main__.cpython-311.pyc,, +certifi/__pycache__/core.cpython-311.pyc,, +certifi/cacert.pem,sha256=eU0Dn_3yd8BH4m8sfVj4Glhl2KDrcCSg-sEWT-pNJ88,281617 +certifi/core.py,sha256=lhewz0zFb2b4ULsQurElmloYwQoecjWzPqY67P8T7iM,4219 +certifi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/REQUESTED b/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/REQUESTED new file mode 100644 index 000000000..e69de29bb diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/WHEEL b/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/WHEEL new file mode 100644 index 000000000..5bad85fdc --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/top_level.txt b/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/top_level.txt new file mode 100644 index 000000000..963eac530 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/certifi-2023.7.22.dist-info/top_level.txt @@ -0,0 +1 @@ +certifi diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/certifi/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/certifi/__init__.py new file mode 100644 index 000000000..8ce89cef7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/certifi/__init__.py @@ -0,0 +1,4 @@ +from .core import contents, where + +__all__ = ["contents", "where"] +__version__ = "2023.07.22" diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/certifi/__main__.py b/inbm/venv-3.11/lib/python3.11/site-packages/certifi/__main__.py new file mode 100644 index 000000000..8945b5da8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/certifi/__main__.py @@ -0,0 +1,12 @@ +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/inbm/venv-3.11/lib/python3.11/site-packages/certifi/cacert.pem b/inbm/venv-3.11/lib/python3.11/site-packages/certifi/cacert.pem new file mode 100644 index 000000000..02123695d --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/certifi/cacert.pem @@ -0,0 +1,4635 @@ + +# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA +# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA +# Label: "GlobalSign Root CA" +# Serial: 4835703278459707669005204 +# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a +# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c +# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99 +-----BEGIN CERTIFICATE----- +MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG +A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv +b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw +MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i +YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT +aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ +jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp +xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp +1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG +snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ +U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8 +9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E +BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B +AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz +yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE +38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP +AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad +DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME +HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A== +-----END CERTIFICATE----- + +# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited +# Label: "Entrust.net Premium 2048 Secure Server CA" +# Serial: 946069240 +# MD5 Fingerprint: ee:29:31:bc:32:7e:9a:e6:e8:b5:f7:51:b4:34:71:90 +# SHA1 Fingerprint: 50:30:06:09:1d:97:d4:f5:ae:39:f7:cb:e7:92:7d:7d:65:2d:34:31 +# SHA256 Fingerprint: 6d:c4:71:72:e0:1c:bc:b0:bf:62:58:0d:89:5f:e2:b8:ac:9a:d4:f8:73:80:1e:0c:10:b9:c8:37:d2:1e:b1:77 +-----BEGIN CERTIFICATE----- +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML +RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp +bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5 +IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp +ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3 +MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3 +LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp +YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG +A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq +K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe +sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX +MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT +XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/ +HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH +4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV +HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub +j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo +U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b +u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+ +bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er +fF6adulZkMV8gzURZVE= +-----END CERTIFICATE----- + +# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust +# Label: "Baltimore CyberTrust Root" +# Serial: 33554617 +# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4 +# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74 +# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb +-----BEGIN CERTIFICATE----- +MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ +RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD +VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX +DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y +ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy +VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr +mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr +IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK +mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu +XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy +dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye +jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1 +BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3 +DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92 +9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx +jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0 +Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz +ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS +R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. +# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc. +# Label: "Entrust Root Certification Authority" +# Serial: 1164660820 +# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4 +# SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9 +# SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c +-----BEGIN CERTIFICATE----- +MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0 +Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW +KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl +cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw +NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw +NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy +ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV +BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo +Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4 +4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9 +KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI +rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi +94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB +sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi +gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo +kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE +vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA +A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t +O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua +AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP +9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/ +eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m +0vdXcDazv/wor3ElhVsT/h5/WrQ8 +-----END CERTIFICATE----- + +# Issuer: CN=AAA Certificate Services O=Comodo CA Limited +# Subject: CN=AAA Certificate Services O=Comodo CA Limited +# Label: "Comodo AAA Services root" +# Serial: 1 +# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0 +# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49 +# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4 +-----BEGIN CERTIFICATE----- +MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb +MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow +GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj +YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL +MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE +BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM +GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP +ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua +BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe +3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4 +YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR +rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm +ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU +oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF +MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v +QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t +b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF +AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q +GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz +Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2 +G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi +l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3 +smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg== +-----END CERTIFICATE----- + +# 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: O=SECOM Trust.net OU=Security Communication RootCA1 +# Subject: O=SECOM Trust.net OU=Security Communication RootCA1 +# Label: "Security Communication Root CA" +# Serial: 0 +# MD5 Fingerprint: f1:bc:63:6a:54:e0:b5:27:f5:cd:e7:1a:e3:4d:6e:4a +# SHA1 Fingerprint: 36:b1:2b:49:f9:81:9e:d7:4c:9e:bc:38:0f:c6:56:8f:5d:ac:b2:f7 +# SHA256 Fingerprint: e7:5e:72:ed:9f:56:0e:ec:6e:b4:80:00:73:a4:3f:c3:ad:19:19:5a:39:22:82:01:78:95:97:4a:99:02:6b:6c +-----BEGIN CERTIFICATE----- +MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY +MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t +dW5pY2F0aW9uIFJvb3RDQTEwHhcNMDMwOTMwMDQyMDQ5WhcNMjMwOTMwMDQyMDQ5 +WjBQMQswCQYDVQQGEwJKUDEYMBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYD +VQQLEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTEwggEiMA0GCSqGSIb3 +DQEBAQUAA4IBDwAwggEKAoIBAQCzs/5/022x7xZ8V6UMbXaKL0u/ZPtM7orw8yl8 +9f/uKuDp6bpbZCKamm8sOiZpUQWZJtzVHGpxxpp9Hp3dfGzGjGdnSj74cbAZJ6kJ +DKaVv0uMDPpVmDvY6CKhS3E4eayXkmmziX7qIWgGmBSWh9JhNrxtJ1aeV+7AwFb9 +Ms+k2Y7CI9eNqPPYJayX5HA49LY6tJ07lyZDo6G8SVlyTCMwhwFY9k6+HGhWZq/N +QV3Is00qVUarH9oe4kA92819uZKAnDfdDJZkndwi92SL32HeFZRSFaB9UslLqCHJ +xrHty8OVYNEP8Ktw+N/LTX7s1vqr2b1/VPKl6Xn62dZ2JChzAgMBAAGjPzA9MB0G +A1UdDgQWBBSgc0mZaNyFW2XjmygvV5+9M7wHSDALBgNVHQ8EBAMCAQYwDwYDVR0T +AQH/BAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAaECpqLvkT115swW1F7NgE+vG +kl3g0dNq/vu+m22/xwVtWSDEHPC32oRYAmP6SBbvT6UL90qY8j+eG61Ha2POCEfr +Uj94nK9NrvjVT8+amCoQQTlSxN3Zmw7vkwGusi7KaEIkQmywszo+zenaSMQVy+n5 +Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU +JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot +RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw== +-----END CERTIFICATE----- + +# Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com +# Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com +# Label: "XRamp Global CA Root" +# Serial: 107108908803651509692980124233745014957 +# MD5 Fingerprint: a1:0b:44:b3:ca:10:d8:00:6e:9d:0f:d8:0f:92:0a:d1 +# SHA1 Fingerprint: b8:01:86:d1:eb:9c:86:a5:41:04:cf:30:54:f3:4c:52:b7:e5:58:c6 +# SHA256 Fingerprint: ce:cd:dc:90:50:99:d8:da:df:c5:b1:d2:09:b7:37:cb:e2:c1:8c:fb:2c:10:c0:ff:0b:cf:0d:32:86:fc:1a:a2 +-----BEGIN CERTIFICATE----- +MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB +gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk +MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY +UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx +NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3 +dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy +dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB +dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6 +38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP +KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q +DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4 +qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa +JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi +PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P +BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs +jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0 +eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD +ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR +vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt +qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa +IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy +i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ +O+7ETPTsJ3xCwnR8gooJybQDJbw= +-----END CERTIFICATE----- + +# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority +# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority +# Label: "Go Daddy Class 2 CA" +# Serial: 0 +# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67 +# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4 +# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4 +-----BEGIN CERTIFICATE----- +MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh +MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE +YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3 +MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo +ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg +MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN +ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA +PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w +wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi +EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY +avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+ +YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE +sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h +/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5 +IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD +ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy +OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P +TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ +HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER +dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf +ReYNnyicsbkqWletNw+vHX/bvZ8= +-----END CERTIFICATE----- + +# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority +# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority +# Label: "Starfield Class 2 CA" +# Serial: 0 +# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24 +# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a +# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58 +-----BEGIN CERTIFICATE----- +MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl +MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp +U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw +NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE +ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp +ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3 +DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf +8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN ++lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0 +X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa +K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA +1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G +A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR +zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0 +YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD +bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w +DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3 +L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D +eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl +xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp +VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY +WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q= +-----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=SwissSign Silver CA - G2 O=SwissSign AG +# Subject: CN=SwissSign Silver CA - G2 O=SwissSign AG +# Label: "SwissSign Silver CA - G2" +# Serial: 5700383053117599563 +# MD5 Fingerprint: e0:06:a1:c9:7d:cf:c9:fc:0d:c0:56:75:96:d8:62:13 +# SHA1 Fingerprint: 9b:aa:e5:9f:56:ee:21:cb:43:5a:be:25:93:df:a7:f0:40:d1:1d:cb +# SHA256 Fingerprint: be:6c:4d:a2:bb:b9:ba:59:b6:f3:93:97:68:37:42:46:c3:c0:05:99:3f:a9:8f:02:0d:1d:ed:be:d4:8a:81:d5 +-----BEGIN CERTIFICATE----- +MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE +BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu +IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow +RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY +U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv +Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br +YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF +nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH +6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt +eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/ +c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ +MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH +HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf +jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6 +5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB +rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU +F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c +wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0 +cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB +AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp +WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9 +xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ +2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ +IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8 +aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X +em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR +dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/ +OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+ +hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy +tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u +-----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=SecureSign RootCA11 O=Japan Certification Services, Inc. +# Subject: CN=SecureSign RootCA11 O=Japan Certification Services, Inc. +# Label: "SecureSign RootCA11" +# Serial: 1 +# MD5 Fingerprint: b7:52:74:e2:92:b4:80:93:f2:75:e4:cc:d7:f2:ea:26 +# SHA1 Fingerprint: 3b:c4:9f:48:f8:f3:73:a0:9c:1e:bd:f8:5b:b1:c3:65:c7:d8:11:b3 +# SHA256 Fingerprint: bf:0f:ee:fb:9e:3a:58:1a:d5:f9:e9:db:75:89:98:57:43:d2:61:08:5c:4d:31:4f:6f:5d:72:59:aa:42:16:12 +-----BEGIN CERTIFICATE----- +MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr +MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG +A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0 +MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp +Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD +QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz +i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8 +h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV +MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9 +UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni +8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC +h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD +VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB +AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm +KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ +X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr +QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5 +pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN +QSdJQO7e5iNEOdyhIta6A/I= +-----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=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068 +# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068" +# Serial: 6047274297262753887 +# MD5 Fingerprint: 73:3a:74:7a:ec:bb:a3:96:a6:c2:e4:e2:c8:9b:c0:c3 +# SHA1 Fingerprint: ae:c5:fb:3f:c8:e1:bf:c4:e5:4f:03:07:5a:9a:e8:00:b7:f7:b6:fa +# SHA256 Fingerprint: 04:04:80:28:bf:1f:28:64:d4:8f:9a:d4:d8:32:94:36:6a:82:88:56:55:3f:3b:14:30:3f:90:14:7f:5d:40:ef +-----BEGIN CERTIFICATE----- +MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE +BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h +cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0wOTA1MjAwODM4MTVaFw0zMDEy +MzEwODM4MTVaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg +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+JIwuwIDAQABo4HvMIHsMBIGA1UdEwEB/wQIMAYBAf8CAQEwDgYD +VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBRlzeurNR4APn7VdMActHNHDhpkLzCBpgYD +VR0gBIGeMIGbMIGYBgRVHSAAMIGPMC8GCCsGAQUFBwIBFiNodHRwOi8vd3d3LmZp +cm1hcHJvZmVzaW9uYWwuY29tL2NwczBcBggrBgEFBQcCAjBQHk4AUABhAHMAZQBv +ACAAZABlACAAbABhACAAQgBvAG4AYQBuAG8AdgBhACAANAA3ACAAQgBhAHIAYwBl +AGwAbwBuAGEAIAAwADgAMAAxADcwDQYJKoZIhvcNAQEFBQADggIBABd9oPm03cXF +661LJLWhAqvdpYhKsg9VSytXjDvlMd3+xDLx51tkljYyGOylMnfX40S2wBEqgLk9 +am58m9Ot/MPWo+ZkKXzR4Tgegiv/J2Wv+xYVxC5xhOW1//qkR71kMrv2JYSiJ0L1 +ILDCExARzRAVukKQKtJE4ZYm6zFIEv0q2skGz3QeqUvVhyj5eTSSPi5E6PaPT481 +PyWzOdxjKpBrIF/EUhJOlywqrJ2X3kjyo2bbwtKDlaZmp54lD+kLM5FlClrD2VQS +3a/DTg4fJl4N3LON7NWBcN7STyQF82xO9UxJZo3R/9ILJUFI/lGExkKvgATP0H5k +SeTy36LssUzAKh3ntLFlosS88Zj0qnAHY7S42jtM+kAiMFsRpvAFDsYCA0irhpuF +3dvd6qJ2gHN99ZwExEWN57kci57q13XRcrHedUTnQn3iV2t93Jm8PYMo6oCTjcVM +ZcFwgbg4/EMxsvYDNEeyrPsiBsse3RdHHF9mudMaotoRsaS8I8nkvof/uZS2+F0g +StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz +Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB +jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V +-----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=AffirmTrust Commercial O=AffirmTrust +# Subject: CN=AffirmTrust Commercial O=AffirmTrust +# Label: "AffirmTrust Commercial" +# Serial: 8608355977964138876 +# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7 +# SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7 +# SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7 +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP +Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr +ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL +MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1 +yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr +VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/ +nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG +XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj +vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt +Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g +N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC +nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8= +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Networking O=AffirmTrust +# Subject: CN=AffirmTrust Networking O=AffirmTrust +# Label: "AffirmTrust Networking" +# Serial: 8957382827206547757 +# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f +# SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f +# SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b +-----BEGIN CERTIFICATE----- +MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz +dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL +MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp +cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC +AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y +YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua +kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL +QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp +6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG +yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i +QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ +KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO +tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu +QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ +Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u +olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48 +x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s= +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Premium O=AffirmTrust +# Subject: CN=AffirmTrust Premium O=AffirmTrust +# Label: "AffirmTrust Premium" +# Serial: 7893706540734352110 +# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57 +# SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27 +# SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a +-----BEGIN CERTIFICATE----- +MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE +BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz +dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG +A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U +cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf +qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ +JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ ++jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS +s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5 +HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7 +70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG +V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S +qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S +5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia +C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX +OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE +FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ +BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2 +KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg +Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B +8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ +MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc +0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ +u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF +u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH +YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8 +GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO +RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e +KeC2uAloGRwYQw== +-----END CERTIFICATE----- + +# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust +# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust +# Label: "AffirmTrust Premium ECC" +# Serial: 8401224907861490260 +# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d +# SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb +# SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23 +-----BEGIN CERTIFICATE----- +MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC +VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ +cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ +BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt +VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D +0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9 +ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G +A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G +A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs +aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I +flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ== +-----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=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - G2" +# Serial: 1246989352 +# MD5 Fingerprint: 4b:e2:c9:91:96:65:0c:f4:0e:5a:93:92:a0:0a:fe:b2 +# SHA1 Fingerprint: 8c:f4:27:fd:79:0c:3a:d1:66:06:8d:e8:1e:57:ef:bb:93:22:72:d4 +# SHA256 Fingerprint: 43:df:57:74:b0:3e:7f:ef:5f:e4:0d:93:1a:7b:ed:f1:bb:2e:6b:42:73:8c:4e:6d:38:41:10:3d:3a:a7:f3:39 +-----BEGIN CERTIFICATE----- +MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC +VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50 +cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs +IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz +dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy +NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu +dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt +dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0 +aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj +YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T +RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN +cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW +wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1 +U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0 +jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN +BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/ +jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ +Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v +1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R +nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH +VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g== +-----END CERTIFICATE----- + +# Issuer: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - EC1" +# Serial: 51543124481930649114116133369 +# MD5 Fingerprint: b6:7e:1d:f0:58:c5:49:6c:24:3b:3d:ed:98:18:ed:bc +# SHA1 Fingerprint: 20:d8:06:40:df:9b:25:f5:12:25:3a:11:ea:f7:59:8a:eb:14:b5:47 +# SHA256 Fingerprint: 02:ed:0e:b2:8c:14:da:45:16:5c:56:67:91:70:0d:64:51:d7:fb:56:f0:b2:ab:1d:3b:8e:b0:70:e5:6e:df:f5 +-----BEGIN CERTIFICATE----- +MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG +A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3 +d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu +dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq +RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy +MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD +VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0 +L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g +Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD +ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi +A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt +ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH +Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O +BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC +R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX +hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G +-----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=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only +# Subject: CN=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only +# Label: "Entrust Root Certification Authority - G4" +# Serial: 289383649854506086828220374796556676440 +# MD5 Fingerprint: 89:53:f1:83:23:b7:7c:8e:05:f1:8c:71:38:4e:1f:88 +# SHA1 Fingerprint: 14:88:4e:86:26:37:b0:26:af:59:62:5c:40:77:ec:35:29:ba:96:01 +# SHA256 Fingerprint: db:35:17:d1:f6:73:2a:2d:5a:b9:7c:53:3e:c7:07:79:ee:32:70:a6:2f:b4:ac:42:38:37:24:60:e6:f0:1e:88 +-----BEGIN CERTIFICATE----- +MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw +gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL +Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg +MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw +BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0 +MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT +MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1 +c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ +bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg +Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B +AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ +2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E +T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j +5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM +C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T +DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX +wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A +2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm +nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8 +dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl +N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj +c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS +5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS +Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr +hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/ +B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI +AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw +H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+ +b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk +2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol +IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk +5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY +n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw== +-----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=GLOBALTRUST 2020 O=e-commerce monitoring GmbH +# Subject: CN=GLOBALTRUST 2020 O=e-commerce monitoring GmbH +# Label: "GLOBALTRUST 2020" +# Serial: 109160994242082918454945253 +# MD5 Fingerprint: 8a:c7:6f:cb:6d:e3:cc:a2:f1:7c:83:fa:0e:78:d7:e8 +# SHA1 Fingerprint: d0:67:c1:13:51:01:0c:aa:d0:c7:6a:65:37:31:16:26:4f:53:71:a2 +# SHA256 Fingerprint: 9a:29:6a:51:82:d1:d4:51:a2:e3:7f:43:9b:74:da:af:a2:67:52:33:29:f9:0f:9a:0d:20:07:c3:34:e2:3c:9a +-----BEGIN CERTIFICATE----- +MIIFgjCCA2qgAwIBAgILWku9WvtPilv6ZeUwDQYJKoZIhvcNAQELBQAwTTELMAkG +A1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9uaXRvcmluZyBHbWJIMRkw +FwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMB4XDTIwMDIxMDAwMDAwMFoXDTQwMDYx +MDAwMDAwMFowTTELMAkGA1UEBhMCQVQxIzAhBgNVBAoTGmUtY29tbWVyY2UgbW9u +aXRvcmluZyBHbWJIMRkwFwYDVQQDExBHTE9CQUxUUlVTVCAyMDIwMIICIjANBgkq +hkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAri5WrRsc7/aVj6B3GyvTY4+ETUWiD59b +RatZe1E0+eyLinjF3WuvvcTfk0Uev5E4C64OFudBc/jbu9G4UeDLgztzOG53ig9Z +YybNpyrOVPu44sB8R85gfD+yc/LAGbaKkoc1DZAoouQVBGM+uq/ufF7MpotQsjj3 +QWPKzv9pj2gOlTblzLmMCcpL3TGQlsjMH/1WljTbjhzqLL6FLmPdqqmV0/0plRPw +yJiT2S0WR5ARg6I6IqIoV6Lr/sCMKKCmfecqQjuCgGOlYx8ZzHyyZqjC0203b+J+ +BlHZRYQfEs4kUmSFC0iAToexIiIwquuuvuAC4EDosEKAA1GqtH6qRNdDYfOiaxaJ +SaSjpCuKAsR49GiKweR6NrFvG5Ybd0mN1MkGco/PU+PcF4UgStyYJ9ORJitHHmkH +r96i5OTUawuzXnzUJIBHKWk7buis/UDr2O1xcSvy6Fgd60GXIsUf1DnQJ4+H4xj0 +4KlGDfV0OoIu0G4skaMxXDtG6nsEEFZegB31pWXogvziB4xiRfUg3kZwhqG8k9Me +dKZssCz3AwyIDMvUclOGvGBG85hqwvG/Q/lwIHfKN0F5VVJjjVsSn8VoxIidrPIw +q7ejMZdnrY8XD2zHc+0klGvIg5rQmjdJBKuxFshsSUktq6HQjJLyQUp5ISXbY9e2 +nKd+Qmn7OmMCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC +AQYwHQYDVR0OBBYEFNwuH9FhN3nkq9XVsxJxaD1qaJwiMB8GA1UdIwQYMBaAFNwu +H9FhN3nkq9XVsxJxaD1qaJwiMA0GCSqGSIb3DQEBCwUAA4ICAQCR8EICaEDuw2jA +VC/f7GLDw56KoDEoqoOOpFaWEhCGVrqXctJUMHytGdUdaG/7FELYjQ7ztdGl4wJC +XtzoRlgHNQIw4Lx0SsFDKv/bGtCwr2zD/cuz9X9tAy5ZVp0tLTWMstZDFyySCstd +6IwPS3BD0IL/qMy/pJTAvoe9iuOTe8aPmxadJ2W8esVCgmxcB9CpwYhgROmYhRZf ++I/KARDOJcP5YBugxZfD0yyIMaK9MOzQ0MAS8cE54+X1+NZK3TTN+2/BT+MAi1bi +kvcoskJ3ciNnxz8RFbLEAwW+uxF7Cr+obuf/WEPPm2eggAe2HcqtbepBEX4tdJP7 +wry+UUTF72glJ4DjyKDUEuzZpTcdN3y0kcra1LGWge9oXHYQSa9+pTeAsRxSvTOB +TI/53WXZFM2KJVj04sWDpQmQ1GwUY7VA3+vA/MRYfg0UFodUJ25W5HCEuGwyEn6C +MUO+1918oa2u1qsgEu8KwxCMSZY13At1XrFP1U80DhEgB3VDRemjEdqso5nCtnkn +4rnvyOL2NSl6dPrFf4IFYqYK6miyeUcGbvJXqBUzxvd4Sj1Ce2t+/vdG6tHrju+I +aFvowdlxfv1k7/9nR4hYJS8+hge9+6jlgqispdNpQ80xiEmEU5LAsTkbOYMBMMTy +qfrQA71yN2BWHzZ8vTmR9W0Nv3vXkg== +-----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 RootCA3 O=SECOM Trust Systems CO.,LTD. +# Subject: CN=Security Communication RootCA3 O=SECOM Trust Systems CO.,LTD. +# Label: "Security Communication RootCA3" +# Serial: 16247922307909811815 +# MD5 Fingerprint: 1c:9a:16:ff:9e:5c:e0:4d:8a:14:01:f4:35:5d:29:26 +# SHA1 Fingerprint: c3:03:c8:22:74:92:e5:61:a2:9c:5f:79:91:2b:1e:44:13:91:30:3a +# SHA256 Fingerprint: 24:a5:5c:2a:b0:51:44:2d:06:17:76:65:41:23:9a:4a:d0:32:d7:c5:51:75:aa:34:ff:de:2f:bc:4f:5c:52:94 +-----BEGIN CERTIFICATE----- +MIIFfzCCA2egAwIBAgIJAOF8N0D9G/5nMA0GCSqGSIb3DQEBDAUAMF0xCzAJBgNV +BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw +JQYDVQQDEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTMwHhcNMTYwNjE2 +MDYxNzE2WhcNMzgwMTE4MDYxNzE2WjBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc +U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UEAxMeU2VjdXJpdHkg +Q29tbXVuaWNhdGlvbiBSb290Q0EzMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC +CgKCAgEA48lySfcw3gl8qUCBWNO0Ot26YQ+TUG5pPDXC7ltzkBtnTCHsXzW7OT4r +CmDvu20rhvtxosis5FaU+cmvsXLUIKx00rgVrVH+hXShuRD+BYD5UpOzQD11EKzA +lrenfna84xtSGc4RHwsENPXY9Wk8d/Nk9A2qhd7gCVAEF5aEt8iKvE1y/By7z/MG +TfmfZPd+pmaGNXHIEYBMwXFAWB6+oHP2/D5Q4eAvJj1+XCO1eXDe+uDRpdYMQXF7 +9+qMHIjH7Iv10S9VlkZ8WjtYO/u62C21Jdp6Ts9EriGmnpjKIG58u4iFW/vAEGK7 +8vknR+/RiTlDxN/e4UG/VHMgly1s2vPUB6PmudhvrvyMGS7TZ2crldtYXLVqAvO4 +g160a75BflcJdURQVc1aEWEhCmHCqYj9E7wtiS/NYeCVvsq1e+F7NGcLH7YMx3we +GVPKp7FKFSBWFHA9K4IsD50VHUeAR/94mQ4xr28+j+2GaR57GIgUssL8gjMunEst ++3A7caoreyYn8xrC3PsXuKHqy6C0rtOUfnrQq8PsOC0RLoi/1D+tEjtCrI8Cbn3M +0V9hvqG8OmpI6iZVIhZdXw3/JzOfGAN0iltSIEdrRU0id4xVJ/CvHozJgyJUt5rQ +T9nO/NkuHJYosQLTA70lUhw0Zk8jq/R3gpYd0VcwCBEF/VfR2ccCAwEAAaNCMEAw +HQYDVR0OBBYEFGQUfPxYchamCik0FW8qy7z8r6irMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDAUAA4ICAQDcAiMI4u8hOscNtybS +YpOnpSNyByCCYN8Y11StaSWSntkUz5m5UoHPrmyKO1o5yGwBQ8IibQLwYs1OY0PA +FNr0Y/Dq9HHuTofjcan0yVflLl8cebsjqodEV+m9NU1Bu0soo5iyG9kLFwfl9+qd +9XbXv8S2gVj/yP9kaWJ5rW4OH3/uHWnlt3Jxs/6lATWUVCvAUm2PVcTJ0rjLyjQI +UYWg9by0F1jqClx6vWPGOi//lkkZhOpn2ASxYfQAW0q3nHE3GYV5v4GwxxMOdnE+ +OoAGrgYWp421wsTL/0ClXI2lyTrtcoHKXJg80jQDdwj98ClZXSEIx2C/pHF7uNke +gr4Jr2VvKKu/S7XuPghHJ6APbw+LP6yVGPO5DtxnVW5inkYO0QR4ynKudtml+LLf +iAlhi+8kTtFZP1rUPcmTPCtk9YENFpb3ksP+MW/oKjJ0DvRMmEoYDjBU1cXrvMUV +nuiZIesnKwkK2/HmcBhWuwzkvvnoEKQTkrgc4NtnHVMDpCKn3F2SEDzq//wbEBrD +2NCcnWXL0CsnMQMeNuE9dnUM/0Umud1RvCPHX9jYhxBAEg09ODfnRDwYwFMJZI// +1ZqmfHAuc1Uh6N//g7kdPjIe1qZ9LPFm6Vwdp6POXiUyK+OVrCoHzrQoeIY8Laad +TdJ0MN1kURXbg4NR16/9M51NZg== +-----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----- diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/certifi/core.py b/inbm/venv-3.11/lib/python3.11/site-packages/certifi/core.py new file mode 100644 index 000000000..de028981b --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/certifi/core.py @@ -0,0 +1,108 @@ +""" +certifi.py +~~~~~~~~~~ + +This module returns the installation location of cacert.pem or its contents. +""" +import sys + + +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__()) + + return _CACERT_PATH + + def contents() -> str: + return files("certifi").joinpath("cacert.pem").read_text(encoding="ascii") + +elif sys.version_info >= (3, 7): + + 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__()) + + return _CACERT_PATH + + def contents() -> str: + return read_text("certifi", "cacert.pem", encoding="ascii") + +else: + import os + import types + from typing import Union + + Package = Union[types.ModuleType, str] + Resource = Union[str, "os.PathLike"] + + # This fallback will work for Python versions prior to 3.7 that lack the + # importlib.resources module but relies on the existing `where` function + # so won't address issues with environments like PyOxidizer that don't set + # __file__ on modules. + def read_text( + package: Package, + resource: Resource, + encoding: str = 'utf-8', + errors: str = 'strict' + ) -> str: + with open(where(), encoding=encoding) as data: + return data.read() + + # If we don't have importlib.resources, then we will just do the old logic + # of assuming we're on the filesystem and munge the path directly. + def where() -> str: + f = os.path.dirname(__file__) + + return os.path.join(f, "cacert.pem") + + def contents() -> str: + return read_text("certifi", "cacert.pem", encoding="ascii") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/certifi/py.typed b/inbm/venv-3.11/lib/python3.11/site-packages/certifi/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/INSTALLER b/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/LICENSE b/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/LICENSE new file mode 100644 index 000000000..29225eee9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/LICENSE @@ -0,0 +1,26 @@ + +Except when otherwise stated (look for LICENSE files in directories or +information at the beginning of each file) all software and +documentation is licensed as follows: + + The MIT License + + 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/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/METADATA b/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/METADATA new file mode 100644 index 000000000..f582bfbba --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/METADATA @@ -0,0 +1,39 @@ +Metadata-Version: 2.1 +Name: cffi +Version: 1.16.0 +Summary: Foreign Function Interface for Python calling C code. +Home-page: http://cffi.readthedocs.org +Author: Armin Rigo, Maciej Fijalkowski +Author-email: python-cffi@googlegroups.com +License: MIT +Project-URL: Documentation, http://cffi.readthedocs.org/ +Project-URL: Source Code, https://github.com/python-cffi/cffi +Project-URL: Issue Tracker, https://github.com/python-cffi/cffi/issues +Project-URL: Changelog, https://cffi.readthedocs.io/en/latest/whatsnew.html +Project-URL: Downloads, https://github.com/python-cffi/cffi/releases +Project-URL: Contact, https://groups.google.com/forum/#!forum/python-cffi +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: License :: OSI Approved :: MIT License +Requires-Python: >=3.8 +License-File: LICENSE +Requires-Dist: pycparser + + +CFFI +==== + +Foreign Function Interface for Python calling C code. +Please see the `Documentation `_. + +Contact +------- + +`Mailing list `_ diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/RECORD b/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/RECORD new file mode 100644 index 000000000..a3f479dc7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/RECORD @@ -0,0 +1,48 @@ +_cffi_backend.cpython-311-x86_64-linux-gnu.so,sha256=OQVrlpQYvwUgPc-eNf5g8Rbj-7aCFr7ApHvV1y1AgIo,1064368 +cffi-1.16.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +cffi-1.16.0.dist-info/LICENSE,sha256=BLgPWwd7vtaICM_rreteNSPyqMmpZJXFh72W3x6sKjM,1294 +cffi-1.16.0.dist-info/METADATA,sha256=qOBI2i0qSlLOKwmzNjbJfLmrTzHV_JFS7uKbcFj_p9Y,1480 +cffi-1.16.0.dist-info/RECORD,, +cffi-1.16.0.dist-info/WHEEL,sha256=48wUIcZcdQ2pWN7qt0HP02Cvv6HIQZGsSgx3PsepNj8,152 +cffi-1.16.0.dist-info/entry_points.txt,sha256=y6jTxnyeuLnL-XJcDv8uML3n6wyYiGRg8MTp_QGJ9Ho,75 +cffi-1.16.0.dist-info/top_level.txt,sha256=rE7WR3rZfNKxWI9-jn6hsHCAl7MDkB-FmuQbxWjFehQ,19 +cffi/__init__.py,sha256=uEnzaXlQndR9nc8ar1qk6_coNEfxfn4pA0sWPVg2MP8,513 +cffi/__pycache__/__init__.cpython-311.pyc,, +cffi/__pycache__/_imp_emulation.cpython-311.pyc,, +cffi/__pycache__/_shimmed_dist_utils.cpython-311.pyc,, +cffi/__pycache__/api.cpython-311.pyc,, +cffi/__pycache__/backend_ctypes.cpython-311.pyc,, +cffi/__pycache__/cffi_opcode.cpython-311.pyc,, +cffi/__pycache__/commontypes.cpython-311.pyc,, +cffi/__pycache__/cparser.cpython-311.pyc,, +cffi/__pycache__/error.cpython-311.pyc,, +cffi/__pycache__/ffiplatform.cpython-311.pyc,, +cffi/__pycache__/lock.cpython-311.pyc,, +cffi/__pycache__/model.cpython-311.pyc,, +cffi/__pycache__/pkgconfig.cpython-311.pyc,, +cffi/__pycache__/recompiler.cpython-311.pyc,, +cffi/__pycache__/setuptools_ext.cpython-311.pyc,, +cffi/__pycache__/vengine_cpy.cpython-311.pyc,, +cffi/__pycache__/vengine_gen.cpython-311.pyc,, +cffi/__pycache__/verifier.cpython-311.pyc,, +cffi/_cffi_errors.h,sha256=zQXt7uR_m8gUW-fI2hJg0KoSkJFwXv8RGUkEDZ177dQ,3908 +cffi/_cffi_include.h,sha256=tKnA1rdSoPHp23FnDL1mDGwFo-Uj6fXfA6vA6kcoEUc,14800 +cffi/_embedding.h,sha256=QEmrJKlB_W2VC601CjjyfMuxtgzPQwwEKFlwMCGHbT0,18787 +cffi/_imp_emulation.py,sha256=RxREG8zAbI2RPGBww90u_5fi8sWdahpdipOoPzkp7C0,2960 +cffi/_shimmed_dist_utils.py,sha256=mLuEtxw4gbuA2De_gD7zEhb6Q8Wm2lBPtwC68gd9XTs,2007 +cffi/api.py,sha256=wtJU0aGUC3TyYnjBIgsOIlv7drF19jV-y_srt7c8yhg,42085 +cffi/backend_ctypes.py,sha256=h5ZIzLc6BFVXnGyc9xPqZWUS7qGy7yFSDqXe68Sa8z4,42454 +cffi/cffi_opcode.py,sha256=v9RdD_ovA8rCtqsC95Ivki5V667rAOhGgs3fb2q9xpM,5724 +cffi/commontypes.py,sha256=QS4uxCDI7JhtTyjh1hlnCA-gynmaszWxJaRRLGkJa1A,2689 +cffi/cparser.py,sha256=rO_1pELRw1gI1DE1m4gi2ik5JMfpxouAACLXpRPlVEA,44231 +cffi/error.py,sha256=v6xTiS4U0kvDcy4h_BDRo5v39ZQuj-IMRYLv5ETddZs,877 +cffi/ffiplatform.py,sha256=avxFjdikYGJoEtmJO7ewVmwG_VEVl6EZ_WaNhZYCqv4,3584 +cffi/lock.py,sha256=l9TTdwMIMpi6jDkJGnQgE9cvTIR7CAntIJr8EGHt3pY,747 +cffi/model.py,sha256=RVsAb3h_u7VHWZJ-J_Z4kvB36pFyFG_MVIjPOQ8YhQ8,21790 +cffi/parse_c_type.h,sha256=OdwQfwM9ktq6vlCB43exFQmxDBtj2MBNdK8LYl15tjw,5976 +cffi/pkgconfig.py,sha256=LP1w7vmWvmKwyqLaU1Z243FOWGNQMrgMUZrvgFuOlco,4374 +cffi/recompiler.py,sha256=oTusgKQ02YY6LXhcmWcqpIlPrG178RMXXSBseSACRgg,64601 +cffi/setuptools_ext.py,sha256=-ebj79lO2_AUH-kRcaja2pKY1Z_5tloGwsJgzK8P3Cc,8871 +cffi/vengine_cpy.py,sha256=nK_im1DbdIGMMgxFgeo1MndFjaB-Qlkc2ZYlSquLjs0,43351 +cffi/vengine_gen.py,sha256=5dX7s1DU6pTBOMI6oTVn_8Bnmru_lj932B6b4v29Hlg,26684 +cffi/verifier.py,sha256=oX8jpaohg2Qm3aHcznidAdvrVm5N4sQYG0a3Eo5mIl4,11182 diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/WHEEL b/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/WHEEL new file mode 100644 index 000000000..6919a7b65 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.41.2) +Root-Is-Purelib: false +Tag: cp311-cp311-manylinux_2_17_x86_64 +Tag: cp311-cp311-manylinux2014_x86_64 + diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/entry_points.txt b/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/entry_points.txt new file mode 100644 index 000000000..4b0274f23 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[distutils.setup_keywords] +cffi_modules = cffi.setuptools_ext:cffi_modules diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/top_level.txt b/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/top_level.txt new file mode 100644 index 000000000..f64577957 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi-1.16.0.dist-info/top_level.txt @@ -0,0 +1,2 @@ +_cffi_backend +cffi diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/__init__.py new file mode 100644 index 000000000..90dedf433 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/__init__.py @@ -0,0 +1,14 @@ +__all__ = ['FFI', 'VerificationError', 'VerificationMissing', 'CDefError', + 'FFIError'] + +from .api import FFI +from .error import CDefError, FFIError, VerificationError, VerificationMissing +from .error import PkgConfigError + +__version__ = "1.16.0" +__version_info__ = (1, 16, 0) + +# The verifier module file names are based on the CRC32 of a string that +# contains the following version number. It may be older than __version__ +# if nothing is clearly incompatible. +__version_verifier_modules__ = "0.8.6" diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/_cffi_errors.h b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/_cffi_errors.h new file mode 100644 index 000000000..158e05903 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/_cffi_errors.h @@ -0,0 +1,149 @@ +#ifndef CFFI_MESSAGEBOX +# ifdef _MSC_VER +# define CFFI_MESSAGEBOX 1 +# else +# define CFFI_MESSAGEBOX 0 +# endif +#endif + + +#if CFFI_MESSAGEBOX +/* Windows only: logic to take the Python-CFFI embedding logic + initialization errors and display them in a background thread + with MessageBox. The idea is that if the whole program closes + as a result of this problem, then likely it is already a console + program and you can read the stderr output in the console too. + If it is not a console program, then it will likely show its own + dialog to complain, or generally not abruptly close, and for this + case the background thread should stay alive. +*/ +static void *volatile _cffi_bootstrap_text; + +static PyObject *_cffi_start_error_capture(void) +{ + PyObject *result = NULL; + PyObject *x, *m, *bi; + + if (InterlockedCompareExchangePointer(&_cffi_bootstrap_text, + (void *)1, NULL) != NULL) + return (PyObject *)1; + + m = PyImport_AddModule("_cffi_error_capture"); + if (m == NULL) + goto error; + + result = PyModule_GetDict(m); + if (result == NULL) + goto error; + +#if PY_MAJOR_VERSION >= 3 + bi = PyImport_ImportModule("builtins"); +#else + bi = PyImport_ImportModule("__builtin__"); +#endif + if (bi == NULL) + goto error; + PyDict_SetItemString(result, "__builtins__", bi); + Py_DECREF(bi); + + x = PyRun_String( + "import sys\n" + "class FileLike:\n" + " def write(self, x):\n" + " try:\n" + " of.write(x)\n" + " except: pass\n" + " self.buf += x\n" + " def flush(self):\n" + " pass\n" + "fl = FileLike()\n" + "fl.buf = ''\n" + "of = sys.stderr\n" + "sys.stderr = fl\n" + "def done():\n" + " sys.stderr = of\n" + " return fl.buf\n", /* make sure the returned value stays alive */ + Py_file_input, + result, result); + Py_XDECREF(x); + + error: + if (PyErr_Occurred()) + { + PyErr_WriteUnraisable(Py_None); + PyErr_Clear(); + } + return result; +} + +#pragma comment(lib, "user32.lib") + +static DWORD WINAPI _cffi_bootstrap_dialog(LPVOID ignored) +{ + Sleep(666); /* may be interrupted if the whole process is closing */ +#if PY_MAJOR_VERSION >= 3 + MessageBoxW(NULL, (wchar_t *)_cffi_bootstrap_text, + L"Python-CFFI error", + MB_OK | MB_ICONERROR); +#else + MessageBoxA(NULL, (char *)_cffi_bootstrap_text, + "Python-CFFI error", + MB_OK | MB_ICONERROR); +#endif + _cffi_bootstrap_text = NULL; + return 0; +} + +static void _cffi_stop_error_capture(PyObject *ecap) +{ + PyObject *s; + void *text; + + if (ecap == (PyObject *)1) + return; + + if (ecap == NULL) + goto error; + + s = PyRun_String("done()", Py_eval_input, ecap, ecap); + if (s == NULL) + goto error; + + /* Show a dialog box, but in a background thread, and + never show multiple dialog boxes at once. */ +#if PY_MAJOR_VERSION >= 3 + text = PyUnicode_AsWideCharString(s, NULL); +#else + text = PyString_AsString(s); +#endif + + _cffi_bootstrap_text = text; + + if (text != NULL) + { + HANDLE h; + h = CreateThread(NULL, 0, _cffi_bootstrap_dialog, + NULL, 0, NULL); + if (h != NULL) + CloseHandle(h); + } + /* decref the string, but it should stay alive as 'fl.buf' + in the small module above. It will really be freed only if + we later get another similar error. So it's a leak of at + most one copy of the small module. That's fine for this + situation which is usually a "fatal error" anyway. */ + Py_DECREF(s); + PyErr_Clear(); + return; + + error: + _cffi_bootstrap_text = NULL; + PyErr_Clear(); +} + +#else + +static PyObject *_cffi_start_error_capture(void) { return NULL; } +static void _cffi_stop_error_capture(PyObject *ecap) { } + +#endif diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/_cffi_include.h b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/_cffi_include.h new file mode 100644 index 000000000..e4c0a6724 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/_cffi_include.h @@ -0,0 +1,385 @@ +#define _CFFI_ + +/* We try to define Py_LIMITED_API before including Python.h. + + Mess: we can only define it if Py_DEBUG, Py_TRACE_REFS and + Py_REF_DEBUG are not defined. This is a best-effort approximation: + we can learn about Py_DEBUG from pyconfig.h, but it is unclear if + the same works for the other two macros. Py_DEBUG implies them, + but not the other way around. + + The implementation is messy (issue #350): on Windows, with _MSC_VER, + we have to define Py_LIMITED_API even before including pyconfig.h. + In that case, we guess what pyconfig.h will do to the macros above, + and check our guess after the #include. + + Note that on Windows, with CPython 3.x, you need >= 3.5 and virtualenv + version >= 16.0.0. With older versions of either, you don't get a + copy of PYTHON3.DLL in the virtualenv. We can't check the version of + CPython *before* we even include pyconfig.h. ffi.set_source() puts + a ``#define _CFFI_NO_LIMITED_API'' at the start of this file if it is + running on Windows < 3.5, as an attempt at fixing it, but that's + arguably wrong because it may not be the target version of Python. + Still better than nothing I guess. As another workaround, you can + remove the definition of Py_LIMITED_API here. + + See also 'py_limited_api' in cffi/setuptools_ext.py. +*/ +#if !defined(_CFFI_USE_EMBEDDING) && !defined(Py_LIMITED_API) +# ifdef _MSC_VER +# if !defined(_DEBUG) && !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) +# define Py_LIMITED_API +# endif +# include + /* sanity-check: Py_LIMITED_API will cause crashes if any of these + are also defined. Normally, the Python file PC/pyconfig.h does not + cause any of these to be defined, with the exception that _DEBUG + causes Py_DEBUG. Double-check that. */ +# ifdef Py_LIMITED_API +# if defined(Py_DEBUG) +# error "pyconfig.h unexpectedly defines Py_DEBUG, but Py_LIMITED_API is set" +# endif +# if defined(Py_TRACE_REFS) +# error "pyconfig.h unexpectedly defines Py_TRACE_REFS, but Py_LIMITED_API is set" +# endif +# if defined(Py_REF_DEBUG) +# error "pyconfig.h unexpectedly defines Py_REF_DEBUG, but Py_LIMITED_API is set" +# endif +# endif +# else +# include +# if !defined(Py_DEBUG) && !defined(Py_TRACE_REFS) && !defined(Py_REF_DEBUG) && !defined(_CFFI_NO_LIMITED_API) +# define Py_LIMITED_API +# endif +# endif +#endif + +#include +#ifdef __cplusplus +extern "C" { +#endif +#include +#include "parse_c_type.h" + +/* this block of #ifs should be kept exactly identical between + c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py + and cffi/_cffi_include.h */ +#if defined(_MSC_VER) +# include /* for alloca() */ +# if _MSC_VER < 1600 /* MSVC < 2010 */ + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int8 int_least8_t; + typedef __int16 int_least16_t; + typedef __int32 int_least32_t; + typedef __int64 int_least64_t; + typedef unsigned __int8 uint_least8_t; + typedef unsigned __int16 uint_least16_t; + typedef unsigned __int32 uint_least32_t; + typedef unsigned __int64 uint_least64_t; + typedef __int8 int_fast8_t; + typedef __int16 int_fast16_t; + typedef __int32 int_fast32_t; + typedef __int64 int_fast64_t; + typedef unsigned __int8 uint_fast8_t; + typedef unsigned __int16 uint_fast16_t; + typedef unsigned __int32 uint_fast32_t; + typedef unsigned __int64 uint_fast64_t; + typedef __int64 intmax_t; + typedef unsigned __int64 uintmax_t; +# else +# include +# endif +# if _MSC_VER < 1800 /* MSVC < 2013 */ +# ifndef __cplusplus + typedef unsigned char _Bool; +# endif +# endif +#else +# include +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) +# include +# endif +#endif + +#ifdef __GNUC__ +# define _CFFI_UNUSED_FN __attribute__((unused)) +#else +# define _CFFI_UNUSED_FN /* nothing */ +#endif + +#ifdef __cplusplus +# ifndef _Bool + typedef bool _Bool; /* semi-hackish: C++ has no _Bool; bool is builtin */ +# endif +#endif + +/********** CPython-specific section **********/ +#ifndef PYPY_VERSION + + +#if PY_MAJOR_VERSION >= 3 +# define PyInt_FromLong PyLong_FromLong +#endif + +#define _cffi_from_c_double PyFloat_FromDouble +#define _cffi_from_c_float PyFloat_FromDouble +#define _cffi_from_c_long PyInt_FromLong +#define _cffi_from_c_ulong PyLong_FromUnsignedLong +#define _cffi_from_c_longlong PyLong_FromLongLong +#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong +#define _cffi_from_c__Bool PyBool_FromLong + +#define _cffi_to_c_double PyFloat_AsDouble +#define _cffi_to_c_float PyFloat_AsDouble + +#define _cffi_from_c_int(x, type) \ + (((type)-1) > 0 ? /* unsigned */ \ + (sizeof(type) < sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + sizeof(type) == sizeof(long) ? \ + PyLong_FromUnsignedLong((unsigned long)x) : \ + PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ + (sizeof(type) <= sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + PyLong_FromLongLong((long long)x))) + +#define _cffi_to_c_int(o, type) \ + ((type)( \ + sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \ + : (type)_cffi_to_c_i8(o)) : \ + sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \ + : (type)_cffi_to_c_i16(o)) : \ + sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \ + : (type)_cffi_to_c_i32(o)) : \ + sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \ + : (type)_cffi_to_c_i64(o)) : \ + (Py_FatalError("unsupported size for type " #type), (type)0))) + +#define _cffi_to_c_i8 \ + ((int(*)(PyObject *))_cffi_exports[1]) +#define _cffi_to_c_u8 \ + ((int(*)(PyObject *))_cffi_exports[2]) +#define _cffi_to_c_i16 \ + ((int(*)(PyObject *))_cffi_exports[3]) +#define _cffi_to_c_u16 \ + ((int(*)(PyObject *))_cffi_exports[4]) +#define _cffi_to_c_i32 \ + ((int(*)(PyObject *))_cffi_exports[5]) +#define _cffi_to_c_u32 \ + ((unsigned int(*)(PyObject *))_cffi_exports[6]) +#define _cffi_to_c_i64 \ + ((long long(*)(PyObject *))_cffi_exports[7]) +#define _cffi_to_c_u64 \ + ((unsigned long long(*)(PyObject *))_cffi_exports[8]) +#define _cffi_to_c_char \ + ((int(*)(PyObject *))_cffi_exports[9]) +#define _cffi_from_c_pointer \ + ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[10]) +#define _cffi_to_c_pointer \ + ((char *(*)(PyObject *, struct _cffi_ctypedescr *))_cffi_exports[11]) +#define _cffi_get_struct_layout \ + not used any more +#define _cffi_restore_errno \ + ((void(*)(void))_cffi_exports[13]) +#define _cffi_save_errno \ + ((void(*)(void))_cffi_exports[14]) +#define _cffi_from_c_char \ + ((PyObject *(*)(char))_cffi_exports[15]) +#define _cffi_from_c_deref \ + ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[16]) +#define _cffi_to_c \ + ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[17]) +#define _cffi_from_c_struct \ + ((PyObject *(*)(char *, struct _cffi_ctypedescr *))_cffi_exports[18]) +#define _cffi_to_c_wchar_t \ + ((_cffi_wchar_t(*)(PyObject *))_cffi_exports[19]) +#define _cffi_from_c_wchar_t \ + ((PyObject *(*)(_cffi_wchar_t))_cffi_exports[20]) +#define _cffi_to_c_long_double \ + ((long double(*)(PyObject *))_cffi_exports[21]) +#define _cffi_to_c__Bool \ + ((_Bool(*)(PyObject *))_cffi_exports[22]) +#define _cffi_prepare_pointer_call_argument \ + ((Py_ssize_t(*)(struct _cffi_ctypedescr *, \ + PyObject *, char **))_cffi_exports[23]) +#define _cffi_convert_array_from_object \ + ((int(*)(char *, struct _cffi_ctypedescr *, PyObject *))_cffi_exports[24]) +#define _CFFI_CPIDX 25 +#define _cffi_call_python \ + ((void(*)(struct _cffi_externpy_s *, char *))_cffi_exports[_CFFI_CPIDX]) +#define _cffi_to_c_wchar3216_t \ + ((int(*)(PyObject *))_cffi_exports[26]) +#define _cffi_from_c_wchar3216_t \ + ((PyObject *(*)(int))_cffi_exports[27]) +#define _CFFI_NUM_EXPORTS 28 + +struct _cffi_ctypedescr; + +static void *_cffi_exports[_CFFI_NUM_EXPORTS]; + +#define _cffi_type(index) ( \ + assert((((uintptr_t)_cffi_types[index]) & 1) == 0), \ + (struct _cffi_ctypedescr *)_cffi_types[index]) + +static PyObject *_cffi_init(const char *module_name, Py_ssize_t version, + const struct _cffi_type_context_s *ctx) +{ + PyObject *module, *o_arg, *new_module; + void *raw[] = { + (void *)module_name, + (void *)version, + (void *)_cffi_exports, + (void *)ctx, + }; + + module = PyImport_ImportModule("_cffi_backend"); + if (module == NULL) + goto failure; + + o_arg = PyLong_FromVoidPtr((void *)raw); + if (o_arg == NULL) + goto failure; + + new_module = PyObject_CallMethod( + module, (char *)"_init_cffi_1_0_external_module", (char *)"O", o_arg); + + Py_DECREF(o_arg); + Py_DECREF(module); + return new_module; + + failure: + Py_XDECREF(module); + return NULL; +} + + +#ifdef HAVE_WCHAR_H +typedef wchar_t _cffi_wchar_t; +#else +typedef uint16_t _cffi_wchar_t; /* same random pick as _cffi_backend.c */ +#endif + +_CFFI_UNUSED_FN static uint16_t _cffi_to_c_char16_t(PyObject *o) +{ + if (sizeof(_cffi_wchar_t) == 2) + return (uint16_t)_cffi_to_c_wchar_t(o); + else + return (uint16_t)_cffi_to_c_wchar3216_t(o); +} + +_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char16_t(uint16_t x) +{ + if (sizeof(_cffi_wchar_t) == 2) + return _cffi_from_c_wchar_t((_cffi_wchar_t)x); + else + return _cffi_from_c_wchar3216_t((int)x); +} + +_CFFI_UNUSED_FN static int _cffi_to_c_char32_t(PyObject *o) +{ + if (sizeof(_cffi_wchar_t) == 4) + return (int)_cffi_to_c_wchar_t(o); + else + return (int)_cffi_to_c_wchar3216_t(o); +} + +_CFFI_UNUSED_FN static PyObject *_cffi_from_c_char32_t(unsigned int x) +{ + if (sizeof(_cffi_wchar_t) == 4) + return _cffi_from_c_wchar_t((_cffi_wchar_t)x); + else + return _cffi_from_c_wchar3216_t((int)x); +} + +union _cffi_union_alignment_u { + unsigned char m_char; + unsigned short m_short; + unsigned int m_int; + unsigned long m_long; + unsigned long long m_longlong; + float m_float; + double m_double; + long double m_longdouble; +}; + +struct _cffi_freeme_s { + struct _cffi_freeme_s *next; + union _cffi_union_alignment_u alignment; +}; + +_CFFI_UNUSED_FN static int +_cffi_convert_array_argument(struct _cffi_ctypedescr *ctptr, PyObject *arg, + char **output_data, Py_ssize_t datasize, + struct _cffi_freeme_s **freeme) +{ + char *p; + if (datasize < 0) + return -1; + + p = *output_data; + if (p == NULL) { + struct _cffi_freeme_s *fp = (struct _cffi_freeme_s *)PyObject_Malloc( + offsetof(struct _cffi_freeme_s, alignment) + (size_t)datasize); + if (fp == NULL) + return -1; + fp->next = *freeme; + *freeme = fp; + p = *output_data = (char *)&fp->alignment; + } + memset((void *)p, 0, (size_t)datasize); + return _cffi_convert_array_from_object(p, ctptr, arg); +} + +_CFFI_UNUSED_FN static void +_cffi_free_array_arguments(struct _cffi_freeme_s *freeme) +{ + do { + void *p = (void *)freeme; + freeme = freeme->next; + PyObject_Free(p); + } while (freeme != NULL); +} + +/********** end CPython-specific section **********/ +#else +_CFFI_UNUSED_FN +static void (*_cffi_call_python_org)(struct _cffi_externpy_s *, char *); +# define _cffi_call_python _cffi_call_python_org +#endif + + +#define _cffi_array_len(array) (sizeof(array) / sizeof((array)[0])) + +#define _cffi_prim_int(size, sign) \ + ((size) == 1 ? ((sign) ? _CFFI_PRIM_INT8 : _CFFI_PRIM_UINT8) : \ + (size) == 2 ? ((sign) ? _CFFI_PRIM_INT16 : _CFFI_PRIM_UINT16) : \ + (size) == 4 ? ((sign) ? _CFFI_PRIM_INT32 : _CFFI_PRIM_UINT32) : \ + (size) == 8 ? ((sign) ? _CFFI_PRIM_INT64 : _CFFI_PRIM_UINT64) : \ + _CFFI__UNKNOWN_PRIM) + +#define _cffi_prim_float(size) \ + ((size) == sizeof(float) ? _CFFI_PRIM_FLOAT : \ + (size) == sizeof(double) ? _CFFI_PRIM_DOUBLE : \ + (size) == sizeof(long double) ? _CFFI__UNKNOWN_LONG_DOUBLE : \ + _CFFI__UNKNOWN_FLOAT_PRIM) + +#define _cffi_check_int(got, got_nonpos, expected) \ + ((got_nonpos) == (expected <= 0) && \ + (got) == (unsigned long long)expected) + +#ifdef MS_WIN32 +# define _cffi_stdcall __stdcall +#else +# define _cffi_stdcall /* nothing */ +#endif + +#ifdef __cplusplus +} +#endif diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/_embedding.h b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/_embedding.h new file mode 100644 index 000000000..1cb66f235 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/_embedding.h @@ -0,0 +1,550 @@ + +/***** Support code for embedding *****/ + +#ifdef __cplusplus +extern "C" { +#endif + + +#if defined(_WIN32) +# define CFFI_DLLEXPORT __declspec(dllexport) +#elif defined(__GNUC__) +# define CFFI_DLLEXPORT __attribute__((visibility("default"))) +#else +# define CFFI_DLLEXPORT /* nothing */ +#endif + + +/* There are two global variables of type _cffi_call_python_fnptr: + + * _cffi_call_python, which we declare just below, is the one called + by ``extern "Python"`` implementations. + + * _cffi_call_python_org, which on CPython is actually part of the + _cffi_exports[] array, is the function pointer copied from + _cffi_backend. If _cffi_start_python() fails, then this is set + to NULL; otherwise, it should never be NULL. + + After initialization is complete, both are equal. However, the + first one remains equal to &_cffi_start_and_call_python until the + very end of initialization, when we are (or should be) sure that + concurrent threads also see a completely initialized world, and + only then is it changed. +*/ +#undef _cffi_call_python +typedef void (*_cffi_call_python_fnptr)(struct _cffi_externpy_s *, char *); +static void _cffi_start_and_call_python(struct _cffi_externpy_s *, char *); +static _cffi_call_python_fnptr _cffi_call_python = &_cffi_start_and_call_python; + + +#ifndef _MSC_VER + /* --- Assuming a GCC not infinitely old --- */ +# define cffi_compare_and_swap(l,o,n) __sync_bool_compare_and_swap(l,o,n) +# define cffi_write_barrier() __sync_synchronize() +# if !defined(__amd64__) && !defined(__x86_64__) && \ + !defined(__i386__) && !defined(__i386) +# define cffi_read_barrier() __sync_synchronize() +# else +# define cffi_read_barrier() (void)0 +# endif +#else + /* --- Windows threads version --- */ +# include +# define cffi_compare_and_swap(l,o,n) \ + (InterlockedCompareExchangePointer(l,n,o) == (o)) +# define cffi_write_barrier() InterlockedCompareExchange(&_cffi_dummy,0,0) +# define cffi_read_barrier() (void)0 +static volatile LONG _cffi_dummy; +#endif + +#ifdef WITH_THREAD +# ifndef _MSC_VER +# include + static pthread_mutex_t _cffi_embed_startup_lock; +# else + static CRITICAL_SECTION _cffi_embed_startup_lock; +# endif + static char _cffi_embed_startup_lock_ready = 0; +#endif + +static void _cffi_acquire_reentrant_mutex(void) +{ + static void *volatile lock = NULL; + + while (!cffi_compare_and_swap(&lock, NULL, (void *)1)) { + /* should ideally do a spin loop instruction here, but + hard to do it portably and doesn't really matter I + think: pthread_mutex_init() should be very fast, and + this is only run at start-up anyway. */ + } + +#ifdef WITH_THREAD + if (!_cffi_embed_startup_lock_ready) { +# ifndef _MSC_VER + pthread_mutexattr_t attr; + pthread_mutexattr_init(&attr); + pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); + pthread_mutex_init(&_cffi_embed_startup_lock, &attr); +# else + InitializeCriticalSection(&_cffi_embed_startup_lock); +# endif + _cffi_embed_startup_lock_ready = 1; + } +#endif + + while (!cffi_compare_and_swap(&lock, (void *)1, NULL)) + ; + +#ifndef _MSC_VER + pthread_mutex_lock(&_cffi_embed_startup_lock); +#else + EnterCriticalSection(&_cffi_embed_startup_lock); +#endif +} + +static void _cffi_release_reentrant_mutex(void) +{ +#ifndef _MSC_VER + pthread_mutex_unlock(&_cffi_embed_startup_lock); +#else + LeaveCriticalSection(&_cffi_embed_startup_lock); +#endif +} + + +/********** CPython-specific section **********/ +#ifndef PYPY_VERSION + +#include "_cffi_errors.h" + + +#define _cffi_call_python_org _cffi_exports[_CFFI_CPIDX] + +PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(void); /* forward */ + +static void _cffi_py_initialize(void) +{ + /* XXX use initsigs=0, which "skips initialization registration of + signal handlers, which might be useful when Python is + embedded" according to the Python docs. But review and think + if it should be a user-controllable setting. + + XXX we should also give a way to write errors to a buffer + instead of to stderr. + + XXX if importing 'site' fails, CPython (any version) calls + exit(). Should we try to work around this behavior here? + */ + Py_InitializeEx(0); +} + +static int _cffi_initialize_python(void) +{ + /* This initializes Python, imports _cffi_backend, and then the + present .dll/.so is set up as a CPython C extension module. + */ + int result; + PyGILState_STATE state; + PyObject *pycode=NULL, *global_dict=NULL, *x; + PyObject *builtins; + + state = PyGILState_Ensure(); + + /* Call the initxxx() function from the present module. It will + create and initialize us as a CPython extension module, instead + of letting the startup Python code do it---it might reimport + the same .dll/.so and get maybe confused on some platforms. + It might also have troubles locating the .dll/.so again for all + I know. + */ + (void)_CFFI_PYTHON_STARTUP_FUNC(); + if (PyErr_Occurred()) + goto error; + + /* Now run the Python code provided to ffi.embedding_init_code(). + */ + pycode = Py_CompileString(_CFFI_PYTHON_STARTUP_CODE, + "", + Py_file_input); + if (pycode == NULL) + goto error; + global_dict = PyDict_New(); + if (global_dict == NULL) + goto error; + builtins = PyEval_GetBuiltins(); + if (builtins == NULL) + goto error; + if (PyDict_SetItemString(global_dict, "__builtins__", builtins) < 0) + goto error; + x = PyEval_EvalCode( +#if PY_MAJOR_VERSION < 3 + (PyCodeObject *) +#endif + pycode, global_dict, global_dict); + if (x == NULL) + goto error; + Py_DECREF(x); + + /* Done! Now if we've been called from + _cffi_start_and_call_python() in an ``extern "Python"``, we can + only hope that the Python code did correctly set up the + corresponding @ffi.def_extern() function. Otherwise, the + general logic of ``extern "Python"`` functions (inside the + _cffi_backend module) will find that the reference is still + missing and print an error. + */ + result = 0; + done: + Py_XDECREF(pycode); + Py_XDECREF(global_dict); + PyGILState_Release(state); + return result; + + error:; + { + /* Print as much information as potentially useful. + Debugging load-time failures with embedding is not fun + */ + PyObject *ecap; + PyObject *exception, *v, *tb, *f, *modules, *mod; + PyErr_Fetch(&exception, &v, &tb); + ecap = _cffi_start_error_capture(); + f = PySys_GetObject((char *)"stderr"); + if (f != NULL && f != Py_None) { + PyFile_WriteString( + "Failed to initialize the Python-CFFI embedding logic:\n\n", f); + } + + if (exception != NULL) { + PyErr_NormalizeException(&exception, &v, &tb); + PyErr_Display(exception, v, tb); + } + Py_XDECREF(exception); + Py_XDECREF(v); + Py_XDECREF(tb); + + if (f != NULL && f != Py_None) { + PyFile_WriteString("\nFrom: " _CFFI_MODULE_NAME + "\ncompiled with cffi version: 1.16.0" + "\n_cffi_backend module: ", f); + modules = PyImport_GetModuleDict(); + mod = PyDict_GetItemString(modules, "_cffi_backend"); + if (mod == NULL) { + PyFile_WriteString("not loaded", f); + } + else { + v = PyObject_GetAttrString(mod, "__file__"); + PyFile_WriteObject(v, f, 0); + Py_XDECREF(v); + } + PyFile_WriteString("\nsys.path: ", f); + PyFile_WriteObject(PySys_GetObject((char *)"path"), f, 0); + PyFile_WriteString("\n\n", f); + } + _cffi_stop_error_capture(ecap); + } + result = -1; + goto done; +} + +#if PY_VERSION_HEX < 0x03080000 +PyAPI_DATA(char *) _PyParser_TokenNames[]; /* from CPython */ +#endif + +static int _cffi_carefully_make_gil(void) +{ + /* This does the basic initialization of Python. It can be called + completely concurrently from unrelated threads. It assumes + that we don't hold the GIL before (if it exists), and we don't + hold it afterwards. + + (What it really does used to be completely different in Python 2 + and Python 3, with the Python 2 solution avoiding the spin-lock + around the Py_InitializeEx() call. However, after recent changes + to CPython 2.7 (issue #358) it no longer works. So we use the + Python 3 solution everywhere.) + + This initializes Python by calling Py_InitializeEx(). + Important: this must not be called concurrently at all. + So we use a global variable as a simple spin lock. This global + variable must be from 'libpythonX.Y.so', not from this + cffi-based extension module, because it must be shared from + different cffi-based extension modules. + + In Python < 3.8, we choose + _PyParser_TokenNames[0] as a completely arbitrary pointer value + that is never written to. The default is to point to the + string "ENDMARKER". We change it temporarily to point to the + next character in that string. (Yes, I know it's REALLY + obscure.) + + In Python >= 3.8, this string array is no longer writable, so + instead we pick PyCapsuleType.tp_version_tag. We can't change + Python < 3.8 because someone might use a mixture of cffi + embedded modules, some of which were compiled before this file + changed. + + In Python >= 3.12, this stopped working because that particular + tp_version_tag gets modified during interpreter startup. It's + arguably a bad idea before 3.12 too, but again we can't change + that because someone might use a mixture of cffi embedded + modules, and no-one reported a bug so far. In Python >= 3.12 + we go instead for PyCapsuleType.tp_as_buffer, which is supposed + to always be NULL. We write to it temporarily a pointer to + a struct full of NULLs, which is semantically the same. + */ + +#ifdef WITH_THREAD +# if PY_VERSION_HEX < 0x03080000 + char *volatile *lock = (char *volatile *)_PyParser_TokenNames; + char *old_value, *locked_value; + + while (1) { /* spin loop */ + old_value = *lock; + locked_value = old_value + 1; + if (old_value[0] == 'E') { + assert(old_value[1] == 'N'); + if (cffi_compare_and_swap(lock, old_value, locked_value)) + break; + } + else { + assert(old_value[0] == 'N'); + /* should ideally do a spin loop instruction here, but + hard to do it portably and doesn't really matter I + think: PyEval_InitThreads() should be very fast, and + this is only run at start-up anyway. */ + } + } +# else +# if PY_VERSION_HEX < 0x030C0000 + int volatile *lock = (int volatile *)&PyCapsule_Type.tp_version_tag; + int old_value, locked_value = -42; + assert(!(PyCapsule_Type.tp_flags & Py_TPFLAGS_HAVE_VERSION_TAG)); +# else + static struct ebp_s { PyBufferProcs buf; int mark; } empty_buffer_procs; + empty_buffer_procs.mark = -42; + PyBufferProcs *volatile *lock = (PyBufferProcs *volatile *) + &PyCapsule_Type.tp_as_buffer; + PyBufferProcs *old_value, *locked_value = &empty_buffer_procs.buf; +# endif + + while (1) { /* spin loop */ + old_value = *lock; + if (old_value == 0) { + if (cffi_compare_and_swap(lock, old_value, locked_value)) + break; + } + else { +# if PY_VERSION_HEX < 0x030C0000 + assert(old_value == locked_value); +# else + /* The pointer should point to a possibly different + empty_buffer_procs from another C extension module */ + assert(((struct ebp_s *)old_value)->mark == -42); +# endif + /* should ideally do a spin loop instruction here, but + hard to do it portably and doesn't really matter I + think: PyEval_InitThreads() should be very fast, and + this is only run at start-up anyway. */ + } + } +# endif +#endif + + /* call Py_InitializeEx() */ + if (!Py_IsInitialized()) { + _cffi_py_initialize(); +#if PY_VERSION_HEX < 0x03070000 + PyEval_InitThreads(); +#endif + PyEval_SaveThread(); /* release the GIL */ + /* the returned tstate must be the one that has been stored into the + autoTLSkey by _PyGILState_Init() called from Py_Initialize(). */ + } + else { +#if PY_VERSION_HEX < 0x03070000 + /* PyEval_InitThreads() is always a no-op from CPython 3.7 */ + PyGILState_STATE state = PyGILState_Ensure(); + PyEval_InitThreads(); + PyGILState_Release(state); +#endif + } + +#ifdef WITH_THREAD + /* release the lock */ + while (!cffi_compare_and_swap(lock, locked_value, old_value)) + ; +#endif + + return 0; +} + +/********** end CPython-specific section **********/ + + +#else + + +/********** PyPy-specific section **********/ + +PyMODINIT_FUNC _CFFI_PYTHON_STARTUP_FUNC(const void *[]); /* forward */ + +static struct _cffi_pypy_init_s { + const char *name; + void *func; /* function pointer */ + const char *code; +} _cffi_pypy_init = { + _CFFI_MODULE_NAME, + _CFFI_PYTHON_STARTUP_FUNC, + _CFFI_PYTHON_STARTUP_CODE, +}; + +extern int pypy_carefully_make_gil(const char *); +extern int pypy_init_embedded_cffi_module(int, struct _cffi_pypy_init_s *); + +static int _cffi_carefully_make_gil(void) +{ + return pypy_carefully_make_gil(_CFFI_MODULE_NAME); +} + +static int _cffi_initialize_python(void) +{ + return pypy_init_embedded_cffi_module(0xB011, &_cffi_pypy_init); +} + +/********** end PyPy-specific section **********/ + + +#endif + + +#ifdef __GNUC__ +__attribute__((noinline)) +#endif +static _cffi_call_python_fnptr _cffi_start_python(void) +{ + /* Delicate logic to initialize Python. This function can be + called multiple times concurrently, e.g. when the process calls + its first ``extern "Python"`` functions in multiple threads at + once. It can also be called recursively, in which case we must + ignore it. We also have to consider what occurs if several + different cffi-based extensions reach this code in parallel + threads---it is a different copy of the code, then, and we + can't have any shared global variable unless it comes from + 'libpythonX.Y.so'. + + Idea: + + * _cffi_carefully_make_gil(): "carefully" call + PyEval_InitThreads() (possibly with Py_InitializeEx() first). + + * then we use a (local) custom lock to make sure that a call to this + cffi-based extension will wait if another call to the *same* + extension is running the initialization in another thread. + It is reentrant, so that a recursive call will not block, but + only one from a different thread. + + * then we grab the GIL and (Python 2) we call Py_InitializeEx(). + At this point, concurrent calls to Py_InitializeEx() are not + possible: we have the GIL. + + * do the rest of the specific initialization, which may + temporarily release the GIL but not the custom lock. + Only release the custom lock when we are done. + */ + static char called = 0; + + if (_cffi_carefully_make_gil() != 0) + return NULL; + + _cffi_acquire_reentrant_mutex(); + + /* Here the GIL exists, but we don't have it. We're only protected + from concurrency by the reentrant mutex. */ + + /* This file only initializes the embedded module once, the first + time this is called, even if there are subinterpreters. */ + if (!called) { + called = 1; /* invoke _cffi_initialize_python() only once, + but don't set '_cffi_call_python' right now, + otherwise concurrent threads won't call + this function at all (we need them to wait) */ + if (_cffi_initialize_python() == 0) { + /* now initialization is finished. Switch to the fast-path. */ + + /* We would like nobody to see the new value of + '_cffi_call_python' without also seeing the rest of the + data initialized. However, this is not possible. But + the new value of '_cffi_call_python' is the function + 'cffi_call_python()' from _cffi_backend. So: */ + cffi_write_barrier(); + /* ^^^ we put a write barrier here, and a corresponding + read barrier at the start of cffi_call_python(). This + ensures that after that read barrier, we see everything + done here before the write barrier. + */ + + assert(_cffi_call_python_org != NULL); + _cffi_call_python = (_cffi_call_python_fnptr)_cffi_call_python_org; + } + else { + /* initialization failed. Reset this to NULL, even if it was + already set to some other value. Future calls to + _cffi_start_python() are still forced to occur, and will + always return NULL from now on. */ + _cffi_call_python_org = NULL; + } + } + + _cffi_release_reentrant_mutex(); + + return (_cffi_call_python_fnptr)_cffi_call_python_org; +} + +static +void _cffi_start_and_call_python(struct _cffi_externpy_s *externpy, char *args) +{ + _cffi_call_python_fnptr fnptr; + int current_err = errno; +#ifdef _MSC_VER + int current_lasterr = GetLastError(); +#endif + fnptr = _cffi_start_python(); + if (fnptr == NULL) { + fprintf(stderr, "function %s() called, but initialization code " + "failed. Returning 0.\n", externpy->name); + memset(args, 0, externpy->size_of_result); + } +#ifdef _MSC_VER + SetLastError(current_lasterr); +#endif + errno = current_err; + + if (fnptr != NULL) + fnptr(externpy, args); +} + + +/* The cffi_start_python() function makes sure Python is initialized + and our cffi module is set up. It can be called manually from the + user C code. The same effect is obtained automatically from any + dll-exported ``extern "Python"`` function. This function returns + -1 if initialization failed, 0 if all is OK. */ +_CFFI_UNUSED_FN +static int cffi_start_python(void) +{ + if (_cffi_call_python == &_cffi_start_and_call_python) { + if (_cffi_start_python() == NULL) + return -1; + } + cffi_read_barrier(); + return 0; +} + +#undef cffi_compare_and_swap +#undef cffi_write_barrier +#undef cffi_read_barrier + +#ifdef __cplusplus +} +#endif diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/_imp_emulation.py b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/_imp_emulation.py new file mode 100644 index 000000000..136abdddf --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/_imp_emulation.py @@ -0,0 +1,83 @@ + +try: + # this works on Python < 3.12 + from imp import * + +except ImportError: + # this is a limited emulation for Python >= 3.12. + # Note that this is used only for tests or for the old ffi.verify(). + # This is copied from the source code of Python 3.11. + + from _imp import (acquire_lock, release_lock, + is_builtin, is_frozen) + + from importlib._bootstrap import _load + + from importlib import machinery + import os + import sys + import tokenize + + SEARCH_ERROR = 0 + PY_SOURCE = 1 + PY_COMPILED = 2 + C_EXTENSION = 3 + PY_RESOURCE = 4 + PKG_DIRECTORY = 5 + C_BUILTIN = 6 + PY_FROZEN = 7 + PY_CODERESOURCE = 8 + IMP_HOOK = 9 + + def get_suffixes(): + extensions = [(s, 'rb', C_EXTENSION) + for s in machinery.EXTENSION_SUFFIXES] + source = [(s, 'r', PY_SOURCE) for s in machinery.SOURCE_SUFFIXES] + bytecode = [(s, 'rb', PY_COMPILED) for s in machinery.BYTECODE_SUFFIXES] + return extensions + source + bytecode + + def find_module(name, path=None): + if not isinstance(name, str): + raise TypeError("'name' must be a str, not {}".format(type(name))) + elif not isinstance(path, (type(None), list)): + # Backwards-compatibility + raise RuntimeError("'path' must be None or a list, " + "not {}".format(type(path))) + + if path is None: + if is_builtin(name): + return None, None, ('', '', C_BUILTIN) + elif is_frozen(name): + return None, None, ('', '', PY_FROZEN) + else: + path = sys.path + + for entry in path: + package_directory = os.path.join(entry, name) + for suffix in ['.py', machinery.BYTECODE_SUFFIXES[0]]: + package_file_name = '__init__' + suffix + file_path = os.path.join(package_directory, package_file_name) + if os.path.isfile(file_path): + return None, package_directory, ('', '', PKG_DIRECTORY) + for suffix, mode, type_ in get_suffixes(): + file_name = name + suffix + file_path = os.path.join(entry, file_name) + if os.path.isfile(file_path): + break + else: + continue + break # Break out of outer loop when breaking out of inner loop. + else: + raise ImportError(name, name=name) + + encoding = None + if 'b' not in mode: + with open(file_path, 'rb') as file: + encoding = tokenize.detect_encoding(file.readline)[0] + file = open(file_path, mode, encoding=encoding) + return file, file_path, (suffix, mode, type_) + + def load_dynamic(name, path, file=None): + loader = machinery.ExtensionFileLoader(name, path) + spec = machinery.ModuleSpec(name=name, loader=loader, origin=path) + return _load(spec) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/_shimmed_dist_utils.py b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/_shimmed_dist_utils.py new file mode 100644 index 000000000..611bf40f4 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/_shimmed_dist_utils.py @@ -0,0 +1,41 @@ +""" +Temporary shim module to indirect the bits of distutils we need from setuptools/distutils while providing useful +error messages beyond `No module named 'distutils' on Python >= 3.12, or when setuptools' vendored distutils is broken. + +This is a compromise to avoid a hard-dep on setuptools for Python >= 3.12, since many users don't need runtime compilation support from CFFI. +""" +import sys + +try: + # import setuptools first; this is the most robust way to ensure its embedded distutils is available + # (the .pth shim should usually work, but this is even more robust) + import setuptools +except Exception as ex: + if sys.version_info >= (3, 12): + # Python 3.12 has no built-in distutils to fall back on, so any import problem is fatal + raise Exception("This CFFI feature requires setuptools on Python >= 3.12. The setuptools module is missing or non-functional.") from ex + + # silently ignore on older Pythons (support fallback to stdlib distutils where available) +else: + del setuptools + +try: + # bring in just the bits of distutils we need, whether they really came from setuptools or stdlib-embedded distutils + from distutils import log, sysconfig + from distutils.ccompiler import CCompiler + from distutils.command.build_ext import build_ext + from distutils.core import Distribution, Extension + from distutils.dir_util import mkpath + from distutils.errors import DistutilsSetupError, CompileError, LinkError + from distutils.log import set_threshold, set_verbosity + + if sys.platform == 'win32': + from distutils.msvc9compiler import MSVCCompiler +except Exception as ex: + if sys.version_info >= (3, 12): + raise Exception("This CFFI feature requires setuptools on Python >= 3.12. Please install the setuptools package.") from ex + + # anything older, just let the underlying distutils import error fly + raise Exception("This CFFI feature requires distutils. Please install the distutils or setuptools package.") from ex + +del sys diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/api.py b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/api.py new file mode 100644 index 000000000..edeb79281 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/api.py @@ -0,0 +1,965 @@ +import sys, types +from .lock import allocate_lock +from .error import CDefError +from . import model + +try: + callable +except NameError: + # Python 3.1 + from collections import Callable + callable = lambda x: isinstance(x, Callable) + +try: + basestring +except NameError: + # Python 3.x + basestring = str + +_unspecified = object() + + + +class FFI(object): + r''' + The main top-level class that you instantiate once, or once per module. + + Example usage: + + ffi = FFI() + ffi.cdef(""" + int printf(const char *, ...); + """) + + C = ffi.dlopen(None) # standard library + -or- + C = ffi.verify() # use a C compiler: verify the decl above is right + + C.printf("hello, %s!\n", ffi.new("char[]", "world")) + ''' + + def __init__(self, backend=None): + """Create an FFI instance. The 'backend' argument is used to + select a non-default backend, mostly for tests. + """ + if backend is None: + # You need PyPy (>= 2.0 beta), or a CPython (>= 2.6) with + # _cffi_backend.so compiled. + import _cffi_backend as backend + from . import __version__ + if backend.__version__ != __version__: + # bad version! Try to be as explicit as possible. + if hasattr(backend, '__file__'): + # CPython + raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. When we import the top-level '_cffi_backend' extension module, we get version %s, located in %r. The two versions should be equal; check your installation." % ( + __version__, __file__, + backend.__version__, backend.__file__)) + else: + # PyPy + raise Exception("Version mismatch: this is the 'cffi' package version %s, located in %r. This interpreter comes with a built-in '_cffi_backend' module, which is version %s. The two versions should be equal; check your installation." % ( + __version__, __file__, backend.__version__)) + # (If you insist you can also try to pass the option + # 'backend=backend_ctypes.CTypesBackend()', but don't + # rely on it! It's probably not going to work well.) + + from . import cparser + self._backend = backend + self._lock = allocate_lock() + self._parser = cparser.Parser() + self._cached_btypes = {} + self._parsed_types = types.ModuleType('parsed_types').__dict__ + self._new_types = types.ModuleType('new_types').__dict__ + self._function_caches = [] + self._libraries = [] + self._cdefsources = [] + self._included_ffis = [] + self._windows_unicode = None + self._init_once_cache = {} + self._cdef_version = None + self._embedding = None + self._typecache = model.get_typecache(backend) + if hasattr(backend, 'set_ffi'): + backend.set_ffi(self) + for name in list(backend.__dict__): + if name.startswith('RTLD_'): + setattr(self, name, getattr(backend, name)) + # + with self._lock: + self.BVoidP = self._get_cached_btype(model.voidp_type) + self.BCharA = self._get_cached_btype(model.char_array_type) + if isinstance(backend, types.ModuleType): + # _cffi_backend: attach these constants to the class + if not hasattr(FFI, 'NULL'): + FFI.NULL = self.cast(self.BVoidP, 0) + FFI.CData, FFI.CType = backend._get_types() + else: + # ctypes backend: attach these constants to the instance + self.NULL = self.cast(self.BVoidP, 0) + self.CData, self.CType = backend._get_types() + self.buffer = backend.buffer + + def cdef(self, csource, override=False, packed=False, pack=None): + """Parse the given C source. This registers all declared functions, + types, and global variables. The functions and global variables can + then be accessed via either 'ffi.dlopen()' or 'ffi.verify()'. + The types can be used in 'ffi.new()' and other functions. + If 'packed' is specified as True, all structs declared inside this + cdef are packed, i.e. laid out without any field alignment at all. + Alternatively, 'pack' can be a small integer, and requests for + alignment greater than that are ignored (pack=1 is equivalent to + packed=True). + """ + self._cdef(csource, override=override, packed=packed, pack=pack) + + def embedding_api(self, csource, packed=False, pack=None): + self._cdef(csource, packed=packed, pack=pack, dllexport=True) + if self._embedding is None: + self._embedding = '' + + def _cdef(self, csource, override=False, **options): + if not isinstance(csource, str): # unicode, on Python 2 + if not isinstance(csource, basestring): + raise TypeError("cdef() argument must be a string") + csource = csource.encode('ascii') + with self._lock: + self._cdef_version = object() + self._parser.parse(csource, override=override, **options) + self._cdefsources.append(csource) + if override: + for cache in self._function_caches: + cache.clear() + finishlist = self._parser._recomplete + if finishlist: + self._parser._recomplete = [] + for tp in finishlist: + tp.finish_backend_type(self, finishlist) + + def dlopen(self, name, flags=0): + """Load and return a dynamic library identified by 'name'. + The standard C library can be loaded by passing None. + Note that functions and types declared by 'ffi.cdef()' are not + linked to a particular library, just like C headers; in the + library we only look for the actual (untyped) symbols. + """ + if not (isinstance(name, basestring) or + name is None or + isinstance(name, self.CData)): + raise TypeError("dlopen(name): name must be a file name, None, " + "or an already-opened 'void *' handle") + with self._lock: + lib, function_cache = _make_ffi_library(self, name, flags) + self._function_caches.append(function_cache) + self._libraries.append(lib) + return lib + + def dlclose(self, lib): + """Close a library obtained with ffi.dlopen(). After this call, + access to functions or variables from the library will fail + (possibly with a segmentation fault). + """ + type(lib).__cffi_close__(lib) + + def _typeof_locked(self, cdecl): + # call me with the lock! + key = cdecl + if key in self._parsed_types: + return self._parsed_types[key] + # + if not isinstance(cdecl, str): # unicode, on Python 2 + cdecl = cdecl.encode('ascii') + # + type = self._parser.parse_type(cdecl) + really_a_function_type = type.is_raw_function + if really_a_function_type: + type = type.as_function_pointer() + btype = self._get_cached_btype(type) + result = btype, really_a_function_type + self._parsed_types[key] = result + return result + + def _typeof(self, cdecl, consider_function_as_funcptr=False): + # string -> ctype object + try: + result = self._parsed_types[cdecl] + except KeyError: + with self._lock: + result = self._typeof_locked(cdecl) + # + btype, really_a_function_type = result + if really_a_function_type and not consider_function_as_funcptr: + raise CDefError("the type %r is a function type, not a " + "pointer-to-function type" % (cdecl,)) + return btype + + def typeof(self, cdecl): + """Parse the C type given as a string and return the + corresponding object. + It can also be used on 'cdata' instance to get its C type. + """ + if isinstance(cdecl, basestring): + return self._typeof(cdecl) + if isinstance(cdecl, self.CData): + return self._backend.typeof(cdecl) + if isinstance(cdecl, types.BuiltinFunctionType): + res = _builtin_function_type(cdecl) + if res is not None: + return res + if (isinstance(cdecl, types.FunctionType) + and hasattr(cdecl, '_cffi_base_type')): + with self._lock: + return self._get_cached_btype(cdecl._cffi_base_type) + raise TypeError(type(cdecl)) + + def sizeof(self, cdecl): + """Return the size in bytes of the argument. It can be a + string naming a C type, or a 'cdata' instance. + """ + if isinstance(cdecl, basestring): + BType = self._typeof(cdecl) + return self._backend.sizeof(BType) + else: + return self._backend.sizeof(cdecl) + + def alignof(self, cdecl): + """Return the natural alignment size in bytes of the C type + given as a string. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.alignof(cdecl) + + def offsetof(self, cdecl, *fields_or_indexes): + """Return the offset of the named field inside the given + structure or array, which must be given as a C type name. + You can give several field names in case of nested structures. + You can also give numeric values which correspond to array + items, in case of an array type. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._typeoffsetof(cdecl, *fields_or_indexes)[1] + + def new(self, cdecl, init=None): + """Allocate an instance according to the specified C type and + return a pointer to it. The specified C type must be either a + pointer or an array: ``new('X *')`` allocates an X and returns + a pointer to it, whereas ``new('X[n]')`` allocates an array of + n X'es and returns an array referencing it (which works + mostly like a pointer, like in C). You can also use + ``new('X[]', n)`` to allocate an array of a non-constant + length n. + + The memory is initialized following the rules of declaring a + global variable in C: by default it is zero-initialized, but + an explicit initializer can be given which can be used to + fill all or part of the memory. + + When the returned object goes out of scope, the memory + is freed. In other words the returned object has + ownership of the value of type 'cdecl' that it points to. This + means that the raw data can be used as long as this object is + kept alive, but must not be used for a longer time. Be careful + about that when copying the pointer to the memory somewhere + else, e.g. into another structure. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.newp(cdecl, init) + + def new_allocator(self, alloc=None, free=None, + should_clear_after_alloc=True): + """Return a new allocator, i.e. a function that behaves like ffi.new() + but uses the provided low-level 'alloc' and 'free' functions. + + 'alloc' is called with the size as argument. If it returns NULL, a + MemoryError is raised. 'free' is called with the result of 'alloc' + as argument. Both can be either Python function or directly C + functions. If 'free' is None, then no free function is called. + If both 'alloc' and 'free' are None, the default is used. + + If 'should_clear_after_alloc' is set to False, then the memory + returned by 'alloc' is assumed to be already cleared (or you are + fine with garbage); otherwise CFFI will clear it. + """ + compiled_ffi = self._backend.FFI() + allocator = compiled_ffi.new_allocator(alloc, free, + should_clear_after_alloc) + def allocate(cdecl, init=None): + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return allocator(cdecl, init) + return allocate + + def cast(self, cdecl, source): + """Similar to a C cast: returns an instance of the named C + type initialized with the given 'source'. The source is + casted between integers or pointers of any type. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.cast(cdecl, source) + + def string(self, cdata, maxlen=-1): + """Return a Python string (or unicode string) from the 'cdata'. + If 'cdata' is a pointer or array of characters or bytes, returns + the null-terminated string. The returned string extends until + the first null character, or at most 'maxlen' characters. If + 'cdata' is an array then 'maxlen' defaults to its length. + + If 'cdata' is a pointer or array of wchar_t, returns a unicode + string following the same rules. + + If 'cdata' is a single character or byte or a wchar_t, returns + it as a string or unicode string. + + If 'cdata' is an enum, returns the value of the enumerator as a + string, or 'NUMBER' if the value is out of range. + """ + return self._backend.string(cdata, maxlen) + + def unpack(self, cdata, length): + """Unpack an array of C data of the given length, + returning a Python string/unicode/list. + + If 'cdata' is a pointer to 'char', returns a byte string. + It does not stop at the first null. This is equivalent to: + ffi.buffer(cdata, length)[:] + + If 'cdata' is a pointer to 'wchar_t', returns a unicode string. + 'length' is measured in wchar_t's; it is not the size in bytes. + + If 'cdata' is a pointer to anything else, returns a list of + 'length' items. This is a faster equivalent to: + [cdata[i] for i in range(length)] + """ + return self._backend.unpack(cdata, length) + + #def buffer(self, cdata, size=-1): + # """Return a read-write buffer object that references the raw C data + # pointed to by the given 'cdata'. The 'cdata' must be a pointer or + # an array. Can be passed to functions expecting a buffer, or directly + # manipulated with: + # + # buf[:] get a copy of it in a regular string, or + # buf[idx] as a single character + # buf[:] = ... + # buf[idx] = ... change the content + # """ + # note that 'buffer' is a type, set on this instance by __init__ + + def from_buffer(self, cdecl, python_buffer=_unspecified, + require_writable=False): + """Return a cdata of the given type pointing to the data of the + given Python object, which must support the buffer interface. + Note that this is not meant to be used on the built-in types + str or unicode (you can build 'char[]' arrays explicitly) + but only on objects containing large quantities of raw data + in some other format, like 'array.array' or numpy arrays. + + The first argument is optional and default to 'char[]'. + """ + if python_buffer is _unspecified: + cdecl, python_buffer = self.BCharA, cdecl + elif isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + return self._backend.from_buffer(cdecl, python_buffer, + require_writable) + + def memmove(self, dest, src, n): + """ffi.memmove(dest, src, n) copies n bytes of memory from src to dest. + + Like the C function memmove(), the memory areas may overlap; + apart from that it behaves like the C function memcpy(). + + 'src' can be any cdata ptr or array, or any Python buffer object. + 'dest' can be any cdata ptr or array, or a writable Python buffer + object. The size to copy, 'n', is always measured in bytes. + + Unlike other methods, this one supports all Python buffer including + byte strings and bytearrays---but it still does not support + non-contiguous buffers. + """ + return self._backend.memmove(dest, src, n) + + def callback(self, cdecl, python_callable=None, error=None, onerror=None): + """Return a callback object or a decorator making such a + callback object. 'cdecl' must name a C function pointer type. + The callback invokes the specified 'python_callable' (which may + be provided either directly or via a decorator). Important: the + callback object must be manually kept alive for as long as the + callback may be invoked from the C level. + """ + def callback_decorator_wrap(python_callable): + if not callable(python_callable): + raise TypeError("the 'python_callable' argument " + "is not callable") + return self._backend.callback(cdecl, python_callable, + error, onerror) + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl, consider_function_as_funcptr=True) + if python_callable is None: + return callback_decorator_wrap # decorator mode + else: + return callback_decorator_wrap(python_callable) # direct mode + + def getctype(self, cdecl, replace_with=''): + """Return a string giving the C type 'cdecl', which may be itself + a string or a object. If 'replace_with' is given, it gives + extra text to append (or insert for more complicated C types), like + a variable name, or '*' to get actually the C type 'pointer-to-cdecl'. + """ + if isinstance(cdecl, basestring): + cdecl = self._typeof(cdecl) + replace_with = replace_with.strip() + if (replace_with.startswith('*') + and '&[' in self._backend.getcname(cdecl, '&')): + replace_with = '(%s)' % replace_with + elif replace_with and not replace_with[0] in '[(': + replace_with = ' ' + replace_with + return self._backend.getcname(cdecl, replace_with) + + def gc(self, cdata, destructor, size=0): + """Return a new cdata object that points to the same + data. Later, when this new cdata object is garbage-collected, + 'destructor(old_cdata_object)' will be called. + + The optional 'size' gives an estimate of the size, used to + trigger the garbage collection more eagerly. So far only used + on PyPy. It tells the GC that the returned object keeps alive + roughly 'size' bytes of external memory. + """ + return self._backend.gcp(cdata, destructor, size) + + def _get_cached_btype(self, type): + assert self._lock.acquire(False) is False + # call me with the lock! + try: + BType = self._cached_btypes[type] + except KeyError: + finishlist = [] + BType = type.get_cached_btype(self, finishlist) + for type in finishlist: + type.finish_backend_type(self, finishlist) + return BType + + def verify(self, source='', tmpdir=None, **kwargs): + """Verify that the current ffi signatures compile on this + machine, and return a dynamic library object. The dynamic + library can be used to call functions and access global + variables declared in this 'ffi'. The library is compiled + by the C compiler: it gives you C-level API compatibility + (including calling macros). This is unlike 'ffi.dlopen()', + which requires binary compatibility in the signatures. + """ + from .verifier import Verifier, _caller_dir_pycache + # + # If set_unicode(True) was called, insert the UNICODE and + # _UNICODE macro declarations + if self._windows_unicode: + self._apply_windows_unicode(kwargs) + # + # Set the tmpdir here, and not in Verifier.__init__: it picks + # up the caller's directory, which we want to be the caller of + # ffi.verify(), as opposed to the caller of Veritier(). + tmpdir = tmpdir or _caller_dir_pycache() + # + # Make a Verifier() and use it to load the library. + self.verifier = Verifier(self, source, tmpdir, **kwargs) + lib = self.verifier.load_library() + # + # Save the loaded library for keep-alive purposes, even + # if the caller doesn't keep it alive itself (it should). + self._libraries.append(lib) + return lib + + def _get_errno(self): + return self._backend.get_errno() + def _set_errno(self, errno): + self._backend.set_errno(errno) + errno = property(_get_errno, _set_errno, None, + "the value of 'errno' from/to the C calls") + + def getwinerror(self, code=-1): + return self._backend.getwinerror(code) + + def _pointer_to(self, ctype): + with self._lock: + return model.pointer_cache(self, ctype) + + def addressof(self, cdata, *fields_or_indexes): + """Return the address of a . + If 'fields_or_indexes' are given, returns the address of that + field or array item in the structure or array, recursively in + case of nested structures. + """ + try: + ctype = self._backend.typeof(cdata) + except TypeError: + if '__addressof__' in type(cdata).__dict__: + return type(cdata).__addressof__(cdata, *fields_or_indexes) + raise + if fields_or_indexes: + ctype, offset = self._typeoffsetof(ctype, *fields_or_indexes) + else: + if ctype.kind == "pointer": + raise TypeError("addressof(pointer)") + offset = 0 + ctypeptr = self._pointer_to(ctype) + return self._backend.rawaddressof(ctypeptr, cdata, offset) + + def _typeoffsetof(self, ctype, field_or_index, *fields_or_indexes): + ctype, offset = self._backend.typeoffsetof(ctype, field_or_index) + for field1 in fields_or_indexes: + ctype, offset1 = self._backend.typeoffsetof(ctype, field1, 1) + offset += offset1 + return ctype, offset + + def include(self, ffi_to_include): + """Includes the typedefs, structs, unions and enums defined + in another FFI instance. Usage is similar to a #include in C, + where a part of the program might include types defined in + another part for its own usage. Note that the include() + method has no effect on functions, constants and global + variables, which must anyway be accessed directly from the + lib object returned by the original FFI instance. + """ + if not isinstance(ffi_to_include, FFI): + raise TypeError("ffi.include() expects an argument that is also of" + " type cffi.FFI, not %r" % ( + type(ffi_to_include).__name__,)) + if ffi_to_include is self: + raise ValueError("self.include(self)") + with ffi_to_include._lock: + with self._lock: + self._parser.include(ffi_to_include._parser) + self._cdefsources.append('[') + self._cdefsources.extend(ffi_to_include._cdefsources) + self._cdefsources.append(']') + self._included_ffis.append(ffi_to_include) + + def new_handle(self, x): + return self._backend.newp_handle(self.BVoidP, x) + + def from_handle(self, x): + return self._backend.from_handle(x) + + def release(self, x): + self._backend.release(x) + + def set_unicode(self, enabled_flag): + """Windows: if 'enabled_flag' is True, enable the UNICODE and + _UNICODE defines in C, and declare the types like TCHAR and LPTCSTR + to be (pointers to) wchar_t. If 'enabled_flag' is False, + declare these types to be (pointers to) plain 8-bit characters. + This is mostly for backward compatibility; you usually want True. + """ + if self._windows_unicode is not None: + raise ValueError("set_unicode() can only be called once") + enabled_flag = bool(enabled_flag) + if enabled_flag: + self.cdef("typedef wchar_t TBYTE;" + "typedef wchar_t TCHAR;" + "typedef const wchar_t *LPCTSTR;" + "typedef const wchar_t *PCTSTR;" + "typedef wchar_t *LPTSTR;" + "typedef wchar_t *PTSTR;" + "typedef TBYTE *PTBYTE;" + "typedef TCHAR *PTCHAR;") + else: + self.cdef("typedef char TBYTE;" + "typedef char TCHAR;" + "typedef const char *LPCTSTR;" + "typedef const char *PCTSTR;" + "typedef char *LPTSTR;" + "typedef char *PTSTR;" + "typedef TBYTE *PTBYTE;" + "typedef TCHAR *PTCHAR;") + self._windows_unicode = enabled_flag + + def _apply_windows_unicode(self, kwds): + defmacros = kwds.get('define_macros', ()) + if not isinstance(defmacros, (list, tuple)): + raise TypeError("'define_macros' must be a list or tuple") + defmacros = list(defmacros) + [('UNICODE', '1'), + ('_UNICODE', '1')] + kwds['define_macros'] = defmacros + + def _apply_embedding_fix(self, kwds): + # must include an argument like "-lpython2.7" for the compiler + def ensure(key, value): + lst = kwds.setdefault(key, []) + if value not in lst: + lst.append(value) + # + if '__pypy__' in sys.builtin_module_names: + import os + if sys.platform == "win32": + # we need 'libpypy-c.lib'. Current distributions of + # pypy (>= 4.1) contain it as 'libs/python27.lib'. + pythonlib = "python{0[0]}{0[1]}".format(sys.version_info) + if hasattr(sys, 'prefix'): + ensure('library_dirs', os.path.join(sys.prefix, 'libs')) + else: + # we need 'libpypy-c.{so,dylib}', which should be by + # default located in 'sys.prefix/bin' for installed + # systems. + if sys.version_info < (3,): + pythonlib = "pypy-c" + else: + pythonlib = "pypy3-c" + if hasattr(sys, 'prefix'): + ensure('library_dirs', os.path.join(sys.prefix, 'bin')) + # On uninstalled pypy's, the libpypy-c is typically found in + # .../pypy/goal/. + if hasattr(sys, 'prefix'): + ensure('library_dirs', os.path.join(sys.prefix, 'pypy', 'goal')) + else: + if sys.platform == "win32": + template = "python%d%d" + if hasattr(sys, 'gettotalrefcount'): + template += '_d' + else: + try: + import sysconfig + except ImportError: # 2.6 + from cffi._shimmed_dist_utils import sysconfig + template = "python%d.%d" + if sysconfig.get_config_var('DEBUG_EXT'): + template += sysconfig.get_config_var('DEBUG_EXT') + pythonlib = (template % + (sys.hexversion >> 24, (sys.hexversion >> 16) & 0xff)) + if hasattr(sys, 'abiflags'): + pythonlib += sys.abiflags + ensure('libraries', pythonlib) + if sys.platform == "win32": + ensure('extra_link_args', '/MANIFEST') + + def set_source(self, module_name, source, source_extension='.c', **kwds): + import os + if hasattr(self, '_assigned_source'): + raise ValueError("set_source() cannot be called several times " + "per ffi object") + if not isinstance(module_name, basestring): + raise TypeError("'module_name' must be a string") + if os.sep in module_name or (os.altsep and os.altsep in module_name): + raise ValueError("'module_name' must not contain '/': use a dotted " + "name to make a 'package.module' location") + self._assigned_source = (str(module_name), source, + source_extension, kwds) + + def set_source_pkgconfig(self, module_name, pkgconfig_libs, source, + source_extension='.c', **kwds): + from . import pkgconfig + if not isinstance(pkgconfig_libs, list): + raise TypeError("the pkgconfig_libs argument must be a list " + "of package names") + kwds2 = pkgconfig.flags_from_pkgconfig(pkgconfig_libs) + pkgconfig.merge_flags(kwds, kwds2) + self.set_source(module_name, source, source_extension, **kwds) + + def distutils_extension(self, tmpdir='build', verbose=True): + from cffi._shimmed_dist_utils import mkpath + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + if hasattr(self, 'verifier'): # fallback, 'tmpdir' ignored + return self.verifier.get_extension() + raise ValueError("set_source() must be called before" + " distutils_extension()") + module_name, source, source_extension, kwds = self._assigned_source + if source is None: + raise TypeError("distutils_extension() is only for C extension " + "modules, not for dlopen()-style pure Python " + "modules") + mkpath(tmpdir) + ext, updated = recompile(self, module_name, + source, tmpdir=tmpdir, extradir=tmpdir, + source_extension=source_extension, + call_c_compiler=False, **kwds) + if verbose: + if updated: + sys.stderr.write("regenerated: %r\n" % (ext.sources[0],)) + else: + sys.stderr.write("not modified: %r\n" % (ext.sources[0],)) + return ext + + def emit_c_code(self, filename): + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + raise ValueError("set_source() must be called before emit_c_code()") + module_name, source, source_extension, kwds = self._assigned_source + if source is None: + raise TypeError("emit_c_code() is only for C extension modules, " + "not for dlopen()-style pure Python modules") + recompile(self, module_name, source, + c_file=filename, call_c_compiler=False, **kwds) + + def emit_python_code(self, filename): + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + raise ValueError("set_source() must be called before emit_c_code()") + module_name, source, source_extension, kwds = self._assigned_source + if source is not None: + raise TypeError("emit_python_code() is only for dlopen()-style " + "pure Python modules, not for C extension modules") + recompile(self, module_name, source, + c_file=filename, call_c_compiler=False, **kwds) + + def compile(self, tmpdir='.', verbose=0, target=None, debug=None): + """The 'target' argument gives the final file name of the + compiled DLL. Use '*' to force distutils' choice, suitable for + regular CPython C API modules. Use a file name ending in '.*' + to ask for the system's default extension for dynamic libraries + (.so/.dll/.dylib). + + The default is '*' when building a non-embedded C API extension, + and (module_name + '.*') when building an embedded library. + """ + from .recompiler import recompile + # + if not hasattr(self, '_assigned_source'): + raise ValueError("set_source() must be called before compile()") + module_name, source, source_extension, kwds = self._assigned_source + return recompile(self, module_name, source, tmpdir=tmpdir, + target=target, source_extension=source_extension, + compiler_verbose=verbose, debug=debug, **kwds) + + def init_once(self, func, tag): + # Read _init_once_cache[tag], which is either (False, lock) if + # we're calling the function now in some thread, or (True, result). + # Don't call setdefault() in most cases, to avoid allocating and + # immediately freeing a lock; but still use setdefaut() to avoid + # races. + try: + x = self._init_once_cache[tag] + except KeyError: + x = self._init_once_cache.setdefault(tag, (False, allocate_lock())) + # Common case: we got (True, result), so we return the result. + if x[0]: + return x[1] + # Else, it's a lock. Acquire it to serialize the following tests. + with x[1]: + # Read again from _init_once_cache the current status. + x = self._init_once_cache[tag] + if x[0]: + return x[1] + # Call the function and store the result back. + result = func() + self._init_once_cache[tag] = (True, result) + return result + + def embedding_init_code(self, pysource): + if self._embedding: + raise ValueError("embedding_init_code() can only be called once") + # fix 'pysource' before it gets dumped into the C file: + # - remove empty lines at the beginning, so it starts at "line 1" + # - dedent, if all non-empty lines are indented + # - check for SyntaxErrors + import re + match = re.match(r'\s*\n', pysource) + if match: + pysource = pysource[match.end():] + lines = pysource.splitlines() or [''] + prefix = re.match(r'\s*', lines[0]).group() + for i in range(1, len(lines)): + line = lines[i] + if line.rstrip(): + while not line.startswith(prefix): + prefix = prefix[:-1] + i = len(prefix) + lines = [line[i:]+'\n' for line in lines] + pysource = ''.join(lines) + # + compile(pysource, "cffi_init", "exec") + # + self._embedding = pysource + + def def_extern(self, *args, **kwds): + raise ValueError("ffi.def_extern() is only available on API-mode FFI " + "objects") + + def list_types(self): + """Returns the user type names known to this FFI instance. + This returns a tuple containing three lists of names: + (typedef_names, names_of_structs, names_of_unions) + """ + typedefs = [] + structs = [] + unions = [] + for key in self._parser._declarations: + if key.startswith('typedef '): + typedefs.append(key[8:]) + elif key.startswith('struct '): + structs.append(key[7:]) + elif key.startswith('union '): + unions.append(key[6:]) + typedefs.sort() + structs.sort() + unions.sort() + return (typedefs, structs, unions) + + +def _load_backend_lib(backend, name, flags): + import os + if not isinstance(name, basestring): + if sys.platform != "win32" or name is not None: + return backend.load_library(name, flags) + name = "c" # Windows: load_library(None) fails, but this works + # on Python 2 (backward compatibility hack only) + first_error = None + if '.' in name or '/' in name or os.sep in name: + try: + return backend.load_library(name, flags) + except OSError as e: + first_error = e + import ctypes.util + path = ctypes.util.find_library(name) + if path is None: + if name == "c" and sys.platform == "win32" and sys.version_info >= (3,): + raise OSError("dlopen(None) cannot work on Windows for Python 3 " + "(see http://bugs.python.org/issue23606)") + msg = ("ctypes.util.find_library() did not manage " + "to locate a library called %r" % (name,)) + if first_error is not None: + msg = "%s. Additionally, %s" % (first_error, msg) + raise OSError(msg) + return backend.load_library(path, flags) + +def _make_ffi_library(ffi, libname, flags): + backend = ffi._backend + backendlib = _load_backend_lib(backend, libname, flags) + # + def accessor_function(name): + key = 'function ' + name + tp, _ = ffi._parser._declarations[key] + BType = ffi._get_cached_btype(tp) + value = backendlib.load_function(BType, name) + library.__dict__[name] = value + # + def accessor_variable(name): + key = 'variable ' + name + tp, _ = ffi._parser._declarations[key] + BType = ffi._get_cached_btype(tp) + read_variable = backendlib.read_variable + write_variable = backendlib.write_variable + setattr(FFILibrary, name, property( + lambda self: read_variable(BType, name), + lambda self, value: write_variable(BType, name, value))) + # + def addressof_var(name): + try: + return addr_variables[name] + except KeyError: + with ffi._lock: + if name not in addr_variables: + key = 'variable ' + name + tp, _ = ffi._parser._declarations[key] + BType = ffi._get_cached_btype(tp) + if BType.kind != 'array': + BType = model.pointer_cache(ffi, BType) + p = backendlib.load_function(BType, name) + addr_variables[name] = p + return addr_variables[name] + # + def accessor_constant(name): + raise NotImplementedError("non-integer constant '%s' cannot be " + "accessed from a dlopen() library" % (name,)) + # + def accessor_int_constant(name): + library.__dict__[name] = ffi._parser._int_constants[name] + # + accessors = {} + accessors_version = [False] + addr_variables = {} + # + def update_accessors(): + if accessors_version[0] is ffi._cdef_version: + return + # + for key, (tp, _) in ffi._parser._declarations.items(): + if not isinstance(tp, model.EnumType): + tag, name = key.split(' ', 1) + if tag == 'function': + accessors[name] = accessor_function + elif tag == 'variable': + accessors[name] = accessor_variable + elif tag == 'constant': + accessors[name] = accessor_constant + else: + for i, enumname in enumerate(tp.enumerators): + def accessor_enum(name, tp=tp, i=i): + tp.check_not_partial() + library.__dict__[name] = tp.enumvalues[i] + accessors[enumname] = accessor_enum + for name in ffi._parser._int_constants: + accessors.setdefault(name, accessor_int_constant) + accessors_version[0] = ffi._cdef_version + # + def make_accessor(name): + with ffi._lock: + if name in library.__dict__ or name in FFILibrary.__dict__: + return # added by another thread while waiting for the lock + if name not in accessors: + update_accessors() + if name not in accessors: + raise AttributeError(name) + accessors[name](name) + # + class FFILibrary(object): + def __getattr__(self, name): + make_accessor(name) + return getattr(self, name) + def __setattr__(self, name, value): + try: + property = getattr(self.__class__, name) + except AttributeError: + make_accessor(name) + setattr(self, name, value) + else: + property.__set__(self, value) + def __dir__(self): + with ffi._lock: + update_accessors() + return accessors.keys() + def __addressof__(self, name): + if name in library.__dict__: + return library.__dict__[name] + if name in FFILibrary.__dict__: + return addressof_var(name) + make_accessor(name) + if name in library.__dict__: + return library.__dict__[name] + if name in FFILibrary.__dict__: + return addressof_var(name) + raise AttributeError("cffi library has no function or " + "global variable named '%s'" % (name,)) + def __cffi_close__(self): + backendlib.close_lib() + self.__dict__.clear() + # + if isinstance(libname, basestring): + try: + if not isinstance(libname, str): # unicode, on Python 2 + libname = libname.encode('utf-8') + FFILibrary.__name__ = 'FFILibrary_%s' % libname + except UnicodeError: + pass + library = FFILibrary() + return library, library.__dict__ + +def _builtin_function_type(func): + # a hack to make at least ffi.typeof(builtin_function) work, + # if the builtin function was obtained by 'vengine_cpy'. + import sys + try: + module = sys.modules[func.__module__] + ffi = module._cffi_original_ffi + types_of_builtin_funcs = module._cffi_types_of_builtin_funcs + tp = types_of_builtin_funcs[func] + except (KeyError, AttributeError, TypeError): + return None + else: + with ffi._lock: + return ffi._get_cached_btype(tp) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/backend_ctypes.py b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/backend_ctypes.py new file mode 100644 index 000000000..e7956a79c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/backend_ctypes.py @@ -0,0 +1,1121 @@ +import ctypes, ctypes.util, operator, sys +from . import model + +if sys.version_info < (3,): + bytechr = chr +else: + unicode = str + long = int + xrange = range + bytechr = lambda num: bytes([num]) + +class CTypesType(type): + pass + +class CTypesData(object): + __metaclass__ = CTypesType + __slots__ = ['__weakref__'] + __name__ = '' + + def __init__(self, *args): + raise TypeError("cannot instantiate %r" % (self.__class__,)) + + @classmethod + def _newp(cls, init): + raise TypeError("expected a pointer or array ctype, got '%s'" + % (cls._get_c_name(),)) + + @staticmethod + def _to_ctypes(value): + raise TypeError + + @classmethod + def _arg_to_ctypes(cls, *value): + try: + ctype = cls._ctype + except AttributeError: + raise TypeError("cannot create an instance of %r" % (cls,)) + if value: + res = cls._to_ctypes(*value) + if not isinstance(res, ctype): + res = cls._ctype(res) + else: + res = cls._ctype() + return res + + @classmethod + def _create_ctype_obj(cls, init): + if init is None: + return cls._arg_to_ctypes() + else: + return cls._arg_to_ctypes(init) + + @staticmethod + def _from_ctypes(ctypes_value): + raise TypeError + + @classmethod + def _get_c_name(cls, replace_with=''): + return cls._reftypename.replace(' &', replace_with) + + @classmethod + def _fix_class(cls): + cls.__name__ = 'CData<%s>' % (cls._get_c_name(),) + cls.__qualname__ = 'CData<%s>' % (cls._get_c_name(),) + cls.__module__ = 'ffi' + + def _get_own_repr(self): + raise NotImplementedError + + def _addr_repr(self, address): + if address == 0: + return 'NULL' + else: + if address < 0: + address += 1 << (8*ctypes.sizeof(ctypes.c_void_p)) + return '0x%x' % address + + def __repr__(self, c_name=None): + own = self._get_own_repr() + return '' % (c_name or self._get_c_name(), own) + + def _convert_to_address(self, BClass): + if BClass is None: + raise TypeError("cannot convert %r to an address" % ( + self._get_c_name(),)) + else: + raise TypeError("cannot convert %r to %r" % ( + self._get_c_name(), BClass._get_c_name())) + + @classmethod + def _get_size(cls): + return ctypes.sizeof(cls._ctype) + + def _get_size_of_instance(self): + return ctypes.sizeof(self._ctype) + + @classmethod + def _cast_from(cls, source): + raise TypeError("cannot cast to %r" % (cls._get_c_name(),)) + + def _cast_to_integer(self): + return self._convert_to_address(None) + + @classmethod + def _alignment(cls): + return ctypes.alignment(cls._ctype) + + def __iter__(self): + raise TypeError("cdata %r does not support iteration" % ( + self._get_c_name()),) + + def _make_cmp(name): + cmpfunc = getattr(operator, name) + def cmp(self, other): + v_is_ptr = not isinstance(self, CTypesGenericPrimitive) + w_is_ptr = (isinstance(other, CTypesData) and + not isinstance(other, CTypesGenericPrimitive)) + if v_is_ptr and w_is_ptr: + return cmpfunc(self._convert_to_address(None), + other._convert_to_address(None)) + elif v_is_ptr or w_is_ptr: + return NotImplemented + else: + if isinstance(self, CTypesGenericPrimitive): + self = self._value + if isinstance(other, CTypesGenericPrimitive): + other = other._value + return cmpfunc(self, other) + cmp.func_name = name + return cmp + + __eq__ = _make_cmp('__eq__') + __ne__ = _make_cmp('__ne__') + __lt__ = _make_cmp('__lt__') + __le__ = _make_cmp('__le__') + __gt__ = _make_cmp('__gt__') + __ge__ = _make_cmp('__ge__') + + def __hash__(self): + return hash(self._convert_to_address(None)) + + def _to_string(self, maxlen): + raise TypeError("string(): %r" % (self,)) + + +class CTypesGenericPrimitive(CTypesData): + __slots__ = [] + + def __hash__(self): + return hash(self._value) + + def _get_own_repr(self): + return repr(self._from_ctypes(self._value)) + + +class CTypesGenericArray(CTypesData): + __slots__ = [] + + @classmethod + def _newp(cls, init): + return cls(init) + + def __iter__(self): + for i in xrange(len(self)): + yield self[i] + + def _get_own_repr(self): + return self._addr_repr(ctypes.addressof(self._blob)) + + +class CTypesGenericPtr(CTypesData): + __slots__ = ['_address', '_as_ctype_ptr'] + _automatic_casts = False + kind = "pointer" + + @classmethod + def _newp(cls, init): + return cls(init) + + @classmethod + def _cast_from(cls, source): + if source is None: + address = 0 + elif isinstance(source, CTypesData): + address = source._cast_to_integer() + elif isinstance(source, (int, long)): + address = source + else: + raise TypeError("bad type for cast to %r: %r" % + (cls, type(source).__name__)) + return cls._new_pointer_at(address) + + @classmethod + def _new_pointer_at(cls, address): + self = cls.__new__(cls) + self._address = address + self._as_ctype_ptr = ctypes.cast(address, cls._ctype) + return self + + def _get_own_repr(self): + try: + return self._addr_repr(self._address) + except AttributeError: + return '???' + + def _cast_to_integer(self): + return self._address + + def __nonzero__(self): + return bool(self._address) + __bool__ = __nonzero__ + + @classmethod + def _to_ctypes(cls, value): + if not isinstance(value, CTypesData): + raise TypeError("unexpected %s object" % type(value).__name__) + address = value._convert_to_address(cls) + return ctypes.cast(address, cls._ctype) + + @classmethod + def _from_ctypes(cls, ctypes_ptr): + address = ctypes.cast(ctypes_ptr, ctypes.c_void_p).value or 0 + return cls._new_pointer_at(address) + + @classmethod + def _initialize(cls, ctypes_ptr, value): + if value: + ctypes_ptr.contents = cls._to_ctypes(value).contents + + def _convert_to_address(self, BClass): + if (BClass in (self.__class__, None) or BClass._automatic_casts + or self._automatic_casts): + return self._address + else: + return CTypesData._convert_to_address(self, BClass) + + +class CTypesBaseStructOrUnion(CTypesData): + __slots__ = ['_blob'] + + @classmethod + def _create_ctype_obj(cls, init): + # may be overridden + raise TypeError("cannot instantiate opaque type %s" % (cls,)) + + def _get_own_repr(self): + return self._addr_repr(ctypes.addressof(self._blob)) + + @classmethod + def _offsetof(cls, fieldname): + return getattr(cls._ctype, fieldname).offset + + def _convert_to_address(self, BClass): + if getattr(BClass, '_BItem', None) is self.__class__: + return ctypes.addressof(self._blob) + else: + return CTypesData._convert_to_address(self, BClass) + + @classmethod + def _from_ctypes(cls, ctypes_struct_or_union): + self = cls.__new__(cls) + self._blob = ctypes_struct_or_union + return self + + @classmethod + def _to_ctypes(cls, value): + return value._blob + + def __repr__(self, c_name=None): + return CTypesData.__repr__(self, c_name or self._get_c_name(' &')) + + +class CTypesBackend(object): + + PRIMITIVE_TYPES = { + 'char': ctypes.c_char, + 'short': ctypes.c_short, + 'int': ctypes.c_int, + 'long': ctypes.c_long, + 'long long': ctypes.c_longlong, + 'signed char': ctypes.c_byte, + 'unsigned char': ctypes.c_ubyte, + 'unsigned short': ctypes.c_ushort, + 'unsigned int': ctypes.c_uint, + 'unsigned long': ctypes.c_ulong, + 'unsigned long long': ctypes.c_ulonglong, + 'float': ctypes.c_float, + 'double': ctypes.c_double, + '_Bool': ctypes.c_bool, + } + + for _name in ['unsigned long long', 'unsigned long', + 'unsigned int', 'unsigned short', 'unsigned char']: + _size = ctypes.sizeof(PRIMITIVE_TYPES[_name]) + PRIMITIVE_TYPES['uint%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_void_p): + PRIMITIVE_TYPES['uintptr_t'] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_size_t): + PRIMITIVE_TYPES['size_t'] = PRIMITIVE_TYPES[_name] + + for _name in ['long long', 'long', 'int', 'short', 'signed char']: + _size = ctypes.sizeof(PRIMITIVE_TYPES[_name]) + PRIMITIVE_TYPES['int%d_t' % (8*_size)] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_void_p): + PRIMITIVE_TYPES['intptr_t'] = PRIMITIVE_TYPES[_name] + PRIMITIVE_TYPES['ptrdiff_t'] = PRIMITIVE_TYPES[_name] + if _size == ctypes.sizeof(ctypes.c_size_t): + PRIMITIVE_TYPES['ssize_t'] = PRIMITIVE_TYPES[_name] + + + def __init__(self): + self.RTLD_LAZY = 0 # not supported anyway by ctypes + self.RTLD_NOW = 0 + self.RTLD_GLOBAL = ctypes.RTLD_GLOBAL + self.RTLD_LOCAL = ctypes.RTLD_LOCAL + + def set_ffi(self, ffi): + self.ffi = ffi + + def _get_types(self): + return CTypesData, CTypesType + + def load_library(self, path, flags=0): + cdll = ctypes.CDLL(path, flags) + return CTypesLibrary(self, cdll) + + def new_void_type(self): + class CTypesVoid(CTypesData): + __slots__ = [] + _reftypename = 'void &' + @staticmethod + def _from_ctypes(novalue): + return None + @staticmethod + def _to_ctypes(novalue): + if novalue is not None: + raise TypeError("None expected, got %s object" % + (type(novalue).__name__,)) + return None + CTypesVoid._fix_class() + return CTypesVoid + + def new_primitive_type(self, name): + if name == 'wchar_t': + raise NotImplementedError(name) + ctype = self.PRIMITIVE_TYPES[name] + if name == 'char': + kind = 'char' + elif name in ('float', 'double'): + kind = 'float' + else: + if name in ('signed char', 'unsigned char'): + kind = 'byte' + elif name == '_Bool': + kind = 'bool' + else: + kind = 'int' + is_signed = (ctype(-1).value == -1) + # + def _cast_source_to_int(source): + if isinstance(source, (int, long, float)): + source = int(source) + elif isinstance(source, CTypesData): + source = source._cast_to_integer() + elif isinstance(source, bytes): + source = ord(source) + elif source is None: + source = 0 + else: + raise TypeError("bad type for cast to %r: %r" % + (CTypesPrimitive, type(source).__name__)) + return source + # + kind1 = kind + class CTypesPrimitive(CTypesGenericPrimitive): + __slots__ = ['_value'] + _ctype = ctype + _reftypename = '%s &' % name + kind = kind1 + + def __init__(self, value): + self._value = value + + @staticmethod + def _create_ctype_obj(init): + if init is None: + return ctype() + return ctype(CTypesPrimitive._to_ctypes(init)) + + if kind == 'int' or kind == 'byte': + @classmethod + def _cast_from(cls, source): + source = _cast_source_to_int(source) + source = ctype(source).value # cast within range + return cls(source) + def __int__(self): + return self._value + + if kind == 'bool': + @classmethod + def _cast_from(cls, source): + if not isinstance(source, (int, long, float)): + source = _cast_source_to_int(source) + return cls(bool(source)) + def __int__(self): + return int(self._value) + + if kind == 'char': + @classmethod + def _cast_from(cls, source): + source = _cast_source_to_int(source) + source = bytechr(source & 0xFF) + return cls(source) + def __int__(self): + return ord(self._value) + + if kind == 'float': + @classmethod + def _cast_from(cls, source): + if isinstance(source, float): + pass + elif isinstance(source, CTypesGenericPrimitive): + if hasattr(source, '__float__'): + source = float(source) + else: + source = int(source) + else: + source = _cast_source_to_int(source) + source = ctype(source).value # fix precision + return cls(source) + def __int__(self): + return int(self._value) + def __float__(self): + return self._value + + _cast_to_integer = __int__ + + if kind == 'int' or kind == 'byte' or kind == 'bool': + @staticmethod + def _to_ctypes(x): + if not isinstance(x, (int, long)): + if isinstance(x, CTypesData): + x = int(x) + else: + raise TypeError("integer expected, got %s" % + type(x).__name__) + if ctype(x).value != x: + if not is_signed and x < 0: + raise OverflowError("%s: negative integer" % name) + else: + raise OverflowError("%s: integer out of bounds" + % name) + return x + + if kind == 'char': + @staticmethod + def _to_ctypes(x): + if isinstance(x, bytes) and len(x) == 1: + return x + if isinstance(x, CTypesPrimitive): # > + return x._value + raise TypeError("character expected, got %s" % + type(x).__name__) + def __nonzero__(self): + return ord(self._value) != 0 + else: + def __nonzero__(self): + return self._value != 0 + __bool__ = __nonzero__ + + if kind == 'float': + @staticmethod + def _to_ctypes(x): + if not isinstance(x, (int, long, float, CTypesData)): + raise TypeError("float expected, got %s" % + type(x).__name__) + return ctype(x).value + + @staticmethod + def _from_ctypes(value): + return getattr(value, 'value', value) + + @staticmethod + def _initialize(blob, init): + blob.value = CTypesPrimitive._to_ctypes(init) + + if kind == 'char': + def _to_string(self, maxlen): + return self._value + if kind == 'byte': + def _to_string(self, maxlen): + return chr(self._value & 0xff) + # + CTypesPrimitive._fix_class() + return CTypesPrimitive + + def new_pointer_type(self, BItem): + getbtype = self.ffi._get_cached_btype + if BItem is getbtype(model.PrimitiveType('char')): + kind = 'charp' + elif BItem in (getbtype(model.PrimitiveType('signed char')), + getbtype(model.PrimitiveType('unsigned char'))): + kind = 'bytep' + elif BItem is getbtype(model.void_type): + kind = 'voidp' + else: + kind = 'generic' + # + class CTypesPtr(CTypesGenericPtr): + __slots__ = ['_own'] + if kind == 'charp': + __slots__ += ['__as_strbuf'] + _BItem = BItem + if hasattr(BItem, '_ctype'): + _ctype = ctypes.POINTER(BItem._ctype) + _bitem_size = ctypes.sizeof(BItem._ctype) + else: + _ctype = ctypes.c_void_p + if issubclass(BItem, CTypesGenericArray): + _reftypename = BItem._get_c_name('(* &)') + else: + _reftypename = BItem._get_c_name(' * &') + + def __init__(self, init): + ctypeobj = BItem._create_ctype_obj(init) + if kind == 'charp': + self.__as_strbuf = ctypes.create_string_buffer( + ctypeobj.value + b'\x00') + self._as_ctype_ptr = ctypes.cast( + self.__as_strbuf, self._ctype) + else: + self._as_ctype_ptr = ctypes.pointer(ctypeobj) + self._address = ctypes.cast(self._as_ctype_ptr, + ctypes.c_void_p).value + self._own = True + + def __add__(self, other): + if isinstance(other, (int, long)): + return self._new_pointer_at(self._address + + other * self._bitem_size) + else: + return NotImplemented + + def __sub__(self, other): + if isinstance(other, (int, long)): + return self._new_pointer_at(self._address - + other * self._bitem_size) + elif type(self) is type(other): + return (self._address - other._address) // self._bitem_size + else: + return NotImplemented + + def __getitem__(self, index): + if getattr(self, '_own', False) and index != 0: + raise IndexError + return BItem._from_ctypes(self._as_ctype_ptr[index]) + + def __setitem__(self, index, value): + self._as_ctype_ptr[index] = BItem._to_ctypes(value) + + if kind == 'charp' or kind == 'voidp': + @classmethod + def _arg_to_ctypes(cls, *value): + if value and isinstance(value[0], bytes): + return ctypes.c_char_p(value[0]) + else: + return super(CTypesPtr, cls)._arg_to_ctypes(*value) + + if kind == 'charp' or kind == 'bytep': + def _to_string(self, maxlen): + if maxlen < 0: + maxlen = sys.maxsize + p = ctypes.cast(self._as_ctype_ptr, + ctypes.POINTER(ctypes.c_char)) + n = 0 + while n < maxlen and p[n] != b'\x00': + n += 1 + return b''.join([p[i] for i in range(n)]) + + def _get_own_repr(self): + if getattr(self, '_own', False): + return 'owning %d bytes' % ( + ctypes.sizeof(self._as_ctype_ptr.contents),) + return super(CTypesPtr, self)._get_own_repr() + # + if (BItem is self.ffi._get_cached_btype(model.void_type) or + BItem is self.ffi._get_cached_btype(model.PrimitiveType('char'))): + CTypesPtr._automatic_casts = True + # + CTypesPtr._fix_class() + return CTypesPtr + + def new_array_type(self, CTypesPtr, length): + if length is None: + brackets = ' &[]' + else: + brackets = ' &[%d]' % length + BItem = CTypesPtr._BItem + getbtype = self.ffi._get_cached_btype + if BItem is getbtype(model.PrimitiveType('char')): + kind = 'char' + elif BItem in (getbtype(model.PrimitiveType('signed char')), + getbtype(model.PrimitiveType('unsigned char'))): + kind = 'byte' + else: + kind = 'generic' + # + class CTypesArray(CTypesGenericArray): + __slots__ = ['_blob', '_own'] + if length is not None: + _ctype = BItem._ctype * length + else: + __slots__.append('_ctype') + _reftypename = BItem._get_c_name(brackets) + _declared_length = length + _CTPtr = CTypesPtr + + def __init__(self, init): + if length is None: + if isinstance(init, (int, long)): + len1 = init + init = None + elif kind == 'char' and isinstance(init, bytes): + len1 = len(init) + 1 # extra null + else: + init = tuple(init) + len1 = len(init) + self._ctype = BItem._ctype * len1 + self._blob = self._ctype() + self._own = True + if init is not None: + self._initialize(self._blob, init) + + @staticmethod + def _initialize(blob, init): + if isinstance(init, bytes): + init = [init[i:i+1] for i in range(len(init))] + else: + if isinstance(init, CTypesGenericArray): + if (len(init) != len(blob) or + not isinstance(init, CTypesArray)): + raise TypeError("length/type mismatch: %s" % (init,)) + init = tuple(init) + if len(init) > len(blob): + raise IndexError("too many initializers") + addr = ctypes.cast(blob, ctypes.c_void_p).value + PTR = ctypes.POINTER(BItem._ctype) + itemsize = ctypes.sizeof(BItem._ctype) + for i, value in enumerate(init): + p = ctypes.cast(addr + i * itemsize, PTR) + BItem._initialize(p.contents, value) + + def __len__(self): + return len(self._blob) + + def __getitem__(self, index): + if not (0 <= index < len(self._blob)): + raise IndexError + return BItem._from_ctypes(self._blob[index]) + + def __setitem__(self, index, value): + if not (0 <= index < len(self._blob)): + raise IndexError + self._blob[index] = BItem._to_ctypes(value) + + if kind == 'char' or kind == 'byte': + def _to_string(self, maxlen): + if maxlen < 0: + maxlen = len(self._blob) + p = ctypes.cast(self._blob, + ctypes.POINTER(ctypes.c_char)) + n = 0 + while n < maxlen and p[n] != b'\x00': + n += 1 + return b''.join([p[i] for i in range(n)]) + + def _get_own_repr(self): + if getattr(self, '_own', False): + return 'owning %d bytes' % (ctypes.sizeof(self._blob),) + return super(CTypesArray, self)._get_own_repr() + + def _convert_to_address(self, BClass): + if BClass in (CTypesPtr, None) or BClass._automatic_casts: + return ctypes.addressof(self._blob) + else: + return CTypesData._convert_to_address(self, BClass) + + @staticmethod + def _from_ctypes(ctypes_array): + self = CTypesArray.__new__(CTypesArray) + self._blob = ctypes_array + return self + + @staticmethod + def _arg_to_ctypes(value): + return CTypesPtr._arg_to_ctypes(value) + + def __add__(self, other): + if isinstance(other, (int, long)): + return CTypesPtr._new_pointer_at( + ctypes.addressof(self._blob) + + other * ctypes.sizeof(BItem._ctype)) + else: + return NotImplemented + + @classmethod + def _cast_from(cls, source): + raise NotImplementedError("casting to %r" % ( + cls._get_c_name(),)) + # + CTypesArray._fix_class() + return CTypesArray + + def _new_struct_or_union(self, kind, name, base_ctypes_class): + # + class struct_or_union(base_ctypes_class): + pass + struct_or_union.__name__ = '%s_%s' % (kind, name) + kind1 = kind + # + class CTypesStructOrUnion(CTypesBaseStructOrUnion): + __slots__ = ['_blob'] + _ctype = struct_or_union + _reftypename = '%s &' % (name,) + _kind = kind = kind1 + # + CTypesStructOrUnion._fix_class() + return CTypesStructOrUnion + + def new_struct_type(self, name): + return self._new_struct_or_union('struct', name, ctypes.Structure) + + def new_union_type(self, name): + return self._new_struct_or_union('union', name, ctypes.Union) + + def complete_struct_or_union(self, CTypesStructOrUnion, fields, tp, + totalsize=-1, totalalignment=-1, sflags=0, + pack=0): + if totalsize >= 0 or totalalignment >= 0: + raise NotImplementedError("the ctypes backend of CFFI does not support " + "structures completed by verify(); please " + "compile and install the _cffi_backend module.") + struct_or_union = CTypesStructOrUnion._ctype + fnames = [fname for (fname, BField, bitsize) in fields] + btypes = [BField for (fname, BField, bitsize) in fields] + bitfields = [bitsize for (fname, BField, bitsize) in fields] + # + bfield_types = {} + cfields = [] + for (fname, BField, bitsize) in fields: + if bitsize < 0: + cfields.append((fname, BField._ctype)) + bfield_types[fname] = BField + else: + cfields.append((fname, BField._ctype, bitsize)) + bfield_types[fname] = Ellipsis + if sflags & 8: + struct_or_union._pack_ = 1 + elif pack: + struct_or_union._pack_ = pack + struct_or_union._fields_ = cfields + CTypesStructOrUnion._bfield_types = bfield_types + # + @staticmethod + def _create_ctype_obj(init): + result = struct_or_union() + if init is not None: + initialize(result, init) + return result + CTypesStructOrUnion._create_ctype_obj = _create_ctype_obj + # + def initialize(blob, init): + if is_union: + if len(init) > 1: + raise ValueError("union initializer: %d items given, but " + "only one supported (use a dict if needed)" + % (len(init),)) + if not isinstance(init, dict): + if isinstance(init, (bytes, unicode)): + raise TypeError("union initializer: got a str") + init = tuple(init) + if len(init) > len(fnames): + raise ValueError("too many values for %s initializer" % + CTypesStructOrUnion._get_c_name()) + init = dict(zip(fnames, init)) + addr = ctypes.addressof(blob) + for fname, value in init.items(): + BField, bitsize = name2fieldtype[fname] + assert bitsize < 0, \ + "not implemented: initializer with bit fields" + offset = CTypesStructOrUnion._offsetof(fname) + PTR = ctypes.POINTER(BField._ctype) + p = ctypes.cast(addr + offset, PTR) + BField._initialize(p.contents, value) + is_union = CTypesStructOrUnion._kind == 'union' + name2fieldtype = dict(zip(fnames, zip(btypes, bitfields))) + # + for fname, BField, bitsize in fields: + if fname == '': + raise NotImplementedError("nested anonymous structs/unions") + if hasattr(CTypesStructOrUnion, fname): + raise ValueError("the field name %r conflicts in " + "the ctypes backend" % fname) + if bitsize < 0: + def getter(self, fname=fname, BField=BField, + offset=CTypesStructOrUnion._offsetof(fname), + PTR=ctypes.POINTER(BField._ctype)): + addr = ctypes.addressof(self._blob) + p = ctypes.cast(addr + offset, PTR) + return BField._from_ctypes(p.contents) + def setter(self, value, fname=fname, BField=BField): + setattr(self._blob, fname, BField._to_ctypes(value)) + # + if issubclass(BField, CTypesGenericArray): + setter = None + if BField._declared_length == 0: + def getter(self, fname=fname, BFieldPtr=BField._CTPtr, + offset=CTypesStructOrUnion._offsetof(fname), + PTR=ctypes.POINTER(BField._ctype)): + addr = ctypes.addressof(self._blob) + p = ctypes.cast(addr + offset, PTR) + return BFieldPtr._from_ctypes(p) + # + else: + def getter(self, fname=fname, BField=BField): + return BField._from_ctypes(getattr(self._blob, fname)) + def setter(self, value, fname=fname, BField=BField): + # xxx obscure workaround + value = BField._to_ctypes(value) + oldvalue = getattr(self._blob, fname) + setattr(self._blob, fname, value) + if value != getattr(self._blob, fname): + setattr(self._blob, fname, oldvalue) + raise OverflowError("value too large for bitfield") + setattr(CTypesStructOrUnion, fname, property(getter, setter)) + # + CTypesPtr = self.ffi._get_cached_btype(model.PointerType(tp)) + for fname in fnames: + if hasattr(CTypesPtr, fname): + raise ValueError("the field name %r conflicts in " + "the ctypes backend" % fname) + def getter(self, fname=fname): + return getattr(self[0], fname) + def setter(self, value, fname=fname): + setattr(self[0], fname, value) + setattr(CTypesPtr, fname, property(getter, setter)) + + def new_function_type(self, BArgs, BResult, has_varargs): + nameargs = [BArg._get_c_name() for BArg in BArgs] + if has_varargs: + nameargs.append('...') + nameargs = ', '.join(nameargs) + # + class CTypesFunctionPtr(CTypesGenericPtr): + __slots__ = ['_own_callback', '_name'] + _ctype = ctypes.CFUNCTYPE(getattr(BResult, '_ctype', None), + *[BArg._ctype for BArg in BArgs], + use_errno=True) + _reftypename = BResult._get_c_name('(* &)(%s)' % (nameargs,)) + + def __init__(self, init, error=None): + # create a callback to the Python callable init() + import traceback + assert not has_varargs, "varargs not supported for callbacks" + if getattr(BResult, '_ctype', None) is not None: + error = BResult._from_ctypes( + BResult._create_ctype_obj(error)) + else: + error = None + def callback(*args): + args2 = [] + for arg, BArg in zip(args, BArgs): + args2.append(BArg._from_ctypes(arg)) + try: + res2 = init(*args2) + res2 = BResult._to_ctypes(res2) + except: + traceback.print_exc() + res2 = error + if issubclass(BResult, CTypesGenericPtr): + if res2: + res2 = ctypes.cast(res2, ctypes.c_void_p).value + # .value: http://bugs.python.org/issue1574593 + else: + res2 = None + #print repr(res2) + return res2 + if issubclass(BResult, CTypesGenericPtr): + # The only pointers callbacks can return are void*s: + # http://bugs.python.org/issue5710 + callback_ctype = ctypes.CFUNCTYPE( + ctypes.c_void_p, + *[BArg._ctype for BArg in BArgs], + use_errno=True) + else: + callback_ctype = CTypesFunctionPtr._ctype + self._as_ctype_ptr = callback_ctype(callback) + self._address = ctypes.cast(self._as_ctype_ptr, + ctypes.c_void_p).value + self._own_callback = init + + @staticmethod + def _initialize(ctypes_ptr, value): + if value: + raise NotImplementedError("ctypes backend: not supported: " + "initializers for function pointers") + + def __repr__(self): + c_name = getattr(self, '_name', None) + if c_name: + i = self._reftypename.index('(* &)') + if self._reftypename[i-1] not in ' )*': + c_name = ' ' + c_name + c_name = self._reftypename.replace('(* &)', c_name) + return CTypesData.__repr__(self, c_name) + + def _get_own_repr(self): + if getattr(self, '_own_callback', None) is not None: + return 'calling %r' % (self._own_callback,) + return super(CTypesFunctionPtr, self)._get_own_repr() + + def __call__(self, *args): + if has_varargs: + assert len(args) >= len(BArgs) + extraargs = args[len(BArgs):] + args = args[:len(BArgs)] + else: + assert len(args) == len(BArgs) + ctypes_args = [] + for arg, BArg in zip(args, BArgs): + ctypes_args.append(BArg._arg_to_ctypes(arg)) + if has_varargs: + for i, arg in enumerate(extraargs): + if arg is None: + ctypes_args.append(ctypes.c_void_p(0)) # NULL + continue + if not isinstance(arg, CTypesData): + raise TypeError( + "argument %d passed in the variadic part " + "needs to be a cdata object (got %s)" % + (1 + len(BArgs) + i, type(arg).__name__)) + ctypes_args.append(arg._arg_to_ctypes(arg)) + result = self._as_ctype_ptr(*ctypes_args) + return BResult._from_ctypes(result) + # + CTypesFunctionPtr._fix_class() + return CTypesFunctionPtr + + def new_enum_type(self, name, enumerators, enumvalues, CTypesInt): + assert isinstance(name, str) + reverse_mapping = dict(zip(reversed(enumvalues), + reversed(enumerators))) + # + class CTypesEnum(CTypesInt): + __slots__ = [] + _reftypename = '%s &' % name + + def _get_own_repr(self): + value = self._value + try: + return '%d: %s' % (value, reverse_mapping[value]) + except KeyError: + return str(value) + + def _to_string(self, maxlen): + value = self._value + try: + return reverse_mapping[value] + except KeyError: + return str(value) + # + CTypesEnum._fix_class() + return CTypesEnum + + def get_errno(self): + return ctypes.get_errno() + + def set_errno(self, value): + ctypes.set_errno(value) + + def string(self, b, maxlen=-1): + return b._to_string(maxlen) + + def buffer(self, bptr, size=-1): + raise NotImplementedError("buffer() with ctypes backend") + + def sizeof(self, cdata_or_BType): + if isinstance(cdata_or_BType, CTypesData): + return cdata_or_BType._get_size_of_instance() + else: + assert issubclass(cdata_or_BType, CTypesData) + return cdata_or_BType._get_size() + + def alignof(self, BType): + assert issubclass(BType, CTypesData) + return BType._alignment() + + def newp(self, BType, source): + if not issubclass(BType, CTypesData): + raise TypeError + return BType._newp(source) + + def cast(self, BType, source): + return BType._cast_from(source) + + def callback(self, BType, source, error, onerror): + assert onerror is None # XXX not implemented + return BType(source, error) + + _weakref_cache_ref = None + + def gcp(self, cdata, destructor, size=0): + if self._weakref_cache_ref is None: + import weakref + class MyRef(weakref.ref): + def __eq__(self, other): + myref = self() + return self is other or ( + myref is not None and myref is other()) + def __ne__(self, other): + return not (self == other) + def __hash__(self): + try: + return self._hash + except AttributeError: + self._hash = hash(self()) + return self._hash + self._weakref_cache_ref = {}, MyRef + weak_cache, MyRef = self._weakref_cache_ref + + if destructor is None: + try: + del weak_cache[MyRef(cdata)] + except KeyError: + raise TypeError("Can remove destructor only on a object " + "previously returned by ffi.gc()") + return None + + def remove(k): + cdata, destructor = weak_cache.pop(k, (None, None)) + if destructor is not None: + destructor(cdata) + + new_cdata = self.cast(self.typeof(cdata), cdata) + assert new_cdata is not cdata + weak_cache[MyRef(new_cdata, remove)] = (cdata, destructor) + return new_cdata + + typeof = type + + def getcname(self, BType, replace_with): + return BType._get_c_name(replace_with) + + def typeoffsetof(self, BType, fieldname, num=0): + if isinstance(fieldname, str): + if num == 0 and issubclass(BType, CTypesGenericPtr): + BType = BType._BItem + if not issubclass(BType, CTypesBaseStructOrUnion): + raise TypeError("expected a struct or union ctype") + BField = BType._bfield_types[fieldname] + if BField is Ellipsis: + raise TypeError("not supported for bitfields") + return (BField, BType._offsetof(fieldname)) + elif isinstance(fieldname, (int, long)): + if issubclass(BType, CTypesGenericArray): + BType = BType._CTPtr + if not issubclass(BType, CTypesGenericPtr): + raise TypeError("expected an array or ptr ctype") + BItem = BType._BItem + offset = BItem._get_size() * fieldname + if offset > sys.maxsize: + raise OverflowError + return (BItem, offset) + else: + raise TypeError(type(fieldname)) + + def rawaddressof(self, BTypePtr, cdata, offset=None): + if isinstance(cdata, CTypesBaseStructOrUnion): + ptr = ctypes.pointer(type(cdata)._to_ctypes(cdata)) + elif isinstance(cdata, CTypesGenericPtr): + if offset is None or not issubclass(type(cdata)._BItem, + CTypesBaseStructOrUnion): + raise TypeError("unexpected cdata type") + ptr = type(cdata)._to_ctypes(cdata) + elif isinstance(cdata, CTypesGenericArray): + ptr = type(cdata)._to_ctypes(cdata) + else: + raise TypeError("expected a ") + if offset: + ptr = ctypes.cast( + ctypes.c_void_p( + ctypes.cast(ptr, ctypes.c_void_p).value + offset), + type(ptr)) + return BTypePtr._from_ctypes(ptr) + + +class CTypesLibrary(object): + + def __init__(self, backend, cdll): + self.backend = backend + self.cdll = cdll + + def load_function(self, BType, name): + c_func = getattr(self.cdll, name) + funcobj = BType._from_ctypes(c_func) + funcobj._name = name + return funcobj + + def read_variable(self, BType, name): + try: + ctypes_obj = BType._ctype.in_dll(self.cdll, name) + except AttributeError as e: + raise NotImplementedError(e) + return BType._from_ctypes(ctypes_obj) + + def write_variable(self, BType, name, value): + new_ctypes_obj = BType._to_ctypes(value) + ctypes_obj = BType._ctype.in_dll(self.cdll, name) + ctypes.memmove(ctypes.addressof(ctypes_obj), + ctypes.addressof(new_ctypes_obj), + ctypes.sizeof(BType._ctype)) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/cffi_opcode.py b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/cffi_opcode.py new file mode 100644 index 000000000..a0df98d1c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/cffi_opcode.py @@ -0,0 +1,187 @@ +from .error import VerificationError + +class CffiOp(object): + def __init__(self, op, arg): + self.op = op + self.arg = arg + + def as_c_expr(self): + if self.op is None: + assert isinstance(self.arg, str) + return '(_cffi_opcode_t)(%s)' % (self.arg,) + classname = CLASS_NAME[self.op] + return '_CFFI_OP(_CFFI_OP_%s, %s)' % (classname, self.arg) + + def as_python_bytes(self): + if self.op is None and self.arg.isdigit(): + value = int(self.arg) # non-negative: '-' not in self.arg + if value >= 2**31: + raise OverflowError("cannot emit %r: limited to 2**31-1" + % (self.arg,)) + return format_four_bytes(value) + if isinstance(self.arg, str): + raise VerificationError("cannot emit to Python: %r" % (self.arg,)) + return format_four_bytes((self.arg << 8) | self.op) + + def __str__(self): + classname = CLASS_NAME.get(self.op, self.op) + return '(%s %s)' % (classname, self.arg) + +def format_four_bytes(num): + return '\\x%02X\\x%02X\\x%02X\\x%02X' % ( + (num >> 24) & 0xFF, + (num >> 16) & 0xFF, + (num >> 8) & 0xFF, + (num ) & 0xFF) + +OP_PRIMITIVE = 1 +OP_POINTER = 3 +OP_ARRAY = 5 +OP_OPEN_ARRAY = 7 +OP_STRUCT_UNION = 9 +OP_ENUM = 11 +OP_FUNCTION = 13 +OP_FUNCTION_END = 15 +OP_NOOP = 17 +OP_BITFIELD = 19 +OP_TYPENAME = 21 +OP_CPYTHON_BLTN_V = 23 # varargs +OP_CPYTHON_BLTN_N = 25 # noargs +OP_CPYTHON_BLTN_O = 27 # O (i.e. a single arg) +OP_CONSTANT = 29 +OP_CONSTANT_INT = 31 +OP_GLOBAL_VAR = 33 +OP_DLOPEN_FUNC = 35 +OP_DLOPEN_CONST = 37 +OP_GLOBAL_VAR_F = 39 +OP_EXTERN_PYTHON = 41 + +PRIM_VOID = 0 +PRIM_BOOL = 1 +PRIM_CHAR = 2 +PRIM_SCHAR = 3 +PRIM_UCHAR = 4 +PRIM_SHORT = 5 +PRIM_USHORT = 6 +PRIM_INT = 7 +PRIM_UINT = 8 +PRIM_LONG = 9 +PRIM_ULONG = 10 +PRIM_LONGLONG = 11 +PRIM_ULONGLONG = 12 +PRIM_FLOAT = 13 +PRIM_DOUBLE = 14 +PRIM_LONGDOUBLE = 15 + +PRIM_WCHAR = 16 +PRIM_INT8 = 17 +PRIM_UINT8 = 18 +PRIM_INT16 = 19 +PRIM_UINT16 = 20 +PRIM_INT32 = 21 +PRIM_UINT32 = 22 +PRIM_INT64 = 23 +PRIM_UINT64 = 24 +PRIM_INTPTR = 25 +PRIM_UINTPTR = 26 +PRIM_PTRDIFF = 27 +PRIM_SIZE = 28 +PRIM_SSIZE = 29 +PRIM_INT_LEAST8 = 30 +PRIM_UINT_LEAST8 = 31 +PRIM_INT_LEAST16 = 32 +PRIM_UINT_LEAST16 = 33 +PRIM_INT_LEAST32 = 34 +PRIM_UINT_LEAST32 = 35 +PRIM_INT_LEAST64 = 36 +PRIM_UINT_LEAST64 = 37 +PRIM_INT_FAST8 = 38 +PRIM_UINT_FAST8 = 39 +PRIM_INT_FAST16 = 40 +PRIM_UINT_FAST16 = 41 +PRIM_INT_FAST32 = 42 +PRIM_UINT_FAST32 = 43 +PRIM_INT_FAST64 = 44 +PRIM_UINT_FAST64 = 45 +PRIM_INTMAX = 46 +PRIM_UINTMAX = 47 +PRIM_FLOATCOMPLEX = 48 +PRIM_DOUBLECOMPLEX = 49 +PRIM_CHAR16 = 50 +PRIM_CHAR32 = 51 + +_NUM_PRIM = 52 +_UNKNOWN_PRIM = -1 +_UNKNOWN_FLOAT_PRIM = -2 +_UNKNOWN_LONG_DOUBLE = -3 + +_IO_FILE_STRUCT = -1 + +PRIMITIVE_TO_INDEX = { + 'char': PRIM_CHAR, + 'short': PRIM_SHORT, + 'int': PRIM_INT, + 'long': PRIM_LONG, + 'long long': PRIM_LONGLONG, + 'signed char': PRIM_SCHAR, + 'unsigned char': PRIM_UCHAR, + 'unsigned short': PRIM_USHORT, + 'unsigned int': PRIM_UINT, + 'unsigned long': PRIM_ULONG, + 'unsigned long long': PRIM_ULONGLONG, + 'float': PRIM_FLOAT, + 'double': PRIM_DOUBLE, + 'long double': PRIM_LONGDOUBLE, + 'float _Complex': PRIM_FLOATCOMPLEX, + 'double _Complex': PRIM_DOUBLECOMPLEX, + '_Bool': PRIM_BOOL, + 'wchar_t': PRIM_WCHAR, + 'char16_t': PRIM_CHAR16, + 'char32_t': PRIM_CHAR32, + 'int8_t': PRIM_INT8, + 'uint8_t': PRIM_UINT8, + 'int16_t': PRIM_INT16, + 'uint16_t': PRIM_UINT16, + 'int32_t': PRIM_INT32, + 'uint32_t': PRIM_UINT32, + 'int64_t': PRIM_INT64, + 'uint64_t': PRIM_UINT64, + 'intptr_t': PRIM_INTPTR, + 'uintptr_t': PRIM_UINTPTR, + 'ptrdiff_t': PRIM_PTRDIFF, + 'size_t': PRIM_SIZE, + 'ssize_t': PRIM_SSIZE, + 'int_least8_t': PRIM_INT_LEAST8, + 'uint_least8_t': PRIM_UINT_LEAST8, + 'int_least16_t': PRIM_INT_LEAST16, + 'uint_least16_t': PRIM_UINT_LEAST16, + 'int_least32_t': PRIM_INT_LEAST32, + 'uint_least32_t': PRIM_UINT_LEAST32, + 'int_least64_t': PRIM_INT_LEAST64, + 'uint_least64_t': PRIM_UINT_LEAST64, + 'int_fast8_t': PRIM_INT_FAST8, + 'uint_fast8_t': PRIM_UINT_FAST8, + 'int_fast16_t': PRIM_INT_FAST16, + 'uint_fast16_t': PRIM_UINT_FAST16, + 'int_fast32_t': PRIM_INT_FAST32, + 'uint_fast32_t': PRIM_UINT_FAST32, + 'int_fast64_t': PRIM_INT_FAST64, + 'uint_fast64_t': PRIM_UINT_FAST64, + 'intmax_t': PRIM_INTMAX, + 'uintmax_t': PRIM_UINTMAX, + } + +F_UNION = 0x01 +F_CHECK_FIELDS = 0x02 +F_PACKED = 0x04 +F_EXTERNAL = 0x08 +F_OPAQUE = 0x10 + +G_FLAGS = dict([('_CFFI_' + _key, globals()[_key]) + for _key in ['F_UNION', 'F_CHECK_FIELDS', 'F_PACKED', + 'F_EXTERNAL', 'F_OPAQUE']]) + +CLASS_NAME = {} +for _name, _value in list(globals().items()): + if _name.startswith('OP_') and isinstance(_value, int): + CLASS_NAME[_value] = _name[3:] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/commontypes.py b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/commontypes.py new file mode 100644 index 000000000..8ec97c756 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/commontypes.py @@ -0,0 +1,80 @@ +import sys +from . import model +from .error import FFIError + + +COMMON_TYPES = {} + +try: + # fetch "bool" and all simple Windows types + from _cffi_backend import _get_common_types + _get_common_types(COMMON_TYPES) +except ImportError: + pass + +COMMON_TYPES['FILE'] = model.unknown_type('FILE', '_IO_FILE') +COMMON_TYPES['bool'] = '_Bool' # in case we got ImportError above + +for _type in model.PrimitiveType.ALL_PRIMITIVE_TYPES: + if _type.endswith('_t'): + COMMON_TYPES[_type] = _type +del _type + +_CACHE = {} + +def resolve_common_type(parser, commontype): + try: + return _CACHE[commontype] + except KeyError: + cdecl = COMMON_TYPES.get(commontype, commontype) + if not isinstance(cdecl, str): + result, quals = cdecl, 0 # cdecl is already a BaseType + elif cdecl in model.PrimitiveType.ALL_PRIMITIVE_TYPES: + result, quals = model.PrimitiveType(cdecl), 0 + elif cdecl == 'set-unicode-needed': + raise FFIError("The Windows type %r is only available after " + "you call ffi.set_unicode()" % (commontype,)) + else: + if commontype == cdecl: + raise FFIError( + "Unsupported type: %r. Please look at " + "http://cffi.readthedocs.io/en/latest/cdef.html#ffi-cdef-limitations " + "and file an issue if you think this type should really " + "be supported." % (commontype,)) + result, quals = parser.parse_type_and_quals(cdecl) # recursive + + assert isinstance(result, model.BaseTypeByIdentity) + _CACHE[commontype] = result, quals + return result, quals + + +# ____________________________________________________________ +# extra types for Windows (most of them are in commontypes.c) + + +def win_common_types(): + return { + "UNICODE_STRING": model.StructType( + "_UNICODE_STRING", + ["Length", + "MaximumLength", + "Buffer"], + [model.PrimitiveType("unsigned short"), + model.PrimitiveType("unsigned short"), + model.PointerType(model.PrimitiveType("wchar_t"))], + [-1, -1, -1]), + "PUNICODE_STRING": "UNICODE_STRING *", + "PCUNICODE_STRING": "const UNICODE_STRING *", + + "TBYTE": "set-unicode-needed", + "TCHAR": "set-unicode-needed", + "LPCTSTR": "set-unicode-needed", + "PCTSTR": "set-unicode-needed", + "LPTSTR": "set-unicode-needed", + "PTSTR": "set-unicode-needed", + "PTBYTE": "set-unicode-needed", + "PTCHAR": "set-unicode-needed", + } + +if sys.platform == 'win32': + COMMON_TYPES.update(win_common_types()) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/cparser.py b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/cparser.py new file mode 100644 index 000000000..74830e913 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/cparser.py @@ -0,0 +1,1006 @@ +from . import model +from .commontypes import COMMON_TYPES, resolve_common_type +from .error import FFIError, CDefError +try: + from . import _pycparser as pycparser +except ImportError: + import pycparser +import weakref, re, sys + +try: + if sys.version_info < (3,): + import thread as _thread + else: + import _thread + lock = _thread.allocate_lock() +except ImportError: + lock = None + +def _workaround_for_static_import_finders(): + # Issue #392: packaging tools like cx_Freeze can not find these + # because pycparser uses exec dynamic import. This is an obscure + # workaround. This function is never called. + import pycparser.yacctab + import pycparser.lextab + +CDEF_SOURCE_STRING = "" +_r_comment = re.compile(r"/\*.*?\*/|//([^\n\\]|\\.)*?$", + re.DOTALL | re.MULTILINE) +_r_define = re.compile(r"^\s*#\s*define\s+([A-Za-z_][A-Za-z_0-9]*)" + r"\b((?:[^\n\\]|\\.)*?)$", + re.DOTALL | re.MULTILINE) +_r_line_directive = re.compile(r"^[ \t]*#[ \t]*(?:line|\d+)\b.*$", re.MULTILINE) +_r_partial_enum = re.compile(r"=\s*\.\.\.\s*[,}]|\.\.\.\s*\}") +_r_enum_dotdotdot = re.compile(r"__dotdotdot\d+__$") +_r_partial_array = re.compile(r"\[\s*\.\.\.\s*\]") +_r_words = re.compile(r"\w+|\S") +_parser_cache = None +_r_int_literal = re.compile(r"-?0?x?[0-9a-f]+[lu]*$", re.IGNORECASE) +_r_stdcall1 = re.compile(r"\b(__stdcall|WINAPI)\b") +_r_stdcall2 = re.compile(r"[(]\s*(__stdcall|WINAPI)\b") +_r_cdecl = re.compile(r"\b__cdecl\b") +_r_extern_python = re.compile(r'\bextern\s*"' + r'(Python|Python\s*\+\s*C|C\s*\+\s*Python)"\s*.') +_r_star_const_space = re.compile( # matches "* const " + r"[*]\s*((const|volatile|restrict)\b\s*)+") +_r_int_dotdotdot = re.compile(r"(\b(int|long|short|signed|unsigned|char)\s*)+" + r"\.\.\.") +_r_float_dotdotdot = re.compile(r"\b(double|float)\s*\.\.\.") + +def _get_parser(): + global _parser_cache + if _parser_cache is None: + _parser_cache = pycparser.CParser() + return _parser_cache + +def _workaround_for_old_pycparser(csource): + # Workaround for a pycparser issue (fixed between pycparser 2.10 and + # 2.14): "char*const***" gives us a wrong syntax tree, the same as + # for "char***(*const)". This means we can't tell the difference + # afterwards. But "char(*const(***))" gives us the right syntax + # tree. The issue only occurs if there are several stars in + # sequence with no parenthesis inbetween, just possibly qualifiers. + # Attempt to fix it by adding some parentheses in the source: each + # time we see "* const" or "* const *", we add an opening + # parenthesis before each star---the hard part is figuring out where + # to close them. + parts = [] + while True: + match = _r_star_const_space.search(csource) + if not match: + break + #print repr(''.join(parts)+csource), '=>', + parts.append(csource[:match.start()]) + parts.append('('); closing = ')' + parts.append(match.group()) # e.g. "* const " + endpos = match.end() + if csource.startswith('*', endpos): + parts.append('('); closing += ')' + level = 0 + i = endpos + while i < len(csource): + c = csource[i] + if c == '(': + level += 1 + elif c == ')': + if level == 0: + break + level -= 1 + elif c in ',;=': + if level == 0: + break + i += 1 + csource = csource[endpos:i] + closing + csource[i:] + #print repr(''.join(parts)+csource) + parts.append(csource) + return ''.join(parts) + +def _preprocess_extern_python(csource): + # input: `extern "Python" int foo(int);` or + # `extern "Python" { int foo(int); }` + # output: + # void __cffi_extern_python_start; + # int foo(int); + # void __cffi_extern_python_stop; + # + # input: `extern "Python+C" int foo(int);` + # output: + # void __cffi_extern_python_plus_c_start; + # int foo(int); + # void __cffi_extern_python_stop; + parts = [] + while True: + match = _r_extern_python.search(csource) + if not match: + break + endpos = match.end() - 1 + #print + #print ''.join(parts)+csource + #print '=>' + parts.append(csource[:match.start()]) + if 'C' in match.group(1): + parts.append('void __cffi_extern_python_plus_c_start; ') + else: + parts.append('void __cffi_extern_python_start; ') + if csource[endpos] == '{': + # grouping variant + closing = csource.find('}', endpos) + if closing < 0: + raise CDefError("'extern \"Python\" {': no '}' found") + if csource.find('{', endpos + 1, closing) >= 0: + raise NotImplementedError("cannot use { } inside a block " + "'extern \"Python\" { ... }'") + parts.append(csource[endpos+1:closing]) + csource = csource[closing+1:] + else: + # non-grouping variant + semicolon = csource.find(';', endpos) + if semicolon < 0: + raise CDefError("'extern \"Python\": no ';' found") + parts.append(csource[endpos:semicolon+1]) + csource = csource[semicolon+1:] + parts.append(' void __cffi_extern_python_stop;') + #print ''.join(parts)+csource + #print + parts.append(csource) + return ''.join(parts) + +def _warn_for_string_literal(csource): + if '"' not in csource: + return + for line in csource.splitlines(): + if '"' in line and not line.lstrip().startswith('#'): + import warnings + warnings.warn("String literal found in cdef() or type source. " + "String literals are ignored here, but you should " + "remove them anyway because some character sequences " + "confuse pre-parsing.") + break + +def _warn_for_non_extern_non_static_global_variable(decl): + if not decl.storage: + import warnings + warnings.warn("Global variable '%s' in cdef(): for consistency " + "with C it should have a storage class specifier " + "(usually 'extern')" % (decl.name,)) + +def _remove_line_directives(csource): + # _r_line_directive matches whole lines, without the final \n, if they + # start with '#line' with some spacing allowed, or '#NUMBER'. This + # function stores them away and replaces them with exactly the string + # '#line@N', where N is the index in the list 'line_directives'. + line_directives = [] + def replace(m): + i = len(line_directives) + line_directives.append(m.group()) + return '#line@%d' % i + csource = _r_line_directive.sub(replace, csource) + return csource, line_directives + +def _put_back_line_directives(csource, line_directives): + def replace(m): + s = m.group() + if not s.startswith('#line@'): + raise AssertionError("unexpected #line directive " + "(should have been processed and removed") + return line_directives[int(s[6:])] + return _r_line_directive.sub(replace, csource) + +def _preprocess(csource): + # First, remove the lines of the form '#line N "filename"' because + # the "filename" part could confuse the rest + csource, line_directives = _remove_line_directives(csource) + # Remove comments. NOTE: this only work because the cdef() section + # should not contain any string literals (except in line directives)! + def replace_keeping_newlines(m): + return ' ' + m.group().count('\n') * '\n' + csource = _r_comment.sub(replace_keeping_newlines, csource) + # Remove the "#define FOO x" lines + macros = {} + for match in _r_define.finditer(csource): + macroname, macrovalue = match.groups() + macrovalue = macrovalue.replace('\\\n', '').strip() + macros[macroname] = macrovalue + csource = _r_define.sub('', csource) + # + if pycparser.__version__ < '2.14': + csource = _workaround_for_old_pycparser(csource) + # + # BIG HACK: replace WINAPI or __stdcall with "volatile const". + # It doesn't make sense for the return type of a function to be + # "volatile volatile const", so we abuse it to detect __stdcall... + # Hack number 2 is that "int(volatile *fptr)();" is not valid C + # syntax, so we place the "volatile" before the opening parenthesis. + csource = _r_stdcall2.sub(' volatile volatile const(', csource) + csource = _r_stdcall1.sub(' volatile volatile const ', csource) + csource = _r_cdecl.sub(' ', csource) + # + # Replace `extern "Python"` with start/end markers + csource = _preprocess_extern_python(csource) + # + # Now there should not be any string literal left; warn if we get one + _warn_for_string_literal(csource) + # + # Replace "[...]" with "[__dotdotdotarray__]" + csource = _r_partial_array.sub('[__dotdotdotarray__]', csource) + # + # Replace "...}" with "__dotdotdotNUM__}". This construction should + # occur only at the end of enums; at the end of structs we have "...;}" + # and at the end of vararg functions "...);". Also replace "=...[,}]" + # with ",__dotdotdotNUM__[,}]": this occurs in the enums too, when + # giving an unknown value. + matches = list(_r_partial_enum.finditer(csource)) + for number, match in enumerate(reversed(matches)): + p = match.start() + if csource[p] == '=': + p2 = csource.find('...', p, match.end()) + assert p2 > p + csource = '%s,__dotdotdot%d__ %s' % (csource[:p], number, + csource[p2+3:]) + else: + assert csource[p:p+3] == '...' + csource = '%s __dotdotdot%d__ %s' % (csource[:p], number, + csource[p+3:]) + # Replace "int ..." or "unsigned long int..." with "__dotdotdotint__" + csource = _r_int_dotdotdot.sub(' __dotdotdotint__ ', csource) + # Replace "float ..." or "double..." with "__dotdotdotfloat__" + csource = _r_float_dotdotdot.sub(' __dotdotdotfloat__ ', csource) + # Replace all remaining "..." with the same name, "__dotdotdot__", + # which is declared with a typedef for the purpose of C parsing. + csource = csource.replace('...', ' __dotdotdot__ ') + # Finally, put back the line directives + csource = _put_back_line_directives(csource, line_directives) + return csource, macros + +def _common_type_names(csource): + # Look in the source for what looks like usages of types from the + # list of common types. A "usage" is approximated here as the + # appearance of the word, minus a "definition" of the type, which + # is the last word in a "typedef" statement. Approximative only + # but should be fine for all the common types. + look_for_words = set(COMMON_TYPES) + look_for_words.add(';') + look_for_words.add(',') + look_for_words.add('(') + look_for_words.add(')') + look_for_words.add('typedef') + words_used = set() + is_typedef = False + paren = 0 + previous_word = '' + for word in _r_words.findall(csource): + if word in look_for_words: + if word == ';': + if is_typedef: + words_used.discard(previous_word) + look_for_words.discard(previous_word) + is_typedef = False + elif word == 'typedef': + is_typedef = True + paren = 0 + elif word == '(': + paren += 1 + elif word == ')': + paren -= 1 + elif word == ',': + if is_typedef and paren == 0: + words_used.discard(previous_word) + look_for_words.discard(previous_word) + else: # word in COMMON_TYPES + words_used.add(word) + previous_word = word + return words_used + + +class Parser(object): + + def __init__(self): + self._declarations = {} + self._included_declarations = set() + self._anonymous_counter = 0 + self._structnode2type = weakref.WeakKeyDictionary() + self._options = {} + self._int_constants = {} + self._recomplete = [] + self._uses_new_feature = None + + def _parse(self, csource): + csource, macros = _preprocess(csource) + # XXX: for more efficiency we would need to poke into the + # internals of CParser... the following registers the + # typedefs, because their presence or absence influences the + # parsing itself (but what they are typedef'ed to plays no role) + ctn = _common_type_names(csource) + typenames = [] + for name in sorted(self._declarations): + if name.startswith('typedef '): + name = name[8:] + typenames.append(name) + ctn.discard(name) + typenames += sorted(ctn) + # + csourcelines = [] + csourcelines.append('# 1 ""') + for typename in typenames: + csourcelines.append('typedef int %s;' % typename) + csourcelines.append('typedef int __dotdotdotint__, __dotdotdotfloat__,' + ' __dotdotdot__;') + # this forces pycparser to consider the following in the file + # called from line 1 + csourcelines.append('# 1 "%s"' % (CDEF_SOURCE_STRING,)) + csourcelines.append(csource) + fullcsource = '\n'.join(csourcelines) + if lock is not None: + lock.acquire() # pycparser is not thread-safe... + try: + ast = _get_parser().parse(fullcsource) + except pycparser.c_parser.ParseError as e: + self.convert_pycparser_error(e, csource) + finally: + if lock is not None: + lock.release() + # csource will be used to find buggy source text + return ast, macros, csource + + def _convert_pycparser_error(self, e, csource): + # xxx look for ":NUM:" at the start of str(e) + # and interpret that as a line number. This will not work if + # the user gives explicit ``# NUM "FILE"`` directives. + line = None + msg = str(e) + match = re.match(r"%s:(\d+):" % (CDEF_SOURCE_STRING,), msg) + if match: + linenum = int(match.group(1), 10) + csourcelines = csource.splitlines() + if 1 <= linenum <= len(csourcelines): + line = csourcelines[linenum-1] + return line + + def convert_pycparser_error(self, e, csource): + line = self._convert_pycparser_error(e, csource) + + msg = str(e) + if line: + msg = 'cannot parse "%s"\n%s' % (line.strip(), msg) + else: + msg = 'parse error\n%s' % (msg,) + raise CDefError(msg) + + def parse(self, csource, override=False, packed=False, pack=None, + dllexport=False): + if packed: + if packed != True: + raise ValueError("'packed' should be False or True; use " + "'pack' to give another value") + if pack: + raise ValueError("cannot give both 'pack' and 'packed'") + pack = 1 + elif pack: + if pack & (pack - 1): + raise ValueError("'pack' must be a power of two, not %r" % + (pack,)) + else: + pack = 0 + prev_options = self._options + try: + self._options = {'override': override, + 'packed': pack, + 'dllexport': dllexport} + self._internal_parse(csource) + finally: + self._options = prev_options + + def _internal_parse(self, csource): + ast, macros, csource = self._parse(csource) + # add the macros + self._process_macros(macros) + # find the first "__dotdotdot__" and use that as a separator + # between the repeated typedefs and the real csource + iterator = iter(ast.ext) + for decl in iterator: + if decl.name == '__dotdotdot__': + break + else: + assert 0 + current_decl = None + # + try: + self._inside_extern_python = '__cffi_extern_python_stop' + for decl in iterator: + current_decl = decl + if isinstance(decl, pycparser.c_ast.Decl): + self._parse_decl(decl) + elif isinstance(decl, pycparser.c_ast.Typedef): + if not decl.name: + raise CDefError("typedef does not declare any name", + decl) + quals = 0 + if (isinstance(decl.type.type, pycparser.c_ast.IdentifierType) and + decl.type.type.names[-1].startswith('__dotdotdot')): + realtype = self._get_unknown_type(decl) + elif (isinstance(decl.type, pycparser.c_ast.PtrDecl) and + isinstance(decl.type.type, pycparser.c_ast.TypeDecl) and + isinstance(decl.type.type.type, + pycparser.c_ast.IdentifierType) and + decl.type.type.type.names[-1].startswith('__dotdotdot')): + realtype = self._get_unknown_ptr_type(decl) + else: + realtype, quals = self._get_type_and_quals( + decl.type, name=decl.name, partial_length_ok=True, + typedef_example="*(%s *)0" % (decl.name,)) + self._declare('typedef ' + decl.name, realtype, quals=quals) + elif decl.__class__.__name__ == 'Pragma': + pass # skip pragma, only in pycparser 2.15 + else: + raise CDefError("unexpected <%s>: this construct is valid " + "C but not valid in cdef()" % + decl.__class__.__name__, decl) + except CDefError as e: + if len(e.args) == 1: + e.args = e.args + (current_decl,) + raise + except FFIError as e: + msg = self._convert_pycparser_error(e, csource) + if msg: + e.args = (e.args[0] + "\n *** Err: %s" % msg,) + raise + + def _add_constants(self, key, val): + if key in self._int_constants: + if self._int_constants[key] == val: + return # ignore identical double declarations + raise FFIError( + "multiple declarations of constant: %s" % (key,)) + self._int_constants[key] = val + + def _add_integer_constant(self, name, int_str): + int_str = int_str.lower().rstrip("ul") + neg = int_str.startswith('-') + if neg: + int_str = int_str[1:] + # "010" is not valid oct in py3 + if (int_str.startswith("0") and int_str != '0' + and not int_str.startswith("0x")): + int_str = "0o" + int_str[1:] + pyvalue = int(int_str, 0) + if neg: + pyvalue = -pyvalue + self._add_constants(name, pyvalue) + self._declare('macro ' + name, pyvalue) + + def _process_macros(self, macros): + for key, value in macros.items(): + value = value.strip() + if _r_int_literal.match(value): + self._add_integer_constant(key, value) + elif value == '...': + self._declare('macro ' + key, value) + else: + raise CDefError( + 'only supports one of the following syntax:\n' + ' #define %s ... (literally dot-dot-dot)\n' + ' #define %s NUMBER (with NUMBER an integer' + ' constant, decimal/hex/octal)\n' + 'got:\n' + ' #define %s %s' + % (key, key, key, value)) + + def _declare_function(self, tp, quals, decl): + tp = self._get_type_pointer(tp, quals) + if self._options.get('dllexport'): + tag = 'dllexport_python ' + elif self._inside_extern_python == '__cffi_extern_python_start': + tag = 'extern_python ' + elif self._inside_extern_python == '__cffi_extern_python_plus_c_start': + tag = 'extern_python_plus_c ' + else: + tag = 'function ' + self._declare(tag + decl.name, tp) + + def _parse_decl(self, decl): + node = decl.type + if isinstance(node, pycparser.c_ast.FuncDecl): + tp, quals = self._get_type_and_quals(node, name=decl.name) + assert isinstance(tp, model.RawFunctionType) + self._declare_function(tp, quals, decl) + else: + if isinstance(node, pycparser.c_ast.Struct): + self._get_struct_union_enum_type('struct', node) + elif isinstance(node, pycparser.c_ast.Union): + self._get_struct_union_enum_type('union', node) + elif isinstance(node, pycparser.c_ast.Enum): + self._get_struct_union_enum_type('enum', node) + elif not decl.name: + raise CDefError("construct does not declare any variable", + decl) + # + if decl.name: + tp, quals = self._get_type_and_quals(node, + partial_length_ok=True) + if tp.is_raw_function: + self._declare_function(tp, quals, decl) + elif (tp.is_integer_type() and + hasattr(decl, 'init') and + hasattr(decl.init, 'value') and + _r_int_literal.match(decl.init.value)): + self._add_integer_constant(decl.name, decl.init.value) + elif (tp.is_integer_type() and + isinstance(decl.init, pycparser.c_ast.UnaryOp) and + decl.init.op == '-' and + hasattr(decl.init.expr, 'value') and + _r_int_literal.match(decl.init.expr.value)): + self._add_integer_constant(decl.name, + '-' + decl.init.expr.value) + elif (tp is model.void_type and + decl.name.startswith('__cffi_extern_python_')): + # hack: `extern "Python"` in the C source is replaced + # with "void __cffi_extern_python_start;" and + # "void __cffi_extern_python_stop;" + self._inside_extern_python = decl.name + else: + if self._inside_extern_python !='__cffi_extern_python_stop': + raise CDefError( + "cannot declare constants or " + "variables with 'extern \"Python\"'") + if (quals & model.Q_CONST) and not tp.is_array_type: + self._declare('constant ' + decl.name, tp, quals=quals) + else: + _warn_for_non_extern_non_static_global_variable(decl) + self._declare('variable ' + decl.name, tp, quals=quals) + + def parse_type(self, cdecl): + return self.parse_type_and_quals(cdecl)[0] + + def parse_type_and_quals(self, cdecl): + ast, macros = self._parse('void __dummy(\n%s\n);' % cdecl)[:2] + assert not macros + exprnode = ast.ext[-1].type.args.params[0] + if isinstance(exprnode, pycparser.c_ast.ID): + raise CDefError("unknown identifier '%s'" % (exprnode.name,)) + return self._get_type_and_quals(exprnode.type) + + def _declare(self, name, obj, included=False, quals=0): + if name in self._declarations: + prevobj, prevquals = self._declarations[name] + if prevobj is obj and prevquals == quals: + return + if not self._options.get('override'): + raise FFIError( + "multiple declarations of %s (for interactive usage, " + "try cdef(xx, override=True))" % (name,)) + assert '__dotdotdot__' not in name.split() + self._declarations[name] = (obj, quals) + if included: + self._included_declarations.add(obj) + + def _extract_quals(self, type): + quals = 0 + if isinstance(type, (pycparser.c_ast.TypeDecl, + pycparser.c_ast.PtrDecl)): + if 'const' in type.quals: + quals |= model.Q_CONST + if 'volatile' in type.quals: + quals |= model.Q_VOLATILE + if 'restrict' in type.quals: + quals |= model.Q_RESTRICT + return quals + + def _get_type_pointer(self, type, quals, declname=None): + if isinstance(type, model.RawFunctionType): + return type.as_function_pointer() + if (isinstance(type, model.StructOrUnionOrEnum) and + type.name.startswith('$') and type.name[1:].isdigit() and + type.forcename is None and declname is not None): + return model.NamedPointerType(type, declname, quals) + return model.PointerType(type, quals) + + def _get_type_and_quals(self, typenode, name=None, partial_length_ok=False, + typedef_example=None): + # first, dereference typedefs, if we have it already parsed, we're good + if (isinstance(typenode, pycparser.c_ast.TypeDecl) and + isinstance(typenode.type, pycparser.c_ast.IdentifierType) and + len(typenode.type.names) == 1 and + ('typedef ' + typenode.type.names[0]) in self._declarations): + tp, quals = self._declarations['typedef ' + typenode.type.names[0]] + quals |= self._extract_quals(typenode) + return tp, quals + # + if isinstance(typenode, pycparser.c_ast.ArrayDecl): + # array type + if typenode.dim is None: + length = None + else: + length = self._parse_constant( + typenode.dim, partial_length_ok=partial_length_ok) + # a hack: in 'typedef int foo_t[...][...];', don't use '...' as + # the length but use directly the C expression that would be + # generated by recompiler.py. This lets the typedef be used in + # many more places within recompiler.py + if typedef_example is not None: + if length == '...': + length = '_cffi_array_len(%s)' % (typedef_example,) + typedef_example = "*" + typedef_example + # + tp, quals = self._get_type_and_quals(typenode.type, + partial_length_ok=partial_length_ok, + typedef_example=typedef_example) + return model.ArrayType(tp, length), quals + # + if isinstance(typenode, pycparser.c_ast.PtrDecl): + # pointer type + itemtype, itemquals = self._get_type_and_quals(typenode.type) + tp = self._get_type_pointer(itemtype, itemquals, declname=name) + quals = self._extract_quals(typenode) + return tp, quals + # + if isinstance(typenode, pycparser.c_ast.TypeDecl): + quals = self._extract_quals(typenode) + type = typenode.type + if isinstance(type, pycparser.c_ast.IdentifierType): + # assume a primitive type. get it from .names, but reduce + # synonyms to a single chosen combination + names = list(type.names) + if names != ['signed', 'char']: # keep this unmodified + prefixes = {} + while names: + name = names[0] + if name in ('short', 'long', 'signed', 'unsigned'): + prefixes[name] = prefixes.get(name, 0) + 1 + del names[0] + else: + break + # ignore the 'signed' prefix below, and reorder the others + newnames = [] + for prefix in ('unsigned', 'short', 'long'): + for i in range(prefixes.get(prefix, 0)): + newnames.append(prefix) + if not names: + names = ['int'] # implicitly + if names == ['int']: # but kill it if 'short' or 'long' + if 'short' in prefixes or 'long' in prefixes: + names = [] + names = newnames + names + ident = ' '.join(names) + if ident == 'void': + return model.void_type, quals + if ident == '__dotdotdot__': + raise FFIError(':%d: bad usage of "..."' % + typenode.coord.line) + tp0, quals0 = resolve_common_type(self, ident) + return tp0, (quals | quals0) + # + if isinstance(type, pycparser.c_ast.Struct): + # 'struct foobar' + tp = self._get_struct_union_enum_type('struct', type, name) + return tp, quals + # + if isinstance(type, pycparser.c_ast.Union): + # 'union foobar' + tp = self._get_struct_union_enum_type('union', type, name) + return tp, quals + # + if isinstance(type, pycparser.c_ast.Enum): + # 'enum foobar' + tp = self._get_struct_union_enum_type('enum', type, name) + return tp, quals + # + if isinstance(typenode, pycparser.c_ast.FuncDecl): + # a function type + return self._parse_function_type(typenode, name), 0 + # + # nested anonymous structs or unions end up here + if isinstance(typenode, pycparser.c_ast.Struct): + return self._get_struct_union_enum_type('struct', typenode, name, + nested=True), 0 + if isinstance(typenode, pycparser.c_ast.Union): + return self._get_struct_union_enum_type('union', typenode, name, + nested=True), 0 + # + raise FFIError(":%d: bad or unsupported type declaration" % + typenode.coord.line) + + def _parse_function_type(self, typenode, funcname=None): + params = list(getattr(typenode.args, 'params', [])) + for i, arg in enumerate(params): + if not hasattr(arg, 'type'): + raise CDefError("%s arg %d: unknown type '%s'" + " (if you meant to use the old C syntax of giving" + " untyped arguments, it is not supported)" + % (funcname or 'in expression', i + 1, + getattr(arg, 'name', '?'))) + ellipsis = ( + len(params) > 0 and + isinstance(params[-1].type, pycparser.c_ast.TypeDecl) and + isinstance(params[-1].type.type, + pycparser.c_ast.IdentifierType) and + params[-1].type.type.names == ['__dotdotdot__']) + if ellipsis: + params.pop() + if not params: + raise CDefError( + "%s: a function with only '(...)' as argument" + " is not correct C" % (funcname or 'in expression')) + args = [self._as_func_arg(*self._get_type_and_quals(argdeclnode.type)) + for argdeclnode in params] + if not ellipsis and args == [model.void_type]: + args = [] + result, quals = self._get_type_and_quals(typenode.type) + # the 'quals' on the result type are ignored. HACK: we absure them + # to detect __stdcall functions: we textually replace "__stdcall" + # with "volatile volatile const" above. + abi = None + if hasattr(typenode.type, 'quals'): # else, probable syntax error anyway + if typenode.type.quals[-3:] == ['volatile', 'volatile', 'const']: + abi = '__stdcall' + return model.RawFunctionType(tuple(args), result, ellipsis, abi) + + def _as_func_arg(self, type, quals): + if isinstance(type, model.ArrayType): + return model.PointerType(type.item, quals) + elif isinstance(type, model.RawFunctionType): + return type.as_function_pointer() + else: + return type + + def _get_struct_union_enum_type(self, kind, type, name=None, nested=False): + # First, a level of caching on the exact 'type' node of the AST. + # This is obscure, but needed because pycparser "unrolls" declarations + # such as "typedef struct { } foo_t, *foo_p" and we end up with + # an AST that is not a tree, but a DAG, with the "type" node of the + # two branches foo_t and foo_p of the trees being the same node. + # It's a bit silly but detecting "DAG-ness" in the AST tree seems + # to be the only way to distinguish this case from two independent + # structs. See test_struct_with_two_usages. + try: + return self._structnode2type[type] + except KeyError: + pass + # + # Note that this must handle parsing "struct foo" any number of + # times and always return the same StructType object. Additionally, + # one of these times (not necessarily the first), the fields of + # the struct can be specified with "struct foo { ...fields... }". + # If no name is given, then we have to create a new anonymous struct + # with no caching; in this case, the fields are either specified + # right now or never. + # + force_name = name + name = type.name + # + # get the type or create it if needed + if name is None: + # 'force_name' is used to guess a more readable name for + # anonymous structs, for the common case "typedef struct { } foo". + if force_name is not None: + explicit_name = '$%s' % force_name + else: + self._anonymous_counter += 1 + explicit_name = '$%d' % self._anonymous_counter + tp = None + else: + explicit_name = name + key = '%s %s' % (kind, name) + tp, _ = self._declarations.get(key, (None, None)) + # + if tp is None: + if kind == 'struct': + tp = model.StructType(explicit_name, None, None, None) + elif kind == 'union': + tp = model.UnionType(explicit_name, None, None, None) + elif kind == 'enum': + if explicit_name == '__dotdotdot__': + raise CDefError("Enums cannot be declared with ...") + tp = self._build_enum_type(explicit_name, type.values) + else: + raise AssertionError("kind = %r" % (kind,)) + if name is not None: + self._declare(key, tp) + else: + if kind == 'enum' and type.values is not None: + raise NotImplementedError( + "enum %s: the '{}' declaration should appear on the first " + "time the enum is mentioned, not later" % explicit_name) + if not tp.forcename: + tp.force_the_name(force_name) + if tp.forcename and '$' in tp.name: + self._declare('anonymous %s' % tp.forcename, tp) + # + self._structnode2type[type] = tp + # + # enums: done here + if kind == 'enum': + return tp + # + # is there a 'type.decls'? If yes, then this is the place in the + # C sources that declare the fields. If no, then just return the + # existing type, possibly still incomplete. + if type.decls is None: + return tp + # + if tp.fldnames is not None: + raise CDefError("duplicate declaration of struct %s" % name) + fldnames = [] + fldtypes = [] + fldbitsize = [] + fldquals = [] + for decl in type.decls: + if (isinstance(decl.type, pycparser.c_ast.IdentifierType) and + ''.join(decl.type.names) == '__dotdotdot__'): + # XXX pycparser is inconsistent: 'names' should be a list + # of strings, but is sometimes just one string. Use + # str.join() as a way to cope with both. + self._make_partial(tp, nested) + continue + if decl.bitsize is None: + bitsize = -1 + else: + bitsize = self._parse_constant(decl.bitsize) + self._partial_length = False + type, fqual = self._get_type_and_quals(decl.type, + partial_length_ok=True) + if self._partial_length: + self._make_partial(tp, nested) + if isinstance(type, model.StructType) and type.partial: + self._make_partial(tp, nested) + fldnames.append(decl.name or '') + fldtypes.append(type) + fldbitsize.append(bitsize) + fldquals.append(fqual) + tp.fldnames = tuple(fldnames) + tp.fldtypes = tuple(fldtypes) + tp.fldbitsize = tuple(fldbitsize) + tp.fldquals = tuple(fldquals) + if fldbitsize != [-1] * len(fldbitsize): + if isinstance(tp, model.StructType) and tp.partial: + raise NotImplementedError("%s: using both bitfields and '...;'" + % (tp,)) + tp.packed = self._options.get('packed') + if tp.completed: # must be re-completed: it is not opaque any more + tp.completed = 0 + self._recomplete.append(tp) + return tp + + def _make_partial(self, tp, nested): + if not isinstance(tp, model.StructOrUnion): + raise CDefError("%s cannot be partial" % (tp,)) + if not tp.has_c_name() and not nested: + raise NotImplementedError("%s is partial but has no C name" %(tp,)) + tp.partial = True + + def _parse_constant(self, exprnode, partial_length_ok=False): + # for now, limited to expressions that are an immediate number + # or positive/negative number + if isinstance(exprnode, pycparser.c_ast.Constant): + s = exprnode.value + if '0' <= s[0] <= '9': + s = s.rstrip('uUlL') + try: + if s.startswith('0'): + return int(s, 8) + else: + return int(s, 10) + except ValueError: + if len(s) > 1: + if s.lower()[0:2] == '0x': + return int(s, 16) + elif s.lower()[0:2] == '0b': + return int(s, 2) + raise CDefError("invalid constant %r" % (s,)) + elif s[0] == "'" and s[-1] == "'" and ( + len(s) == 3 or (len(s) == 4 and s[1] == "\\")): + return ord(s[-2]) + else: + raise CDefError("invalid constant %r" % (s,)) + # + if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and + exprnode.op == '+'): + return self._parse_constant(exprnode.expr) + # + if (isinstance(exprnode, pycparser.c_ast.UnaryOp) and + exprnode.op == '-'): + return -self._parse_constant(exprnode.expr) + # load previously defined int constant + if (isinstance(exprnode, pycparser.c_ast.ID) and + exprnode.name in self._int_constants): + return self._int_constants[exprnode.name] + # + if (isinstance(exprnode, pycparser.c_ast.ID) and + exprnode.name == '__dotdotdotarray__'): + if partial_length_ok: + self._partial_length = True + return '...' + raise FFIError(":%d: unsupported '[...]' here, cannot derive " + "the actual array length in this context" + % exprnode.coord.line) + # + if isinstance(exprnode, pycparser.c_ast.BinaryOp): + left = self._parse_constant(exprnode.left) + right = self._parse_constant(exprnode.right) + if exprnode.op == '+': + return left + right + elif exprnode.op == '-': + return left - right + elif exprnode.op == '*': + return left * right + elif exprnode.op == '/': + return self._c_div(left, right) + elif exprnode.op == '%': + return left - self._c_div(left, right) * right + elif exprnode.op == '<<': + return left << right + elif exprnode.op == '>>': + return left >> right + elif exprnode.op == '&': + return left & right + elif exprnode.op == '|': + return left | right + elif exprnode.op == '^': + return left ^ right + # + raise FFIError(":%d: unsupported expression: expected a " + "simple numeric constant" % exprnode.coord.line) + + def _c_div(self, a, b): + result = a // b + if ((a < 0) ^ (b < 0)) and (a % b) != 0: + result += 1 + return result + + def _build_enum_type(self, explicit_name, decls): + if decls is not None: + partial = False + enumerators = [] + enumvalues = [] + nextenumvalue = 0 + for enum in decls.enumerators: + if _r_enum_dotdotdot.match(enum.name): + partial = True + continue + if enum.value is not None: + nextenumvalue = self._parse_constant(enum.value) + enumerators.append(enum.name) + enumvalues.append(nextenumvalue) + self._add_constants(enum.name, nextenumvalue) + nextenumvalue += 1 + enumerators = tuple(enumerators) + enumvalues = tuple(enumvalues) + tp = model.EnumType(explicit_name, enumerators, enumvalues) + tp.partial = partial + else: # opaque enum + tp = model.EnumType(explicit_name, (), ()) + return tp + + def include(self, other): + for name, (tp, quals) in other._declarations.items(): + if name.startswith('anonymous $enum_$'): + continue # fix for test_anonymous_enum_include + kind = name.split(' ', 1)[0] + if kind in ('struct', 'union', 'enum', 'anonymous', 'typedef'): + self._declare(name, tp, included=True, quals=quals) + for k, v in other._int_constants.items(): + self._add_constants(k, v) + + def _get_unknown_type(self, decl): + typenames = decl.type.type.names + if typenames == ['__dotdotdot__']: + return model.unknown_type(decl.name) + + if typenames == ['__dotdotdotint__']: + if self._uses_new_feature is None: + self._uses_new_feature = "'typedef int... %s'" % decl.name + return model.UnknownIntegerType(decl.name) + + if typenames == ['__dotdotdotfloat__']: + # note: not for 'long double' so far + if self._uses_new_feature is None: + self._uses_new_feature = "'typedef float... %s'" % decl.name + return model.UnknownFloatType(decl.name) + + raise FFIError(':%d: unsupported usage of "..." in typedef' + % decl.coord.line) + + def _get_unknown_ptr_type(self, decl): + if decl.type.type.type.names == ['__dotdotdot__']: + return model.unknown_ptr_type(decl.name) + raise FFIError(':%d: unsupported usage of "..." in typedef' + % decl.coord.line) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/error.py b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/error.py new file mode 100644 index 000000000..0a27247c3 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/error.py @@ -0,0 +1,31 @@ + +class FFIError(Exception): + __module__ = 'cffi' + +class CDefError(Exception): + __module__ = 'cffi' + def __str__(self): + try: + current_decl = self.args[1] + filename = current_decl.coord.file + linenum = current_decl.coord.line + prefix = '%s:%d: ' % (filename, linenum) + except (AttributeError, TypeError, IndexError): + prefix = '' + return '%s%s' % (prefix, self.args[0]) + +class VerificationError(Exception): + """ An error raised when verification fails + """ + __module__ = 'cffi' + +class VerificationMissing(Exception): + """ An error raised when incomplete structures are passed into + cdef, but no verification has been done + """ + __module__ = 'cffi' + +class PkgConfigError(Exception): + """ An error raised for missing modules in pkg-config + """ + __module__ = 'cffi' diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/ffiplatform.py b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/ffiplatform.py new file mode 100644 index 000000000..adca28f1a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/ffiplatform.py @@ -0,0 +1,113 @@ +import sys, os +from .error import VerificationError + + +LIST_OF_FILE_NAMES = ['sources', 'include_dirs', 'library_dirs', + 'extra_objects', 'depends'] + +def get_extension(srcfilename, modname, sources=(), **kwds): + from cffi._shimmed_dist_utils import Extension + allsources = [srcfilename] + for src in sources: + allsources.append(os.path.normpath(src)) + return Extension(name=modname, sources=allsources, **kwds) + +def compile(tmpdir, ext, compiler_verbose=0, debug=None): + """Compile a C extension module using distutils.""" + + saved_environ = os.environ.copy() + try: + outputfilename = _build(tmpdir, ext, compiler_verbose, debug) + outputfilename = os.path.abspath(outputfilename) + finally: + # workaround for a distutils bugs where some env vars can + # become longer and longer every time it is used + for key, value in saved_environ.items(): + if os.environ.get(key) != value: + os.environ[key] = value + return outputfilename + +def _build(tmpdir, ext, compiler_verbose=0, debug=None): + # XXX compact but horrible :-( + from cffi._shimmed_dist_utils import Distribution, CompileError, LinkError, set_threshold, set_verbosity + + dist = Distribution({'ext_modules': [ext]}) + dist.parse_config_files() + options = dist.get_option_dict('build_ext') + if debug is None: + debug = sys.flags.debug + options['debug'] = ('ffiplatform', debug) + options['force'] = ('ffiplatform', True) + options['build_lib'] = ('ffiplatform', tmpdir) + options['build_temp'] = ('ffiplatform', tmpdir) + # + try: + old_level = set_threshold(0) or 0 + try: + set_verbosity(compiler_verbose) + dist.run_command('build_ext') + cmd_obj = dist.get_command_obj('build_ext') + [soname] = cmd_obj.get_outputs() + finally: + set_threshold(old_level) + except (CompileError, LinkError) as e: + raise VerificationError('%s: %s' % (e.__class__.__name__, e)) + # + return soname + +try: + from os.path import samefile +except ImportError: + def samefile(f1, f2): + return os.path.abspath(f1) == os.path.abspath(f2) + +def maybe_relative_path(path): + if not os.path.isabs(path): + return path # already relative + dir = path + names = [] + while True: + prevdir = dir + dir, name = os.path.split(prevdir) + if dir == prevdir or not dir: + return path # failed to make it relative + names.append(name) + try: + if samefile(dir, os.curdir): + names.reverse() + return os.path.join(*names) + except OSError: + pass + +# ____________________________________________________________ + +try: + int_or_long = (int, long) + import cStringIO +except NameError: + int_or_long = int # Python 3 + import io as cStringIO + +def _flatten(x, f): + if isinstance(x, str): + f.write('%ds%s' % (len(x), x)) + elif isinstance(x, dict): + keys = sorted(x.keys()) + f.write('%dd' % len(keys)) + for key in keys: + _flatten(key, f) + _flatten(x[key], f) + elif isinstance(x, (list, tuple)): + f.write('%dl' % len(x)) + for value in x: + _flatten(value, f) + elif isinstance(x, int_or_long): + f.write('%di' % (x,)) + else: + raise TypeError( + "the keywords to verify() contains unsupported object %r" % (x,)) + +def flatten(x): + f = cStringIO.StringIO() + _flatten(x, f) + return f.getvalue() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/lock.py b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/lock.py new file mode 100644 index 000000000..db91b7158 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/lock.py @@ -0,0 +1,30 @@ +import sys + +if sys.version_info < (3,): + try: + from thread import allocate_lock + except ImportError: + from dummy_thread import allocate_lock +else: + try: + from _thread import allocate_lock + except ImportError: + from _dummy_thread import allocate_lock + + +##import sys +##l1 = allocate_lock + +##class allocate_lock(object): +## def __init__(self): +## self._real = l1() +## def __enter__(self): +## for i in range(4, 0, -1): +## print sys._getframe(i).f_code +## print +## return self._real.__enter__() +## def __exit__(self, *args): +## return self._real.__exit__(*args) +## def acquire(self, f): +## assert f is False +## return self._real.acquire(f) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/model.py b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/model.py new file mode 100644 index 000000000..1708f43df --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/model.py @@ -0,0 +1,618 @@ +import types +import weakref + +from .lock import allocate_lock +from .error import CDefError, VerificationError, VerificationMissing + +# type qualifiers +Q_CONST = 0x01 +Q_RESTRICT = 0x02 +Q_VOLATILE = 0x04 + +def qualify(quals, replace_with): + if quals & Q_CONST: + replace_with = ' const ' + replace_with.lstrip() + if quals & Q_VOLATILE: + replace_with = ' volatile ' + replace_with.lstrip() + if quals & Q_RESTRICT: + # It seems that __restrict is supported by gcc and msvc. + # If you hit some different compiler, add a #define in + # _cffi_include.h for it (and in its copies, documented there) + replace_with = ' __restrict ' + replace_with.lstrip() + return replace_with + + +class BaseTypeByIdentity(object): + is_array_type = False + is_raw_function = False + + def get_c_name(self, replace_with='', context='a C file', quals=0): + result = self.c_name_with_marker + assert result.count('&') == 1 + # some logic duplication with ffi.getctype()... :-( + replace_with = replace_with.strip() + if replace_with: + if replace_with.startswith('*') and '&[' in result: + replace_with = '(%s)' % replace_with + elif not replace_with[0] in '[(': + replace_with = ' ' + replace_with + replace_with = qualify(quals, replace_with) + result = result.replace('&', replace_with) + if '$' in result: + raise VerificationError( + "cannot generate '%s' in %s: unknown type name" + % (self._get_c_name(), context)) + return result + + def _get_c_name(self): + return self.c_name_with_marker.replace('&', '') + + def has_c_name(self): + return '$' not in self._get_c_name() + + def is_integer_type(self): + return False + + def get_cached_btype(self, ffi, finishlist, can_delay=False): + try: + BType = ffi._cached_btypes[self] + except KeyError: + BType = self.build_backend_type(ffi, finishlist) + BType2 = ffi._cached_btypes.setdefault(self, BType) + assert BType2 is BType + return BType + + def __repr__(self): + return '<%s>' % (self._get_c_name(),) + + def _get_items(self): + return [(name, getattr(self, name)) for name in self._attrs_] + + +class BaseType(BaseTypeByIdentity): + + def __eq__(self, other): + return (self.__class__ == other.__class__ and + self._get_items() == other._get_items()) + + def __ne__(self, other): + return not self == other + + def __hash__(self): + return hash((self.__class__, tuple(self._get_items()))) + + +class VoidType(BaseType): + _attrs_ = () + + def __init__(self): + self.c_name_with_marker = 'void&' + + def build_backend_type(self, ffi, finishlist): + return global_cache(self, ffi, 'new_void_type') + +void_type = VoidType() + + +class BasePrimitiveType(BaseType): + def is_complex_type(self): + return False + + +class PrimitiveType(BasePrimitiveType): + _attrs_ = ('name',) + + ALL_PRIMITIVE_TYPES = { + 'char': 'c', + 'short': 'i', + 'int': 'i', + 'long': 'i', + 'long long': 'i', + 'signed char': 'i', + 'unsigned char': 'i', + 'unsigned short': 'i', + 'unsigned int': 'i', + 'unsigned long': 'i', + 'unsigned long long': 'i', + 'float': 'f', + 'double': 'f', + 'long double': 'f', + 'float _Complex': 'j', + 'double _Complex': 'j', + '_Bool': 'i', + # the following types are not primitive in the C sense + 'wchar_t': 'c', + 'char16_t': 'c', + 'char32_t': 'c', + 'int8_t': 'i', + 'uint8_t': 'i', + 'int16_t': 'i', + 'uint16_t': 'i', + 'int32_t': 'i', + 'uint32_t': 'i', + 'int64_t': 'i', + 'uint64_t': 'i', + 'int_least8_t': 'i', + 'uint_least8_t': 'i', + 'int_least16_t': 'i', + 'uint_least16_t': 'i', + 'int_least32_t': 'i', + 'uint_least32_t': 'i', + 'int_least64_t': 'i', + 'uint_least64_t': 'i', + 'int_fast8_t': 'i', + 'uint_fast8_t': 'i', + 'int_fast16_t': 'i', + 'uint_fast16_t': 'i', + 'int_fast32_t': 'i', + 'uint_fast32_t': 'i', + 'int_fast64_t': 'i', + 'uint_fast64_t': 'i', + 'intptr_t': 'i', + 'uintptr_t': 'i', + 'intmax_t': 'i', + 'uintmax_t': 'i', + 'ptrdiff_t': 'i', + 'size_t': 'i', + 'ssize_t': 'i', + } + + def __init__(self, name): + assert name in self.ALL_PRIMITIVE_TYPES + self.name = name + self.c_name_with_marker = name + '&' + + def is_char_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'c' + def is_integer_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'i' + def is_float_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'f' + def is_complex_type(self): + return self.ALL_PRIMITIVE_TYPES[self.name] == 'j' + + def build_backend_type(self, ffi, finishlist): + return global_cache(self, ffi, 'new_primitive_type', self.name) + + +class UnknownIntegerType(BasePrimitiveType): + _attrs_ = ('name',) + + def __init__(self, name): + self.name = name + self.c_name_with_marker = name + '&' + + def is_integer_type(self): + return True + + def build_backend_type(self, ffi, finishlist): + raise NotImplementedError("integer type '%s' can only be used after " + "compilation" % self.name) + +class UnknownFloatType(BasePrimitiveType): + _attrs_ = ('name', ) + + def __init__(self, name): + self.name = name + self.c_name_with_marker = name + '&' + + def build_backend_type(self, ffi, finishlist): + raise NotImplementedError("float type '%s' can only be used after " + "compilation" % self.name) + + +class BaseFunctionType(BaseType): + _attrs_ = ('args', 'result', 'ellipsis', 'abi') + + def __init__(self, args, result, ellipsis, abi=None): + self.args = args + self.result = result + self.ellipsis = ellipsis + self.abi = abi + # + reprargs = [arg._get_c_name() for arg in self.args] + if self.ellipsis: + reprargs.append('...') + reprargs = reprargs or ['void'] + replace_with = self._base_pattern % (', '.join(reprargs),) + if abi is not None: + replace_with = replace_with[:1] + abi + ' ' + replace_with[1:] + self.c_name_with_marker = ( + self.result.c_name_with_marker.replace('&', replace_with)) + + +class RawFunctionType(BaseFunctionType): + # Corresponds to a C type like 'int(int)', which is the C type of + # a function, but not a pointer-to-function. The backend has no + # notion of such a type; it's used temporarily by parsing. + _base_pattern = '(&)(%s)' + is_raw_function = True + + def build_backend_type(self, ffi, finishlist): + raise CDefError("cannot render the type %r: it is a function " + "type, not a pointer-to-function type" % (self,)) + + def as_function_pointer(self): + return FunctionPtrType(self.args, self.result, self.ellipsis, self.abi) + + +class FunctionPtrType(BaseFunctionType): + _base_pattern = '(*&)(%s)' + + def build_backend_type(self, ffi, finishlist): + result = self.result.get_cached_btype(ffi, finishlist) + args = [] + for tp in self.args: + args.append(tp.get_cached_btype(ffi, finishlist)) + abi_args = () + if self.abi == "__stdcall": + if not self.ellipsis: # __stdcall ignored for variadic funcs + try: + abi_args = (ffi._backend.FFI_STDCALL,) + except AttributeError: + pass + return global_cache(self, ffi, 'new_function_type', + tuple(args), result, self.ellipsis, *abi_args) + + def as_raw_function(self): + return RawFunctionType(self.args, self.result, self.ellipsis, self.abi) + + +class PointerType(BaseType): + _attrs_ = ('totype', 'quals') + + def __init__(self, totype, quals=0): + self.totype = totype + self.quals = quals + extra = " *&" + if totype.is_array_type: + extra = "(%s)" % (extra.lstrip(),) + extra = qualify(quals, extra) + self.c_name_with_marker = totype.c_name_with_marker.replace('&', extra) + + def build_backend_type(self, ffi, finishlist): + BItem = self.totype.get_cached_btype(ffi, finishlist, can_delay=True) + return global_cache(self, ffi, 'new_pointer_type', BItem) + +voidp_type = PointerType(void_type) + +def ConstPointerType(totype): + return PointerType(totype, Q_CONST) + +const_voidp_type = ConstPointerType(void_type) + + +class NamedPointerType(PointerType): + _attrs_ = ('totype', 'name') + + def __init__(self, totype, name, quals=0): + PointerType.__init__(self, totype, quals) + self.name = name + self.c_name_with_marker = name + '&' + + +class ArrayType(BaseType): + _attrs_ = ('item', 'length') + is_array_type = True + + def __init__(self, item, length): + self.item = item + self.length = length + # + if length is None: + brackets = '&[]' + elif length == '...': + brackets = '&[/*...*/]' + else: + brackets = '&[%s]' % length + self.c_name_with_marker = ( + self.item.c_name_with_marker.replace('&', brackets)) + + def length_is_unknown(self): + return isinstance(self.length, str) + + def resolve_length(self, newlength): + return ArrayType(self.item, newlength) + + def build_backend_type(self, ffi, finishlist): + if self.length_is_unknown(): + raise CDefError("cannot render the type %r: unknown length" % + (self,)) + self.item.get_cached_btype(ffi, finishlist) # force the item BType + BPtrItem = PointerType(self.item).get_cached_btype(ffi, finishlist) + return global_cache(self, ffi, 'new_array_type', BPtrItem, self.length) + +char_array_type = ArrayType(PrimitiveType('char'), None) + + +class StructOrUnionOrEnum(BaseTypeByIdentity): + _attrs_ = ('name',) + forcename = None + + def build_c_name_with_marker(self): + name = self.forcename or '%s %s' % (self.kind, self.name) + self.c_name_with_marker = name + '&' + + def force_the_name(self, forcename): + self.forcename = forcename + self.build_c_name_with_marker() + + def get_official_name(self): + assert self.c_name_with_marker.endswith('&') + return self.c_name_with_marker[:-1] + + +class StructOrUnion(StructOrUnionOrEnum): + fixedlayout = None + completed = 0 + partial = False + packed = 0 + + def __init__(self, name, fldnames, fldtypes, fldbitsize, fldquals=None): + self.name = name + self.fldnames = fldnames + self.fldtypes = fldtypes + self.fldbitsize = fldbitsize + self.fldquals = fldquals + self.build_c_name_with_marker() + + def anonymous_struct_fields(self): + if self.fldtypes is not None: + for name, type in zip(self.fldnames, self.fldtypes): + if name == '' and isinstance(type, StructOrUnion): + yield type + + def enumfields(self, expand_anonymous_struct_union=True): + fldquals = self.fldquals + if fldquals is None: + fldquals = (0,) * len(self.fldnames) + for name, type, bitsize, quals in zip(self.fldnames, self.fldtypes, + self.fldbitsize, fldquals): + if (name == '' and isinstance(type, StructOrUnion) + and expand_anonymous_struct_union): + # nested anonymous struct/union + for result in type.enumfields(): + yield result + else: + yield (name, type, bitsize, quals) + + def force_flatten(self): + # force the struct or union to have a declaration that lists + # directly all fields returned by enumfields(), flattening + # nested anonymous structs/unions. + names = [] + types = [] + bitsizes = [] + fldquals = [] + for name, type, bitsize, quals in self.enumfields(): + names.append(name) + types.append(type) + bitsizes.append(bitsize) + fldquals.append(quals) + self.fldnames = tuple(names) + self.fldtypes = tuple(types) + self.fldbitsize = tuple(bitsizes) + self.fldquals = tuple(fldquals) + + def get_cached_btype(self, ffi, finishlist, can_delay=False): + BType = StructOrUnionOrEnum.get_cached_btype(self, ffi, finishlist, + can_delay) + if not can_delay: + self.finish_backend_type(ffi, finishlist) + return BType + + def finish_backend_type(self, ffi, finishlist): + if self.completed: + if self.completed != 2: + raise NotImplementedError("recursive structure declaration " + "for '%s'" % (self.name,)) + return + BType = ffi._cached_btypes[self] + # + self.completed = 1 + # + if self.fldtypes is None: + pass # not completing it: it's an opaque struct + # + elif self.fixedlayout is None: + fldtypes = [tp.get_cached_btype(ffi, finishlist) + for tp in self.fldtypes] + lst = list(zip(self.fldnames, fldtypes, self.fldbitsize)) + extra_flags = () + if self.packed: + if self.packed == 1: + extra_flags = (8,) # SF_PACKED + else: + extra_flags = (0, self.packed) + ffi._backend.complete_struct_or_union(BType, lst, self, + -1, -1, *extra_flags) + # + else: + fldtypes = [] + fieldofs, fieldsize, totalsize, totalalignment = self.fixedlayout + for i in range(len(self.fldnames)): + fsize = fieldsize[i] + ftype = self.fldtypes[i] + # + if isinstance(ftype, ArrayType) and ftype.length_is_unknown(): + # fix the length to match the total size + BItemType = ftype.item.get_cached_btype(ffi, finishlist) + nlen, nrest = divmod(fsize, ffi.sizeof(BItemType)) + if nrest != 0: + self._verification_error( + "field '%s.%s' has a bogus size?" % ( + self.name, self.fldnames[i] or '{}')) + ftype = ftype.resolve_length(nlen) + self.fldtypes = (self.fldtypes[:i] + (ftype,) + + self.fldtypes[i+1:]) + # + BFieldType = ftype.get_cached_btype(ffi, finishlist) + if isinstance(ftype, ArrayType) and ftype.length is None: + assert fsize == 0 + else: + bitemsize = ffi.sizeof(BFieldType) + if bitemsize != fsize: + self._verification_error( + "field '%s.%s' is declared as %d bytes, but is " + "really %d bytes" % (self.name, + self.fldnames[i] or '{}', + bitemsize, fsize)) + fldtypes.append(BFieldType) + # + lst = list(zip(self.fldnames, fldtypes, self.fldbitsize, fieldofs)) + ffi._backend.complete_struct_or_union(BType, lst, self, + totalsize, totalalignment) + self.completed = 2 + + def _verification_error(self, msg): + raise VerificationError(msg) + + def check_not_partial(self): + if self.partial and self.fixedlayout is None: + raise VerificationMissing(self._get_c_name()) + + def build_backend_type(self, ffi, finishlist): + self.check_not_partial() + finishlist.append(self) + # + return global_cache(self, ffi, 'new_%s_type' % self.kind, + self.get_official_name(), key=self) + + +class StructType(StructOrUnion): + kind = 'struct' + + +class UnionType(StructOrUnion): + kind = 'union' + + +class EnumType(StructOrUnionOrEnum): + kind = 'enum' + partial = False + partial_resolved = False + + def __init__(self, name, enumerators, enumvalues, baseinttype=None): + self.name = name + self.enumerators = enumerators + self.enumvalues = enumvalues + self.baseinttype = baseinttype + self.build_c_name_with_marker() + + def force_the_name(self, forcename): + StructOrUnionOrEnum.force_the_name(self, forcename) + if self.forcename is None: + name = self.get_official_name() + self.forcename = '$' + name.replace(' ', '_') + + def check_not_partial(self): + if self.partial and not self.partial_resolved: + raise VerificationMissing(self._get_c_name()) + + def build_backend_type(self, ffi, finishlist): + self.check_not_partial() + base_btype = self.build_baseinttype(ffi, finishlist) + return global_cache(self, ffi, 'new_enum_type', + self.get_official_name(), + self.enumerators, self.enumvalues, + base_btype, key=self) + + def build_baseinttype(self, ffi, finishlist): + if self.baseinttype is not None: + return self.baseinttype.get_cached_btype(ffi, finishlist) + # + if self.enumvalues: + smallest_value = min(self.enumvalues) + largest_value = max(self.enumvalues) + else: + import warnings + try: + # XXX! The goal is to ensure that the warnings.warn() + # will not suppress the warning. We want to get it + # several times if we reach this point several times. + __warningregistry__.clear() + except NameError: + pass + warnings.warn("%r has no values explicitly defined; " + "guessing that it is equivalent to 'unsigned int'" + % self._get_c_name()) + smallest_value = largest_value = 0 + if smallest_value < 0: # needs a signed type + sign = 1 + candidate1 = PrimitiveType("int") + candidate2 = PrimitiveType("long") + else: + sign = 0 + candidate1 = PrimitiveType("unsigned int") + candidate2 = PrimitiveType("unsigned long") + btype1 = candidate1.get_cached_btype(ffi, finishlist) + btype2 = candidate2.get_cached_btype(ffi, finishlist) + size1 = ffi.sizeof(btype1) + size2 = ffi.sizeof(btype2) + if (smallest_value >= ((-1) << (8*size1-1)) and + largest_value < (1 << (8*size1-sign))): + return btype1 + if (smallest_value >= ((-1) << (8*size2-1)) and + largest_value < (1 << (8*size2-sign))): + return btype2 + raise CDefError("%s values don't all fit into either 'long' " + "or 'unsigned long'" % self._get_c_name()) + +def unknown_type(name, structname=None): + if structname is None: + structname = '$%s' % name + tp = StructType(structname, None, None, None) + tp.force_the_name(name) + tp.origin = "unknown_type" + return tp + +def unknown_ptr_type(name, structname=None): + if structname is None: + structname = '$$%s' % name + tp = StructType(structname, None, None, None) + return NamedPointerType(tp, name) + + +global_lock = allocate_lock() +_typecache_cffi_backend = weakref.WeakValueDictionary() + +def get_typecache(backend): + # returns _typecache_cffi_backend if backend is the _cffi_backend + # module, or type(backend).__typecache if backend is an instance of + # CTypesBackend (or some FakeBackend class during tests) + if isinstance(backend, types.ModuleType): + return _typecache_cffi_backend + with global_lock: + if not hasattr(type(backend), '__typecache'): + type(backend).__typecache = weakref.WeakValueDictionary() + return type(backend).__typecache + +def global_cache(srctype, ffi, funcname, *args, **kwds): + key = kwds.pop('key', (funcname, args)) + assert not kwds + try: + return ffi._typecache[key] + except KeyError: + pass + try: + res = getattr(ffi._backend, funcname)(*args) + except NotImplementedError as e: + raise NotImplementedError("%s: %r: %s" % (funcname, srctype, e)) + # note that setdefault() on WeakValueDictionary is not atomic + # and contains a rare bug (http://bugs.python.org/issue19542); + # we have to use a lock and do it ourselves + cache = ffi._typecache + with global_lock: + res1 = cache.get(key) + if res1 is None: + cache[key] = res + return res + else: + return res1 + +def pointer_cache(ffi, BType): + return global_cache('?', ffi, 'new_pointer_type', BType) + +def attach_exception_info(e, name): + if e.args and type(e.args[0]) is str: + e.args = ('%s: %s' % (name, e.args[0]),) + e.args[1:] diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/parse_c_type.h b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/parse_c_type.h new file mode 100644 index 000000000..84e4ef856 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/parse_c_type.h @@ -0,0 +1,181 @@ + +/* This part is from file 'cffi/parse_c_type.h'. It is copied at the + beginning of C sources generated by CFFI's ffi.set_source(). */ + +typedef void *_cffi_opcode_t; + +#define _CFFI_OP(opcode, arg) (_cffi_opcode_t)(opcode | (((uintptr_t)(arg)) << 8)) +#define _CFFI_GETOP(cffi_opcode) ((unsigned char)(uintptr_t)cffi_opcode) +#define _CFFI_GETARG(cffi_opcode) (((intptr_t)cffi_opcode) >> 8) + +#define _CFFI_OP_PRIMITIVE 1 +#define _CFFI_OP_POINTER 3 +#define _CFFI_OP_ARRAY 5 +#define _CFFI_OP_OPEN_ARRAY 7 +#define _CFFI_OP_STRUCT_UNION 9 +#define _CFFI_OP_ENUM 11 +#define _CFFI_OP_FUNCTION 13 +#define _CFFI_OP_FUNCTION_END 15 +#define _CFFI_OP_NOOP 17 +#define _CFFI_OP_BITFIELD 19 +#define _CFFI_OP_TYPENAME 21 +#define _CFFI_OP_CPYTHON_BLTN_V 23 // varargs +#define _CFFI_OP_CPYTHON_BLTN_N 25 // noargs +#define _CFFI_OP_CPYTHON_BLTN_O 27 // O (i.e. a single arg) +#define _CFFI_OP_CONSTANT 29 +#define _CFFI_OP_CONSTANT_INT 31 +#define _CFFI_OP_GLOBAL_VAR 33 +#define _CFFI_OP_DLOPEN_FUNC 35 +#define _CFFI_OP_DLOPEN_CONST 37 +#define _CFFI_OP_GLOBAL_VAR_F 39 +#define _CFFI_OP_EXTERN_PYTHON 41 + +#define _CFFI_PRIM_VOID 0 +#define _CFFI_PRIM_BOOL 1 +#define _CFFI_PRIM_CHAR 2 +#define _CFFI_PRIM_SCHAR 3 +#define _CFFI_PRIM_UCHAR 4 +#define _CFFI_PRIM_SHORT 5 +#define _CFFI_PRIM_USHORT 6 +#define _CFFI_PRIM_INT 7 +#define _CFFI_PRIM_UINT 8 +#define _CFFI_PRIM_LONG 9 +#define _CFFI_PRIM_ULONG 10 +#define _CFFI_PRIM_LONGLONG 11 +#define _CFFI_PRIM_ULONGLONG 12 +#define _CFFI_PRIM_FLOAT 13 +#define _CFFI_PRIM_DOUBLE 14 +#define _CFFI_PRIM_LONGDOUBLE 15 + +#define _CFFI_PRIM_WCHAR 16 +#define _CFFI_PRIM_INT8 17 +#define _CFFI_PRIM_UINT8 18 +#define _CFFI_PRIM_INT16 19 +#define _CFFI_PRIM_UINT16 20 +#define _CFFI_PRIM_INT32 21 +#define _CFFI_PRIM_UINT32 22 +#define _CFFI_PRIM_INT64 23 +#define _CFFI_PRIM_UINT64 24 +#define _CFFI_PRIM_INTPTR 25 +#define _CFFI_PRIM_UINTPTR 26 +#define _CFFI_PRIM_PTRDIFF 27 +#define _CFFI_PRIM_SIZE 28 +#define _CFFI_PRIM_SSIZE 29 +#define _CFFI_PRIM_INT_LEAST8 30 +#define _CFFI_PRIM_UINT_LEAST8 31 +#define _CFFI_PRIM_INT_LEAST16 32 +#define _CFFI_PRIM_UINT_LEAST16 33 +#define _CFFI_PRIM_INT_LEAST32 34 +#define _CFFI_PRIM_UINT_LEAST32 35 +#define _CFFI_PRIM_INT_LEAST64 36 +#define _CFFI_PRIM_UINT_LEAST64 37 +#define _CFFI_PRIM_INT_FAST8 38 +#define _CFFI_PRIM_UINT_FAST8 39 +#define _CFFI_PRIM_INT_FAST16 40 +#define _CFFI_PRIM_UINT_FAST16 41 +#define _CFFI_PRIM_INT_FAST32 42 +#define _CFFI_PRIM_UINT_FAST32 43 +#define _CFFI_PRIM_INT_FAST64 44 +#define _CFFI_PRIM_UINT_FAST64 45 +#define _CFFI_PRIM_INTMAX 46 +#define _CFFI_PRIM_UINTMAX 47 +#define _CFFI_PRIM_FLOATCOMPLEX 48 +#define _CFFI_PRIM_DOUBLECOMPLEX 49 +#define _CFFI_PRIM_CHAR16 50 +#define _CFFI_PRIM_CHAR32 51 + +#define _CFFI__NUM_PRIM 52 +#define _CFFI__UNKNOWN_PRIM (-1) +#define _CFFI__UNKNOWN_FLOAT_PRIM (-2) +#define _CFFI__UNKNOWN_LONG_DOUBLE (-3) + +#define _CFFI__IO_FILE_STRUCT (-1) + + +struct _cffi_global_s { + const char *name; + void *address; + _cffi_opcode_t type_op; + void *size_or_direct_fn; // OP_GLOBAL_VAR: size, or 0 if unknown + // OP_CPYTHON_BLTN_*: addr of direct function +}; + +struct _cffi_getconst_s { + unsigned long long value; + const struct _cffi_type_context_s *ctx; + int gindex; +}; + +struct _cffi_struct_union_s { + const char *name; + int type_index; // -> _cffi_types, on a OP_STRUCT_UNION + int flags; // _CFFI_F_* flags below + size_t size; + int alignment; + int first_field_index; // -> _cffi_fields array + int num_fields; +}; +#define _CFFI_F_UNION 0x01 // is a union, not a struct +#define _CFFI_F_CHECK_FIELDS 0x02 // complain if fields are not in the + // "standard layout" or if some are missing +#define _CFFI_F_PACKED 0x04 // for CHECK_FIELDS, assume a packed struct +#define _CFFI_F_EXTERNAL 0x08 // in some other ffi.include() +#define _CFFI_F_OPAQUE 0x10 // opaque + +struct _cffi_field_s { + const char *name; + size_t field_offset; + size_t field_size; + _cffi_opcode_t field_type_op; +}; + +struct _cffi_enum_s { + const char *name; + int type_index; // -> _cffi_types, on a OP_ENUM + int type_prim; // _CFFI_PRIM_xxx + const char *enumerators; // comma-delimited string +}; + +struct _cffi_typename_s { + const char *name; + int type_index; /* if opaque, points to a possibly artificial + OP_STRUCT which is itself opaque */ +}; + +struct _cffi_type_context_s { + _cffi_opcode_t *types; + const struct _cffi_global_s *globals; + const struct _cffi_field_s *fields; + const struct _cffi_struct_union_s *struct_unions; + const struct _cffi_enum_s *enums; + const struct _cffi_typename_s *typenames; + int num_globals; + int num_struct_unions; + int num_enums; + int num_typenames; + const char *const *includes; + int num_types; + int flags; /* future extension */ +}; + +struct _cffi_parse_info_s { + const struct _cffi_type_context_s *ctx; + _cffi_opcode_t *output; + unsigned int output_size; + size_t error_location; + const char *error_message; +}; + +struct _cffi_externpy_s { + const char *name; + size_t size_of_result; + void *reserved1, *reserved2; +}; + +#ifdef _CFFI_INTERNAL +static int parse_c_type(struct _cffi_parse_info_s *info, const char *input); +static int search_in_globals(const struct _cffi_type_context_s *ctx, + const char *search, size_t search_len); +static int search_in_struct_unions(const struct _cffi_type_context_s *ctx, + const char *search, size_t search_len); +#endif diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/pkgconfig.py b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/pkgconfig.py new file mode 100644 index 000000000..5c93f15a6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/pkgconfig.py @@ -0,0 +1,121 @@ +# pkg-config, https://www.freedesktop.org/wiki/Software/pkg-config/ integration for cffi +import sys, os, subprocess + +from .error import PkgConfigError + + +def merge_flags(cfg1, cfg2): + """Merge values from cffi config flags cfg2 to cf1 + + Example: + merge_flags({"libraries": ["one"]}, {"libraries": ["two"]}) + {"libraries": ["one", "two"]} + """ + for key, value in cfg2.items(): + if key not in cfg1: + cfg1[key] = value + else: + if not isinstance(cfg1[key], list): + raise TypeError("cfg1[%r] should be a list of strings" % (key,)) + if not isinstance(value, list): + raise TypeError("cfg2[%r] should be a list of strings" % (key,)) + cfg1[key].extend(value) + return cfg1 + + +def call(libname, flag, encoding=sys.getfilesystemencoding()): + """Calls pkg-config and returns the output if found + """ + a = ["pkg-config", "--print-errors"] + a.append(flag) + a.append(libname) + try: + pc = subprocess.Popen(a, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + except EnvironmentError as e: + raise PkgConfigError("cannot run pkg-config: %s" % (str(e).strip(),)) + + bout, berr = pc.communicate() + if pc.returncode != 0: + try: + berr = berr.decode(encoding) + except Exception: + pass + raise PkgConfigError(berr.strip()) + + if sys.version_info >= (3,) and not isinstance(bout, str): # Python 3.x + try: + bout = bout.decode(encoding) + except UnicodeDecodeError: + raise PkgConfigError("pkg-config %s %s returned bytes that cannot " + "be decoded with encoding %r:\n%r" % + (flag, libname, encoding, bout)) + + if os.altsep != '\\' and '\\' in bout: + raise PkgConfigError("pkg-config %s %s returned an unsupported " + "backslash-escaped output:\n%r" % + (flag, libname, bout)) + return bout + + +def flags_from_pkgconfig(libs): + r"""Return compiler line flags for FFI.set_source based on pkg-config output + + Usage + ... + ffibuilder.set_source("_foo", pkgconfig = ["libfoo", "libbar >= 1.8.3"]) + + If pkg-config is installed on build machine, then arguments include_dirs, + library_dirs, libraries, define_macros, extra_compile_args and + extra_link_args are extended with an output of pkg-config for libfoo and + libbar. + + Raises PkgConfigError in case the pkg-config call fails. + """ + + def get_include_dirs(string): + return [x[2:] for x in string.split() if x.startswith("-I")] + + def get_library_dirs(string): + return [x[2:] for x in string.split() if x.startswith("-L")] + + def get_libraries(string): + return [x[2:] for x in string.split() if x.startswith("-l")] + + # convert -Dfoo=bar to list of tuples [("foo", "bar")] expected by distutils + def get_macros(string): + def _macro(x): + x = x[2:] # drop "-D" + if '=' in x: + return tuple(x.split("=", 1)) # "-Dfoo=bar" => ("foo", "bar") + else: + return (x, None) # "-Dfoo" => ("foo", None) + return [_macro(x) for x in string.split() if x.startswith("-D")] + + def get_other_cflags(string): + return [x for x in string.split() if not x.startswith("-I") and + not x.startswith("-D")] + + def get_other_libs(string): + return [x for x in string.split() if not x.startswith("-L") and + not x.startswith("-l")] + + # return kwargs for given libname + def kwargs(libname): + fse = sys.getfilesystemencoding() + all_cflags = call(libname, "--cflags") + all_libs = call(libname, "--libs") + return { + "include_dirs": get_include_dirs(all_cflags), + "library_dirs": get_library_dirs(all_libs), + "libraries": get_libraries(all_libs), + "define_macros": get_macros(all_cflags), + "extra_compile_args": get_other_cflags(all_cflags), + "extra_link_args": get_other_libs(all_libs), + } + + # merge all arguments together + ret = {} + for libname in libs: + lib_flags = kwargs(libname) + merge_flags(ret, lib_flags) + return ret diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/recompiler.py b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/recompiler.py new file mode 100644 index 000000000..4167bc05f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/recompiler.py @@ -0,0 +1,1581 @@ +import os, sys, io +from . import ffiplatform, model +from .error import VerificationError +from .cffi_opcode import * + +VERSION_BASE = 0x2601 +VERSION_EMBEDDED = 0x2701 +VERSION_CHAR16CHAR32 = 0x2801 + +USE_LIMITED_API = (sys.platform != 'win32' or sys.version_info < (3, 0) or + sys.version_info >= (3, 5)) + + +class GlobalExpr: + def __init__(self, name, address, type_op, size=0, check_value=0): + self.name = name + self.address = address + self.type_op = type_op + self.size = size + self.check_value = check_value + + def as_c_expr(self): + return ' { "%s", (void *)%s, %s, (void *)%s },' % ( + self.name, self.address, self.type_op.as_c_expr(), self.size) + + def as_python_expr(self): + return "b'%s%s',%d" % (self.type_op.as_python_bytes(), self.name, + self.check_value) + +class FieldExpr: + def __init__(self, name, field_offset, field_size, fbitsize, field_type_op): + self.name = name + self.field_offset = field_offset + self.field_size = field_size + self.fbitsize = fbitsize + self.field_type_op = field_type_op + + def as_c_expr(self): + spaces = " " * len(self.name) + return (' { "%s", %s,\n' % (self.name, self.field_offset) + + ' %s %s,\n' % (spaces, self.field_size) + + ' %s %s },' % (spaces, self.field_type_op.as_c_expr())) + + def as_python_expr(self): + raise NotImplementedError + + def as_field_python_expr(self): + if self.field_type_op.op == OP_NOOP: + size_expr = '' + elif self.field_type_op.op == OP_BITFIELD: + size_expr = format_four_bytes(self.fbitsize) + else: + raise NotImplementedError + return "b'%s%s%s'" % (self.field_type_op.as_python_bytes(), + size_expr, + self.name) + +class StructUnionExpr: + def __init__(self, name, type_index, flags, size, alignment, comment, + first_field_index, c_fields): + self.name = name + self.type_index = type_index + self.flags = flags + self.size = size + self.alignment = alignment + self.comment = comment + self.first_field_index = first_field_index + self.c_fields = c_fields + + def as_c_expr(self): + return (' { "%s", %d, %s,' % (self.name, self.type_index, self.flags) + + '\n %s, %s, ' % (self.size, self.alignment) + + '%d, %d ' % (self.first_field_index, len(self.c_fields)) + + ('/* %s */ ' % self.comment if self.comment else '') + + '},') + + def as_python_expr(self): + flags = eval(self.flags, G_FLAGS) + fields_expr = [c_field.as_field_python_expr() + for c_field in self.c_fields] + return "(b'%s%s%s',%s)" % ( + format_four_bytes(self.type_index), + format_four_bytes(flags), + self.name, + ','.join(fields_expr)) + +class EnumExpr: + def __init__(self, name, type_index, size, signed, allenums): + self.name = name + self.type_index = type_index + self.size = size + self.signed = signed + self.allenums = allenums + + def as_c_expr(self): + return (' { "%s", %d, _cffi_prim_int(%s, %s),\n' + ' "%s" },' % (self.name, self.type_index, + self.size, self.signed, self.allenums)) + + def as_python_expr(self): + prim_index = { + (1, 0): PRIM_UINT8, (1, 1): PRIM_INT8, + (2, 0): PRIM_UINT16, (2, 1): PRIM_INT16, + (4, 0): PRIM_UINT32, (4, 1): PRIM_INT32, + (8, 0): PRIM_UINT64, (8, 1): PRIM_INT64, + }[self.size, self.signed] + return "b'%s%s%s\\x00%s'" % (format_four_bytes(self.type_index), + format_four_bytes(prim_index), + self.name, self.allenums) + +class TypenameExpr: + def __init__(self, name, type_index): + self.name = name + self.type_index = type_index + + def as_c_expr(self): + return ' { "%s", %d },' % (self.name, self.type_index) + + def as_python_expr(self): + return "b'%s%s'" % (format_four_bytes(self.type_index), self.name) + + +# ____________________________________________________________ + + +class Recompiler: + _num_externpy = 0 + + def __init__(self, ffi, module_name, target_is_python=False): + self.ffi = ffi + self.module_name = module_name + self.target_is_python = target_is_python + self._version = VERSION_BASE + + def needs_version(self, ver): + self._version = max(self._version, ver) + + def collect_type_table(self): + self._typesdict = {} + self._generate("collecttype") + # + all_decls = sorted(self._typesdict, key=str) + # + # prepare all FUNCTION bytecode sequences first + self.cffi_types = [] + for tp in all_decls: + if tp.is_raw_function: + assert self._typesdict[tp] is None + self._typesdict[tp] = len(self.cffi_types) + self.cffi_types.append(tp) # placeholder + for tp1 in tp.args: + assert isinstance(tp1, (model.VoidType, + model.BasePrimitiveType, + model.PointerType, + model.StructOrUnionOrEnum, + model.FunctionPtrType)) + if self._typesdict[tp1] is None: + self._typesdict[tp1] = len(self.cffi_types) + self.cffi_types.append(tp1) # placeholder + self.cffi_types.append('END') # placeholder + # + # prepare all OTHER bytecode sequences + for tp in all_decls: + if not tp.is_raw_function and self._typesdict[tp] is None: + self._typesdict[tp] = len(self.cffi_types) + self.cffi_types.append(tp) # placeholder + if tp.is_array_type and tp.length is not None: + self.cffi_types.append('LEN') # placeholder + assert None not in self._typesdict.values() + # + # collect all structs and unions and enums + self._struct_unions = {} + self._enums = {} + for tp in all_decls: + if isinstance(tp, model.StructOrUnion): + self._struct_unions[tp] = None + elif isinstance(tp, model.EnumType): + self._enums[tp] = None + for i, tp in enumerate(sorted(self._struct_unions, + key=lambda tp: tp.name)): + self._struct_unions[tp] = i + for i, tp in enumerate(sorted(self._enums, + key=lambda tp: tp.name)): + self._enums[tp] = i + # + # emit all bytecode sequences now + for tp in all_decls: + method = getattr(self, '_emit_bytecode_' + tp.__class__.__name__) + method(tp, self._typesdict[tp]) + # + # consistency check + for op in self.cffi_types: + assert isinstance(op, CffiOp) + self.cffi_types = tuple(self.cffi_types) # don't change any more + + def _enum_fields(self, tp): + # When producing C, expand all anonymous struct/union fields. + # That's necessary to have C code checking the offsets of the + # individual fields contained in them. When producing Python, + # don't do it and instead write it like it is, with the + # corresponding fields having an empty name. Empty names are + # recognized at runtime when we import the generated Python + # file. + expand_anonymous_struct_union = not self.target_is_python + return tp.enumfields(expand_anonymous_struct_union) + + def _do_collect_type(self, tp): + if not isinstance(tp, model.BaseTypeByIdentity): + if isinstance(tp, tuple): + for x in tp: + self._do_collect_type(x) + return + if tp not in self._typesdict: + self._typesdict[tp] = None + if isinstance(tp, model.FunctionPtrType): + self._do_collect_type(tp.as_raw_function()) + elif isinstance(tp, model.StructOrUnion): + if tp.fldtypes is not None and ( + tp not in self.ffi._parser._included_declarations): + for name1, tp1, _, _ in self._enum_fields(tp): + self._do_collect_type(self._field_type(tp, name1, tp1)) + else: + for _, x in tp._get_items(): + self._do_collect_type(x) + + def _generate(self, step_name): + lst = self.ffi._parser._declarations.items() + for name, (tp, quals) in sorted(lst): + kind, realname = name.split(' ', 1) + try: + method = getattr(self, '_generate_cpy_%s_%s' % (kind, + step_name)) + except AttributeError: + raise VerificationError( + "not implemented in recompile(): %r" % name) + try: + self._current_quals = quals + method(tp, realname) + except Exception as e: + model.attach_exception_info(e, name) + raise + + # ---------- + + ALL_STEPS = ["global", "field", "struct_union", "enum", "typename"] + + def collect_step_tables(self): + # collect the declarations for '_cffi_globals', '_cffi_typenames', etc. + self._lsts = {} + for step_name in self.ALL_STEPS: + self._lsts[step_name] = [] + self._seen_struct_unions = set() + self._generate("ctx") + self._add_missing_struct_unions() + # + for step_name in self.ALL_STEPS: + lst = self._lsts[step_name] + if step_name != "field": + lst.sort(key=lambda entry: entry.name) + self._lsts[step_name] = tuple(lst) # don't change any more + # + # check for a possible internal inconsistency: _cffi_struct_unions + # should have been generated with exactly self._struct_unions + lst = self._lsts["struct_union"] + for tp, i in self._struct_unions.items(): + assert i < len(lst) + assert lst[i].name == tp.name + assert len(lst) == len(self._struct_unions) + # same with enums + lst = self._lsts["enum"] + for tp, i in self._enums.items(): + assert i < len(lst) + assert lst[i].name == tp.name + assert len(lst) == len(self._enums) + + # ---------- + + def _prnt(self, what=''): + self._f.write(what + '\n') + + def write_source_to_f(self, f, preamble): + if self.target_is_python: + assert preamble is None + self.write_py_source_to_f(f) + else: + assert preamble is not None + self.write_c_source_to_f(f, preamble) + + def _rel_readlines(self, filename): + g = open(os.path.join(os.path.dirname(__file__), filename), 'r') + lines = g.readlines() + g.close() + return lines + + def write_c_source_to_f(self, f, preamble): + self._f = f + prnt = self._prnt + if self.ffi._embedding is not None: + prnt('#define _CFFI_USE_EMBEDDING') + if not USE_LIMITED_API: + prnt('#define _CFFI_NO_LIMITED_API') + # + # first the '#include' (actually done by inlining the file's content) + lines = self._rel_readlines('_cffi_include.h') + i = lines.index('#include "parse_c_type.h"\n') + lines[i:i+1] = self._rel_readlines('parse_c_type.h') + prnt(''.join(lines)) + # + # if we have ffi._embedding != None, we give it here as a macro + # and include an extra file + base_module_name = self.module_name.split('.')[-1] + if self.ffi._embedding is not None: + prnt('#define _CFFI_MODULE_NAME "%s"' % (self.module_name,)) + prnt('static const char _CFFI_PYTHON_STARTUP_CODE[] = {') + self._print_string_literal_in_array(self.ffi._embedding) + prnt('0 };') + prnt('#ifdef PYPY_VERSION') + prnt('# define _CFFI_PYTHON_STARTUP_FUNC _cffi_pypyinit_%s' % ( + base_module_name,)) + prnt('#elif PY_MAJOR_VERSION >= 3') + prnt('# define _CFFI_PYTHON_STARTUP_FUNC PyInit_%s' % ( + base_module_name,)) + prnt('#else') + prnt('# define _CFFI_PYTHON_STARTUP_FUNC init%s' % ( + base_module_name,)) + prnt('#endif') + lines = self._rel_readlines('_embedding.h') + i = lines.index('#include "_cffi_errors.h"\n') + lines[i:i+1] = self._rel_readlines('_cffi_errors.h') + prnt(''.join(lines)) + self.needs_version(VERSION_EMBEDDED) + # + # then paste the C source given by the user, verbatim. + prnt('/************************************************************/') + prnt() + prnt(preamble) + prnt() + prnt('/************************************************************/') + prnt() + # + # the declaration of '_cffi_types' + prnt('static void *_cffi_types[] = {') + typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) + for i, op in enumerate(self.cffi_types): + comment = '' + if i in typeindex2type: + comment = ' // ' + typeindex2type[i]._get_c_name() + prnt('/* %2d */ %s,%s' % (i, op.as_c_expr(), comment)) + if not self.cffi_types: + prnt(' 0') + prnt('};') + prnt() + # + # call generate_cpy_xxx_decl(), for every xxx found from + # ffi._parser._declarations. This generates all the functions. + self._seen_constants = set() + self._generate("decl") + # + # the declaration of '_cffi_globals' and '_cffi_typenames' + nums = {} + for step_name in self.ALL_STEPS: + lst = self._lsts[step_name] + nums[step_name] = len(lst) + if nums[step_name] > 0: + prnt('static const struct _cffi_%s_s _cffi_%ss[] = {' % ( + step_name, step_name)) + for entry in lst: + prnt(entry.as_c_expr()) + prnt('};') + prnt() + # + # the declaration of '_cffi_includes' + if self.ffi._included_ffis: + prnt('static const char * const _cffi_includes[] = {') + for ffi_to_include in self.ffi._included_ffis: + try: + included_module_name, included_source = ( + ffi_to_include._assigned_source[:2]) + except AttributeError: + raise VerificationError( + "ffi object %r includes %r, but the latter has not " + "been prepared with set_source()" % ( + self.ffi, ffi_to_include,)) + if included_source is None: + raise VerificationError( + "not implemented yet: ffi.include() of a Python-based " + "ffi inside a C-based ffi") + prnt(' "%s",' % (included_module_name,)) + prnt(' NULL') + prnt('};') + prnt() + # + # the declaration of '_cffi_type_context' + prnt('static const struct _cffi_type_context_s _cffi_type_context = {') + prnt(' _cffi_types,') + for step_name in self.ALL_STEPS: + if nums[step_name] > 0: + prnt(' _cffi_%ss,' % step_name) + else: + prnt(' NULL, /* no %ss */' % step_name) + for step_name in self.ALL_STEPS: + if step_name != "field": + prnt(' %d, /* num_%ss */' % (nums[step_name], step_name)) + if self.ffi._included_ffis: + prnt(' _cffi_includes,') + else: + prnt(' NULL, /* no includes */') + prnt(' %d, /* num_types */' % (len(self.cffi_types),)) + flags = 0 + if self._num_externpy > 0 or self.ffi._embedding is not None: + flags |= 1 # set to mean that we use extern "Python" + prnt(' %d, /* flags */' % flags) + prnt('};') + prnt() + # + # the init function + prnt('#ifdef __GNUC__') + prnt('# pragma GCC visibility push(default) /* for -fvisibility= */') + prnt('#endif') + prnt() + prnt('#ifdef PYPY_VERSION') + prnt('PyMODINIT_FUNC') + prnt('_cffi_pypyinit_%s(const void *p[])' % (base_module_name,)) + prnt('{') + if flags & 1: + prnt(' if (((intptr_t)p[0]) >= 0x0A03) {') + prnt(' _cffi_call_python_org = ' + '(void(*)(struct _cffi_externpy_s *, char *))p[1];') + prnt(' }') + prnt(' p[0] = (const void *)0x%x;' % self._version) + prnt(' p[1] = &_cffi_type_context;') + prnt('#if PY_MAJOR_VERSION >= 3') + prnt(' return NULL;') + prnt('#endif') + prnt('}') + # on Windows, distutils insists on putting init_cffi_xyz in + # 'export_symbols', so instead of fighting it, just give up and + # give it one + prnt('# ifdef _MSC_VER') + prnt(' PyMODINIT_FUNC') + prnt('# if PY_MAJOR_VERSION >= 3') + prnt(' PyInit_%s(void) { return NULL; }' % (base_module_name,)) + prnt('# else') + prnt(' init%s(void) { }' % (base_module_name,)) + prnt('# endif') + prnt('# endif') + prnt('#elif PY_MAJOR_VERSION >= 3') + prnt('PyMODINIT_FUNC') + prnt('PyInit_%s(void)' % (base_module_name,)) + prnt('{') + prnt(' return _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( + self.module_name, self._version)) + prnt('}') + prnt('#else') + prnt('PyMODINIT_FUNC') + prnt('init%s(void)' % (base_module_name,)) + prnt('{') + prnt(' _cffi_init("%s", 0x%x, &_cffi_type_context);' % ( + self.module_name, self._version)) + prnt('}') + prnt('#endif') + prnt() + prnt('#ifdef __GNUC__') + prnt('# pragma GCC visibility pop') + prnt('#endif') + self._version = None + + def _to_py(self, x): + if isinstance(x, str): + return "b'%s'" % (x,) + if isinstance(x, (list, tuple)): + rep = [self._to_py(item) for item in x] + if len(rep) == 1: + rep.append('') + return "(%s)" % (','.join(rep),) + return x.as_python_expr() # Py2: unicode unexpected; Py3: bytes unexp. + + def write_py_source_to_f(self, f): + self._f = f + prnt = self._prnt + # + # header + prnt("# auto-generated file") + prnt("import _cffi_backend") + # + # the 'import' of the included ffis + num_includes = len(self.ffi._included_ffis or ()) + for i in range(num_includes): + ffi_to_include = self.ffi._included_ffis[i] + try: + included_module_name, included_source = ( + ffi_to_include._assigned_source[:2]) + except AttributeError: + raise VerificationError( + "ffi object %r includes %r, but the latter has not " + "been prepared with set_source()" % ( + self.ffi, ffi_to_include,)) + if included_source is not None: + raise VerificationError( + "not implemented yet: ffi.include() of a C-based " + "ffi inside a Python-based ffi") + prnt('from %s import ffi as _ffi%d' % (included_module_name, i)) + prnt() + prnt("ffi = _cffi_backend.FFI('%s'," % (self.module_name,)) + prnt(" _version = 0x%x," % (self._version,)) + self._version = None + # + # the '_types' keyword argument + self.cffi_types = tuple(self.cffi_types) # don't change any more + types_lst = [op.as_python_bytes() for op in self.cffi_types] + prnt(' _types = %s,' % (self._to_py(''.join(types_lst)),)) + typeindex2type = dict([(i, tp) for (tp, i) in self._typesdict.items()]) + # + # the keyword arguments from ALL_STEPS + for step_name in self.ALL_STEPS: + lst = self._lsts[step_name] + if len(lst) > 0 and step_name != "field": + prnt(' _%ss = %s,' % (step_name, self._to_py(lst))) + # + # the '_includes' keyword argument + if num_includes > 0: + prnt(' _includes = (%s,),' % ( + ', '.join(['_ffi%d' % i for i in range(num_includes)]),)) + # + # the footer + prnt(')') + + # ---------- + + def _gettypenum(self, type): + # a KeyError here is a bug. please report it! :-) + return self._typesdict[type] + + def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): + extraarg = '' + if isinstance(tp, model.BasePrimitiveType) and not tp.is_complex_type(): + if tp.is_integer_type() and tp.name != '_Bool': + converter = '_cffi_to_c_int' + extraarg = ', %s' % tp.name + elif isinstance(tp, model.UnknownFloatType): + # don't check with is_float_type(): it may be a 'long + # double' here, and _cffi_to_c_double would loose precision + converter = '(%s)_cffi_to_c_double' % (tp.get_c_name(''),) + else: + cname = tp.get_c_name('') + converter = '(%s)_cffi_to_c_%s' % (cname, + tp.name.replace(' ', '_')) + if cname in ('char16_t', 'char32_t'): + self.needs_version(VERSION_CHAR16CHAR32) + errvalue = '-1' + # + elif isinstance(tp, model.PointerType): + self._convert_funcarg_to_c_ptr_or_array(tp, fromvar, + tovar, errcode) + return + # + elif (isinstance(tp, model.StructOrUnionOrEnum) or + isinstance(tp, model.BasePrimitiveType)): + # a struct (not a struct pointer) as a function argument; + # or, a complex (the same code works) + self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' + % (tovar, self._gettypenum(tp), fromvar)) + self._prnt(' %s;' % errcode) + return + # + elif isinstance(tp, model.FunctionPtrType): + converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') + extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) + errvalue = 'NULL' + # + else: + raise NotImplementedError(tp) + # + self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg)) + self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % ( + tovar, tp.get_c_name(''), errvalue)) + self._prnt(' %s;' % errcode) + + def _extra_local_variables(self, tp, localvars, freelines): + if isinstance(tp, model.PointerType): + localvars.add('Py_ssize_t datasize') + localvars.add('struct _cffi_freeme_s *large_args_free = NULL') + freelines.add('if (large_args_free != NULL)' + ' _cffi_free_array_arguments(large_args_free);') + + def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode): + self._prnt(' datasize = _cffi_prepare_pointer_call_argument(') + self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % ( + self._gettypenum(tp), fromvar, tovar)) + self._prnt(' if (datasize != 0) {') + self._prnt(' %s = ((size_t)datasize) <= 640 ? ' + '(%s)alloca((size_t)datasize) : NULL;' % ( + tovar, tp.get_c_name(''))) + self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, ' + '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar)) + self._prnt(' datasize, &large_args_free) < 0)') + self._prnt(' %s;' % errcode) + self._prnt(' }') + + def _convert_expr_from_c(self, tp, var, context): + if isinstance(tp, model.BasePrimitiveType): + if tp.is_integer_type() and tp.name != '_Bool': + return '_cffi_from_c_int(%s, %s)' % (var, tp.name) + elif isinstance(tp, model.UnknownFloatType): + return '_cffi_from_c_double(%s)' % (var,) + elif tp.name != 'long double' and not tp.is_complex_type(): + cname = tp.name.replace(' ', '_') + if cname in ('char16_t', 'char32_t'): + self.needs_version(VERSION_CHAR16CHAR32) + return '_cffi_from_c_%s(%s)' % (cname, var) + else: + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, (model.PointerType, model.FunctionPtrType)): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.ArrayType): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(model.PointerType(tp.item))) + elif isinstance(tp, model.StructOrUnion): + if tp.fldnames is None: + raise TypeError("'%s' is used as %s, but is opaque" % ( + tp._get_c_name(), context)) + return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.EnumType): + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + else: + raise NotImplementedError(tp) + + # ---------- + # typedefs + + def _typedef_type(self, tp, name): + return self._global_type(tp, "(*(%s *)0)" % (name,)) + + def _generate_cpy_typedef_collecttype(self, tp, name): + self._do_collect_type(self._typedef_type(tp, name)) + + def _generate_cpy_typedef_decl(self, tp, name): + pass + + def _typedef_ctx(self, tp, name): + type_index = self._typesdict[tp] + self._lsts["typename"].append(TypenameExpr(name, type_index)) + + def _generate_cpy_typedef_ctx(self, tp, name): + tp = self._typedef_type(tp, name) + self._typedef_ctx(tp, name) + if getattr(tp, "origin", None) == "unknown_type": + self._struct_ctx(tp, tp.name, approxname=None) + elif isinstance(tp, model.NamedPointerType): + self._struct_ctx(tp.totype, tp.totype.name, approxname=tp.name, + named_ptr=tp) + + # ---------- + # function declarations + + def _generate_cpy_function_collecttype(self, tp, name): + self._do_collect_type(tp.as_raw_function()) + if tp.ellipsis and not self.target_is_python: + self._do_collect_type(tp) + + def _generate_cpy_function_decl(self, tp, name): + assert not self.target_is_python + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + # cannot support vararg functions better than this: check for its + # exact type (including the fixed arguments), and build it as a + # constant function pointer (no CPython wrapper) + self._generate_cpy_constant_decl(tp, name) + return + prnt = self._prnt + numargs = len(tp.args) + if numargs == 0: + argname = 'noarg' + elif numargs == 1: + argname = 'arg0' + else: + argname = 'args' + # + # ------------------------------ + # the 'd' version of the function, only for addressof(lib, 'func') + arguments = [] + call_arguments = [] + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + arguments.append(type.get_c_name(' x%d' % i, context)) + call_arguments.append('x%d' % i) + repr_arguments = ', '.join(arguments) + repr_arguments = repr_arguments or 'void' + if tp.abi: + abi = tp.abi + ' ' + else: + abi = '' + name_and_arguments = '%s_cffi_d_%s(%s)' % (abi, name, repr_arguments) + prnt('static %s' % (tp.result.get_c_name(name_and_arguments),)) + prnt('{') + call_arguments = ', '.join(call_arguments) + result_code = 'return ' + if isinstance(tp.result, model.VoidType): + result_code = '' + prnt(' %s%s(%s);' % (result_code, name, call_arguments)) + prnt('}') + # + prnt('#ifndef PYPY_VERSION') # ------------------------------ + # + prnt('static PyObject *') + prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname)) + prnt('{') + # + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + arg = type.get_c_name(' x%d' % i, context) + prnt(' %s;' % arg) + # + localvars = set() + freelines = set() + for type in tp.args: + self._extra_local_variables(type, localvars, freelines) + for decl in sorted(localvars): + prnt(' %s;' % (decl,)) + # + if not isinstance(tp.result, model.VoidType): + result_code = 'result = ' + context = 'result of %s' % name + result_decl = ' %s;' % tp.result.get_c_name(' result', context) + prnt(result_decl) + prnt(' PyObject *pyresult;') + else: + result_decl = None + result_code = '' + # + if len(tp.args) > 1: + rng = range(len(tp.args)) + for i in rng: + prnt(' PyObject *arg%d;' % i) + prnt() + prnt(' if (!PyArg_UnpackTuple(args, "%s", %d, %d, %s))' % ( + name, len(rng), len(rng), + ', '.join(['&arg%d' % i for i in rng]))) + prnt(' return NULL;') + prnt() + # + for i, type in enumerate(tp.args): + self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i, + 'return NULL') + prnt() + # + prnt(' Py_BEGIN_ALLOW_THREADS') + prnt(' _cffi_restore_errno();') + call_arguments = ['x%d' % i for i in range(len(tp.args))] + call_arguments = ', '.join(call_arguments) + prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) + prnt(' _cffi_save_errno();') + prnt(' Py_END_ALLOW_THREADS') + prnt() + # + prnt(' (void)self; /* unused */') + if numargs == 0: + prnt(' (void)noarg; /* unused */') + if result_code: + prnt(' pyresult = %s;' % + self._convert_expr_from_c(tp.result, 'result', 'result type')) + for freeline in freelines: + prnt(' ' + freeline) + prnt(' return pyresult;') + else: + for freeline in freelines: + prnt(' ' + freeline) + prnt(' Py_INCREF(Py_None);') + prnt(' return Py_None;') + prnt('}') + # + prnt('#else') # ------------------------------ + # + # the PyPy version: need to replace struct/union arguments with + # pointers, and if the result is a struct/union, insert a first + # arg that is a pointer to the result. We also do that for + # complex args and return type. + def need_indirection(type): + return (isinstance(type, model.StructOrUnion) or + (isinstance(type, model.PrimitiveType) and + type.is_complex_type())) + difference = False + arguments = [] + call_arguments = [] + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + indirection = '' + if need_indirection(type): + indirection = '*' + difference = True + arg = type.get_c_name(' %sx%d' % (indirection, i), context) + arguments.append(arg) + call_arguments.append('%sx%d' % (indirection, i)) + tp_result = tp.result + if need_indirection(tp_result): + context = 'result of %s' % name + arg = tp_result.get_c_name(' *result', context) + arguments.insert(0, arg) + tp_result = model.void_type + result_decl = None + result_code = '*result = ' + difference = True + if difference: + repr_arguments = ', '.join(arguments) + repr_arguments = repr_arguments or 'void' + name_and_arguments = '%s_cffi_f_%s(%s)' % (abi, name, + repr_arguments) + prnt('static %s' % (tp_result.get_c_name(name_and_arguments),)) + prnt('{') + if result_decl: + prnt(result_decl) + call_arguments = ', '.join(call_arguments) + prnt(' { %s%s(%s); }' % (result_code, name, call_arguments)) + if result_decl: + prnt(' return result;') + prnt('}') + else: + prnt('# define _cffi_f_%s _cffi_d_%s' % (name, name)) + # + prnt('#endif') # ------------------------------ + prnt() + + def _generate_cpy_function_ctx(self, tp, name): + if tp.ellipsis and not self.target_is_python: + self._generate_cpy_constant_ctx(tp, name) + return + type_index = self._typesdict[tp.as_raw_function()] + numargs = len(tp.args) + if self.target_is_python: + meth_kind = OP_DLOPEN_FUNC + elif numargs == 0: + meth_kind = OP_CPYTHON_BLTN_N # 'METH_NOARGS' + elif numargs == 1: + meth_kind = OP_CPYTHON_BLTN_O # 'METH_O' + else: + meth_kind = OP_CPYTHON_BLTN_V # 'METH_VARARGS' + self._lsts["global"].append( + GlobalExpr(name, '_cffi_f_%s' % name, + CffiOp(meth_kind, type_index), + size='_cffi_d_%s' % name)) + + # ---------- + # named structs or unions + + def _field_type(self, tp_struct, field_name, tp_field): + if isinstance(tp_field, model.ArrayType): + actual_length = tp_field.length + if actual_length == '...': + ptr_struct_name = tp_struct.get_c_name('*') + actual_length = '_cffi_array_len(((%s)0)->%s)' % ( + ptr_struct_name, field_name) + tp_item = self._field_type(tp_struct, '%s[0]' % field_name, + tp_field.item) + tp_field = model.ArrayType(tp_item, actual_length) + return tp_field + + def _struct_collecttype(self, tp): + self._do_collect_type(tp) + if self.target_is_python: + # also requires nested anon struct/unions in ABI mode, recursively + for fldtype in tp.anonymous_struct_fields(): + self._struct_collecttype(fldtype) + + def _struct_decl(self, tp, cname, approxname): + if tp.fldtypes is None: + return + prnt = self._prnt + checkfuncname = '_cffi_checkfld_%s' % (approxname,) + prnt('_CFFI_UNUSED_FN') + prnt('static void %s(%s *p)' % (checkfuncname, cname)) + prnt('{') + prnt(' /* only to generate compile-time warnings or errors */') + prnt(' (void)p;') + for fname, ftype, fbitsize, fqual in self._enum_fields(tp): + try: + if ftype.is_integer_type() or fbitsize >= 0: + # accept all integers, but complain on float or double + if fname != '': + prnt(" (void)((p->%s) | 0); /* check that '%s.%s' is " + "an integer */" % (fname, cname, fname)) + continue + # only accept exactly the type declared, except that '[]' + # is interpreted as a '*' and so will match any array length. + # (It would also match '*', but that's harder to detect...) + while (isinstance(ftype, model.ArrayType) + and (ftype.length is None or ftype.length == '...')): + ftype = ftype.item + fname = fname + '[0]' + prnt(' { %s = &p->%s; (void)tmp; }' % ( + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) + except VerificationError as e: + prnt(' /* %s */' % str(e)) # cannot verify it, ignore + prnt('}') + prnt('struct _cffi_align_%s { char x; %s y; };' % (approxname, cname)) + prnt() + + def _struct_ctx(self, tp, cname, approxname, named_ptr=None): + type_index = self._typesdict[tp] + reason_for_not_expanding = None + flags = [] + if isinstance(tp, model.UnionType): + flags.append("_CFFI_F_UNION") + if tp.fldtypes is None: + flags.append("_CFFI_F_OPAQUE") + reason_for_not_expanding = "opaque" + if (tp not in self.ffi._parser._included_declarations and + (named_ptr is None or + named_ptr not in self.ffi._parser._included_declarations)): + if tp.fldtypes is None: + pass # opaque + elif tp.partial or any(tp.anonymous_struct_fields()): + pass # field layout obtained silently from the C compiler + else: + flags.append("_CFFI_F_CHECK_FIELDS") + if tp.packed: + if tp.packed > 1: + raise NotImplementedError( + "%r is declared with 'pack=%r'; only 0 or 1 are " + "supported in API mode (try to use \"...;\", which " + "does not require a 'pack' declaration)" % + (tp, tp.packed)) + flags.append("_CFFI_F_PACKED") + else: + flags.append("_CFFI_F_EXTERNAL") + reason_for_not_expanding = "external" + flags = '|'.join(flags) or '0' + c_fields = [] + if reason_for_not_expanding is None: + enumfields = list(self._enum_fields(tp)) + for fldname, fldtype, fbitsize, fqual in enumfields: + fldtype = self._field_type(tp, fldname, fldtype) + self._check_not_opaque(fldtype, + "field '%s.%s'" % (tp.name, fldname)) + # cname is None for _add_missing_struct_unions() only + op = OP_NOOP + if fbitsize >= 0: + op = OP_BITFIELD + size = '%d /* bits */' % fbitsize + elif cname is None or ( + isinstance(fldtype, model.ArrayType) and + fldtype.length is None): + size = '(size_t)-1' + else: + size = 'sizeof(((%s)0)->%s)' % ( + tp.get_c_name('*') if named_ptr is None + else named_ptr.name, + fldname) + if cname is None or fbitsize >= 0: + offset = '(size_t)-1' + elif named_ptr is not None: + offset = '((char *)&((%s)0)->%s) - (char *)0' % ( + named_ptr.name, fldname) + else: + offset = 'offsetof(%s, %s)' % (tp.get_c_name(''), fldname) + c_fields.append( + FieldExpr(fldname, offset, size, fbitsize, + CffiOp(op, self._typesdict[fldtype]))) + first_field_index = len(self._lsts["field"]) + self._lsts["field"].extend(c_fields) + # + if cname is None: # unknown name, for _add_missing_struct_unions + size = '(size_t)-2' + align = -2 + comment = "unnamed" + else: + if named_ptr is not None: + size = 'sizeof(*(%s)0)' % (named_ptr.name,) + align = '-1 /* unknown alignment */' + else: + size = 'sizeof(%s)' % (cname,) + align = 'offsetof(struct _cffi_align_%s, y)' % (approxname,) + comment = None + else: + size = '(size_t)-1' + align = -1 + first_field_index = -1 + comment = reason_for_not_expanding + self._lsts["struct_union"].append( + StructUnionExpr(tp.name, type_index, flags, size, align, comment, + first_field_index, c_fields)) + self._seen_struct_unions.add(tp) + + def _check_not_opaque(self, tp, location): + while isinstance(tp, model.ArrayType): + tp = tp.item + if isinstance(tp, model.StructOrUnion) and tp.fldtypes is None: + raise TypeError( + "%s is of an opaque type (not declared in cdef())" % location) + + def _add_missing_struct_unions(self): + # not very nice, but some struct declarations might be missing + # because they don't have any known C name. Check that they are + # not partial (we can't complete or verify them!) and emit them + # anonymously. + lst = list(self._struct_unions.items()) + lst.sort(key=lambda tp_order: tp_order[1]) + for tp, order in lst: + if tp not in self._seen_struct_unions: + if tp.partial: + raise NotImplementedError("internal inconsistency: %r is " + "partial but was not seen at " + "this point" % (tp,)) + if tp.name.startswith('$') and tp.name[1:].isdigit(): + approxname = tp.name[1:] + elif tp.name == '_IO_FILE' and tp.forcename == 'FILE': + approxname = 'FILE' + self._typedef_ctx(tp, 'FILE') + else: + raise NotImplementedError("internal inconsistency: %r" % + (tp,)) + self._struct_ctx(tp, None, approxname) + + def _generate_cpy_struct_collecttype(self, tp, name): + self._struct_collecttype(tp) + _generate_cpy_union_collecttype = _generate_cpy_struct_collecttype + + def _struct_names(self, tp): + cname = tp.get_c_name('') + if ' ' in cname: + return cname, cname.replace(' ', '_') + else: + return cname, '_' + cname + + def _generate_cpy_struct_decl(self, tp, name): + self._struct_decl(tp, *self._struct_names(tp)) + _generate_cpy_union_decl = _generate_cpy_struct_decl + + def _generate_cpy_struct_ctx(self, tp, name): + self._struct_ctx(tp, *self._struct_names(tp)) + _generate_cpy_union_ctx = _generate_cpy_struct_ctx + + # ---------- + # 'anonymous' declarations. These are produced for anonymous structs + # or unions; the 'name' is obtained by a typedef. + + def _generate_cpy_anonymous_collecttype(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_cpy_enum_collecttype(tp, name) + else: + self._struct_collecttype(tp) + + def _generate_cpy_anonymous_decl(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_cpy_enum_decl(tp) + else: + self._struct_decl(tp, name, 'typedef_' + name) + + def _generate_cpy_anonymous_ctx(self, tp, name): + if isinstance(tp, model.EnumType): + self._enum_ctx(tp, name) + else: + self._struct_ctx(tp, name, 'typedef_' + name) + + # ---------- + # constants, declared with "static const ..." + + def _generate_cpy_const(self, is_int, name, tp=None, category='const', + check_value=None): + if (category, name) in self._seen_constants: + raise VerificationError( + "duplicate declaration of %s '%s'" % (category, name)) + self._seen_constants.add((category, name)) + # + prnt = self._prnt + funcname = '_cffi_%s_%s' % (category, name) + if is_int: + prnt('static int %s(unsigned long long *o)' % funcname) + prnt('{') + prnt(' int n = (%s) <= 0;' % (name,)) + prnt(' *o = (unsigned long long)((%s) | 0);' + ' /* check that %s is an integer */' % (name, name)) + if check_value is not None: + if check_value > 0: + check_value = '%dU' % (check_value,) + prnt(' if (!_cffi_check_int(*o, n, %s))' % (check_value,)) + prnt(' n |= 2;') + prnt(' return n;') + prnt('}') + else: + assert check_value is None + prnt('static void %s(char *o)' % funcname) + prnt('{') + prnt(' *(%s)o = %s;' % (tp.get_c_name('*'), name)) + prnt('}') + prnt() + + def _generate_cpy_constant_collecttype(self, tp, name): + is_int = tp.is_integer_type() + if not is_int or self.target_is_python: + self._do_collect_type(tp) + + def _generate_cpy_constant_decl(self, tp, name): + is_int = tp.is_integer_type() + self._generate_cpy_const(is_int, name, tp) + + def _generate_cpy_constant_ctx(self, tp, name): + if not self.target_is_python and tp.is_integer_type(): + type_op = CffiOp(OP_CONSTANT_INT, -1) + else: + if self.target_is_python: + const_kind = OP_DLOPEN_CONST + else: + const_kind = OP_CONSTANT + type_index = self._typesdict[tp] + type_op = CffiOp(const_kind, type_index) + self._lsts["global"].append( + GlobalExpr(name, '_cffi_const_%s' % name, type_op)) + + # ---------- + # enums + + def _generate_cpy_enum_collecttype(self, tp, name): + self._do_collect_type(tp) + + def _generate_cpy_enum_decl(self, tp, name=None): + for enumerator in tp.enumerators: + self._generate_cpy_const(True, enumerator) + + def _enum_ctx(self, tp, cname): + type_index = self._typesdict[tp] + type_op = CffiOp(OP_ENUM, -1) + if self.target_is_python: + tp.check_not_partial() + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + self._lsts["global"].append( + GlobalExpr(enumerator, '_cffi_const_%s' % enumerator, type_op, + check_value=enumvalue)) + # + if cname is not None and '$' not in cname and not self.target_is_python: + size = "sizeof(%s)" % cname + signed = "((%s)-1) <= 0" % cname + else: + basetp = tp.build_baseinttype(self.ffi, []) + size = self.ffi.sizeof(basetp) + signed = int(int(self.ffi.cast(basetp, -1)) < 0) + allenums = ",".join(tp.enumerators) + self._lsts["enum"].append( + EnumExpr(tp.name, type_index, size, signed, allenums)) + + def _generate_cpy_enum_ctx(self, tp, name): + self._enum_ctx(tp, tp._get_c_name()) + + # ---------- + # macros: for now only for integers + + def _generate_cpy_macro_collecttype(self, tp, name): + pass + + def _generate_cpy_macro_decl(self, tp, name): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + self._generate_cpy_const(True, name, check_value=check_value) + + def _generate_cpy_macro_ctx(self, tp, name): + if tp == '...': + if self.target_is_python: + raise VerificationError( + "cannot use the syntax '...' in '#define %s ...' when " + "using the ABI mode" % (name,)) + check_value = None + else: + check_value = tp # an integer + type_op = CffiOp(OP_CONSTANT_INT, -1) + self._lsts["global"].append( + GlobalExpr(name, '_cffi_const_%s' % name, type_op, + check_value=check_value)) + + # ---------- + # global variables + + def _global_type(self, tp, global_name): + if isinstance(tp, model.ArrayType): + actual_length = tp.length + if actual_length == '...': + actual_length = '_cffi_array_len(%s)' % (global_name,) + tp_item = self._global_type(tp.item, '%s[0]' % global_name) + tp = model.ArrayType(tp_item, actual_length) + return tp + + def _generate_cpy_variable_collecttype(self, tp, name): + self._do_collect_type(self._global_type(tp, name)) + + def _generate_cpy_variable_decl(self, tp, name): + prnt = self._prnt + tp = self._global_type(tp, name) + if isinstance(tp, model.ArrayType) and tp.length is None: + tp = tp.item + ampersand = '' + else: + ampersand = '&' + # This code assumes that casts from "tp *" to "void *" is a + # no-op, i.e. a function that returns a "tp *" can be called + # as if it returned a "void *". This should be generally true + # on any modern machine. The only exception to that rule (on + # uncommon architectures, and as far as I can tell) might be + # if 'tp' were a function type, but that is not possible here. + # (If 'tp' is a function _pointer_ type, then casts from "fn_t + # **" to "void *" are again no-ops, as far as I can tell.) + decl = '*_cffi_var_%s(void)' % (name,) + prnt('static ' + tp.get_c_name(decl, quals=self._current_quals)) + prnt('{') + prnt(' return %s(%s);' % (ampersand, name)) + prnt('}') + prnt() + + def _generate_cpy_variable_ctx(self, tp, name): + tp = self._global_type(tp, name) + type_index = self._typesdict[tp] + if self.target_is_python: + op = OP_GLOBAL_VAR + else: + op = OP_GLOBAL_VAR_F + self._lsts["global"].append( + GlobalExpr(name, '_cffi_var_%s' % name, CffiOp(op, type_index))) + + # ---------- + # extern "Python" + + def _generate_cpy_extern_python_collecttype(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + self._do_collect_type(tp) + _generate_cpy_dllexport_python_collecttype = \ + _generate_cpy_extern_python_plus_c_collecttype = \ + _generate_cpy_extern_python_collecttype + + def _extern_python_decl(self, tp, name, tag_and_space): + prnt = self._prnt + if isinstance(tp.result, model.VoidType): + size_of_result = '0' + else: + context = 'result of %s' % name + size_of_result = '(int)sizeof(%s)' % ( + tp.result.get_c_name('', context),) + prnt('static struct _cffi_externpy_s _cffi_externpy__%s =' % name) + prnt(' { "%s.%s", %s, 0, 0 };' % ( + self.module_name, name, size_of_result)) + prnt() + # + arguments = [] + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + arg = type.get_c_name(' a%d' % i, context) + arguments.append(arg) + # + repr_arguments = ', '.join(arguments) + repr_arguments = repr_arguments or 'void' + name_and_arguments = '%s(%s)' % (name, repr_arguments) + if tp.abi == "__stdcall": + name_and_arguments = '_cffi_stdcall ' + name_and_arguments + # + def may_need_128_bits(tp): + return (isinstance(tp, model.PrimitiveType) and + tp.name == 'long double') + # + size_of_a = max(len(tp.args)*8, 8) + if may_need_128_bits(tp.result): + size_of_a = max(size_of_a, 16) + if isinstance(tp.result, model.StructOrUnion): + size_of_a = 'sizeof(%s) > %d ? sizeof(%s) : %d' % ( + tp.result.get_c_name(''), size_of_a, + tp.result.get_c_name(''), size_of_a) + prnt('%s%s' % (tag_and_space, tp.result.get_c_name(name_and_arguments))) + prnt('{') + prnt(' char a[%s];' % size_of_a) + prnt(' char *p = a;') + for i, type in enumerate(tp.args): + arg = 'a%d' % i + if (isinstance(type, model.StructOrUnion) or + may_need_128_bits(type)): + arg = '&' + arg + type = model.PointerType(type) + prnt(' *(%s)(p + %d) = %s;' % (type.get_c_name('*'), i*8, arg)) + prnt(' _cffi_call_python(&_cffi_externpy__%s, p);' % name) + if not isinstance(tp.result, model.VoidType): + prnt(' return *(%s)p;' % (tp.result.get_c_name('*'),)) + prnt('}') + prnt() + self._num_externpy += 1 + + def _generate_cpy_extern_python_decl(self, tp, name): + self._extern_python_decl(tp, name, 'static ') + + def _generate_cpy_dllexport_python_decl(self, tp, name): + self._extern_python_decl(tp, name, 'CFFI_DLLEXPORT ') + + def _generate_cpy_extern_python_plus_c_decl(self, tp, name): + self._extern_python_decl(tp, name, '') + + def _generate_cpy_extern_python_ctx(self, tp, name): + if self.target_is_python: + raise VerificationError( + "cannot use 'extern \"Python\"' in the ABI mode") + if tp.ellipsis: + raise NotImplementedError("a vararg function is extern \"Python\"") + type_index = self._typesdict[tp] + type_op = CffiOp(OP_EXTERN_PYTHON, type_index) + self._lsts["global"].append( + GlobalExpr(name, '&_cffi_externpy__%s' % name, type_op, name)) + + _generate_cpy_dllexport_python_ctx = \ + _generate_cpy_extern_python_plus_c_ctx = \ + _generate_cpy_extern_python_ctx + + def _print_string_literal_in_array(self, s): + prnt = self._prnt + prnt('// # NB. this is not a string because of a size limit in MSVC') + if not isinstance(s, bytes): # unicode + s = s.encode('utf-8') # -> bytes + else: + s.decode('utf-8') # got bytes, check for valid utf-8 + try: + s.decode('ascii') + except UnicodeDecodeError: + s = b'# -*- encoding: utf8 -*-\n' + s + for line in s.splitlines(True): + comment = line + if type('//') is bytes: # python2 + line = map(ord, line) # make a list of integers + else: # python3 + # type(line) is bytes, which enumerates like a list of integers + comment = ascii(comment)[1:-1] + prnt(('// ' + comment).rstrip()) + printed_line = '' + for c in line: + if len(printed_line) >= 76: + prnt(printed_line) + printed_line = '' + printed_line += '%d,' % (c,) + prnt(printed_line) + + # ---------- + # emitting the opcodes for individual types + + def _emit_bytecode_VoidType(self, tp, index): + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, PRIM_VOID) + + def _emit_bytecode_PrimitiveType(self, tp, index): + prim_index = PRIMITIVE_TO_INDEX[tp.name] + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, prim_index) + + def _emit_bytecode_UnknownIntegerType(self, tp, index): + s = ('_cffi_prim_int(sizeof(%s), (\n' + ' ((%s)-1) | 0 /* check that %s is an integer type */\n' + ' ) <= 0)' % (tp.name, tp.name, tp.name)) + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + + def _emit_bytecode_UnknownFloatType(self, tp, index): + s = ('_cffi_prim_float(sizeof(%s) *\n' + ' (((%s)1) / 2) * 2 /* integer => 0, float => 1 */\n' + ' )' % (tp.name, tp.name)) + self.cffi_types[index] = CffiOp(OP_PRIMITIVE, s) + + def _emit_bytecode_RawFunctionType(self, tp, index): + self.cffi_types[index] = CffiOp(OP_FUNCTION, self._typesdict[tp.result]) + index += 1 + for tp1 in tp.args: + realindex = self._typesdict[tp1] + if index != realindex: + if isinstance(tp1, model.PrimitiveType): + self._emit_bytecode_PrimitiveType(tp1, index) + else: + self.cffi_types[index] = CffiOp(OP_NOOP, realindex) + index += 1 + flags = int(tp.ellipsis) + if tp.abi is not None: + if tp.abi == '__stdcall': + flags |= 2 + else: + raise NotImplementedError("abi=%r" % (tp.abi,)) + self.cffi_types[index] = CffiOp(OP_FUNCTION_END, flags) + + def _emit_bytecode_PointerType(self, tp, index): + self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[tp.totype]) + + _emit_bytecode_ConstPointerType = _emit_bytecode_PointerType + _emit_bytecode_NamedPointerType = _emit_bytecode_PointerType + + def _emit_bytecode_FunctionPtrType(self, tp, index): + raw = tp.as_raw_function() + self.cffi_types[index] = CffiOp(OP_POINTER, self._typesdict[raw]) + + def _emit_bytecode_ArrayType(self, tp, index): + item_index = self._typesdict[tp.item] + if tp.length is None: + self.cffi_types[index] = CffiOp(OP_OPEN_ARRAY, item_index) + elif tp.length == '...': + raise VerificationError( + "type %s badly placed: the '...' array length can only be " + "used on global arrays or on fields of structures" % ( + str(tp).replace('/*...*/', '...'),)) + else: + assert self.cffi_types[index + 1] == 'LEN' + self.cffi_types[index] = CffiOp(OP_ARRAY, item_index) + self.cffi_types[index + 1] = CffiOp(None, str(tp.length)) + + def _emit_bytecode_StructType(self, tp, index): + struct_index = self._struct_unions[tp] + self.cffi_types[index] = CffiOp(OP_STRUCT_UNION, struct_index) + _emit_bytecode_UnionType = _emit_bytecode_StructType + + def _emit_bytecode_EnumType(self, tp, index): + enum_index = self._enums[tp] + self.cffi_types[index] = CffiOp(OP_ENUM, enum_index) + + +if sys.version_info >= (3,): + NativeIO = io.StringIO +else: + class NativeIO(io.BytesIO): + def write(self, s): + if isinstance(s, unicode): + s = s.encode('ascii') + super(NativeIO, self).write(s) + +def _make_c_or_py_source(ffi, module_name, preamble, target_file, verbose): + if verbose: + print("generating %s" % (target_file,)) + recompiler = Recompiler(ffi, module_name, + target_is_python=(preamble is None)) + recompiler.collect_type_table() + recompiler.collect_step_tables() + f = NativeIO() + recompiler.write_source_to_f(f, preamble) + output = f.getvalue() + try: + with open(target_file, 'r') as f1: + if f1.read(len(output) + 1) != output: + raise IOError + if verbose: + print("(already up-to-date)") + return False # already up-to-date + except IOError: + tmp_file = '%s.~%d' % (target_file, os.getpid()) + with open(tmp_file, 'w') as f1: + f1.write(output) + try: + os.rename(tmp_file, target_file) + except OSError: + os.unlink(target_file) + os.rename(tmp_file, target_file) + return True + +def make_c_source(ffi, module_name, preamble, target_c_file, verbose=False): + assert preamble is not None + return _make_c_or_py_source(ffi, module_name, preamble, target_c_file, + verbose) + +def make_py_source(ffi, module_name, target_py_file, verbose=False): + return _make_c_or_py_source(ffi, module_name, None, target_py_file, + verbose) + +def _modname_to_file(outputdir, modname, extension): + parts = modname.split('.') + try: + os.makedirs(os.path.join(outputdir, *parts[:-1])) + except OSError: + pass + parts[-1] += extension + return os.path.join(outputdir, *parts), parts + + +# Aaargh. Distutils is not tested at all for the purpose of compiling +# DLLs that are not extension modules. Here are some hacks to work +# around that, in the _patch_for_*() functions... + +def _patch_meth(patchlist, cls, name, new_meth): + old = getattr(cls, name) + patchlist.append((cls, name, old)) + setattr(cls, name, new_meth) + return old + +def _unpatch_meths(patchlist): + for cls, name, old_meth in reversed(patchlist): + setattr(cls, name, old_meth) + +def _patch_for_embedding(patchlist): + if sys.platform == 'win32': + # we must not remove the manifest when building for embedding! + from cffi._shimmed_dist_utils import MSVCCompiler + _patch_meth(patchlist, MSVCCompiler, '_remove_visual_c_ref', + lambda self, manifest_file: manifest_file) + + if sys.platform == 'darwin': + # we must not make a '-bundle', but a '-dynamiclib' instead + from cffi._shimmed_dist_utils import CCompiler + def my_link_shared_object(self, *args, **kwds): + if '-bundle' in self.linker_so: + self.linker_so = list(self.linker_so) + i = self.linker_so.index('-bundle') + self.linker_so[i] = '-dynamiclib' + return old_link_shared_object(self, *args, **kwds) + old_link_shared_object = _patch_meth(patchlist, CCompiler, + 'link_shared_object', + my_link_shared_object) + +def _patch_for_target(patchlist, target): + from cffi._shimmed_dist_utils import build_ext + # if 'target' is different from '*', we need to patch some internal + # method to just return this 'target' value, instead of having it + # built from module_name + if target.endswith('.*'): + target = target[:-2] + if sys.platform == 'win32': + target += '.dll' + elif sys.platform == 'darwin': + target += '.dylib' + else: + target += '.so' + _patch_meth(patchlist, build_ext, 'get_ext_filename', + lambda self, ext_name: target) + + +def recompile(ffi, module_name, preamble, tmpdir='.', call_c_compiler=True, + c_file=None, source_extension='.c', extradir=None, + compiler_verbose=1, target=None, debug=None, **kwds): + if not isinstance(module_name, str): + module_name = module_name.encode('ascii') + if ffi._windows_unicode: + ffi._apply_windows_unicode(kwds) + if preamble is not None: + embedding = (ffi._embedding is not None) + if embedding: + ffi._apply_embedding_fix(kwds) + if c_file is None: + c_file, parts = _modname_to_file(tmpdir, module_name, + source_extension) + if extradir: + parts = [extradir] + parts + ext_c_file = os.path.join(*parts) + else: + ext_c_file = c_file + # + if target is None: + if embedding: + target = '%s.*' % module_name + else: + target = '*' + # + ext = ffiplatform.get_extension(ext_c_file, module_name, **kwds) + updated = make_c_source(ffi, module_name, preamble, c_file, + verbose=compiler_verbose) + if call_c_compiler: + patchlist = [] + cwd = os.getcwd() + try: + if embedding: + _patch_for_embedding(patchlist) + if target != '*': + _patch_for_target(patchlist, target) + if compiler_verbose: + if tmpdir == '.': + msg = 'the current directory is' + else: + msg = 'setting the current directory to' + print('%s %r' % (msg, os.path.abspath(tmpdir))) + os.chdir(tmpdir) + outputfilename = ffiplatform.compile('.', ext, + compiler_verbose, debug) + finally: + os.chdir(cwd) + _unpatch_meths(patchlist) + return outputfilename + else: + return ext, updated + else: + if c_file is None: + c_file, _ = _modname_to_file(tmpdir, module_name, '.py') + updated = make_py_source(ffi, module_name, c_file, + verbose=compiler_verbose) + if call_c_compiler: + return c_file + else: + return None, updated + diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/setuptools_ext.py b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/setuptools_ext.py new file mode 100644 index 000000000..681b49d7a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/setuptools_ext.py @@ -0,0 +1,216 @@ +import os +import sys + +try: + basestring +except NameError: + # Python 3.x + basestring = str + +def error(msg): + from cffi._shimmed_dist_utils import DistutilsSetupError + raise DistutilsSetupError(msg) + + +def execfile(filename, glob): + # We use execfile() (here rewritten for Python 3) instead of + # __import__() to load the build script. The problem with + # a normal import is that in some packages, the intermediate + # __init__.py files may already try to import the file that + # we are generating. + with open(filename) as f: + src = f.read() + src += '\n' # Python 2.6 compatibility + code = compile(src, filename, 'exec') + exec(code, glob, glob) + + +def add_cffi_module(dist, mod_spec): + from cffi.api import FFI + + if not isinstance(mod_spec, basestring): + error("argument to 'cffi_modules=...' must be a str or a list of str," + " not %r" % (type(mod_spec).__name__,)) + mod_spec = str(mod_spec) + try: + build_file_name, ffi_var_name = mod_spec.split(':') + except ValueError: + error("%r must be of the form 'path/build.py:ffi_variable'" % + (mod_spec,)) + if not os.path.exists(build_file_name): + ext = '' + rewritten = build_file_name.replace('.', '/') + '.py' + if os.path.exists(rewritten): + ext = ' (rewrite cffi_modules to [%r])' % ( + rewritten + ':' + ffi_var_name,) + error("%r does not name an existing file%s" % (build_file_name, ext)) + + mod_vars = {'__name__': '__cffi__', '__file__': build_file_name} + execfile(build_file_name, mod_vars) + + try: + ffi = mod_vars[ffi_var_name] + except KeyError: + error("%r: object %r not found in module" % (mod_spec, + ffi_var_name)) + if not isinstance(ffi, FFI): + ffi = ffi() # maybe it's a function instead of directly an ffi + if not isinstance(ffi, FFI): + error("%r is not an FFI instance (got %r)" % (mod_spec, + type(ffi).__name__)) + if not hasattr(ffi, '_assigned_source'): + error("%r: the set_source() method was not called" % (mod_spec,)) + module_name, source, source_extension, kwds = ffi._assigned_source + if ffi._windows_unicode: + kwds = kwds.copy() + ffi._apply_windows_unicode(kwds) + + if source is None: + _add_py_module(dist, ffi, module_name) + else: + _add_c_module(dist, ffi, module_name, source, source_extension, kwds) + +def _set_py_limited_api(Extension, kwds): + """ + Add py_limited_api to kwds if setuptools >= 26 is in use. + Do not alter the setting if it already exists. + Setuptools takes care of ignoring the flag on Python 2 and PyPy. + + CPython itself should ignore the flag in a debugging version + (by not listing .abi3.so in the extensions it supports), but + it doesn't so far, creating troubles. That's why we check + for "not hasattr(sys, 'gettotalrefcount')" (the 2.7 compatible equivalent + of 'd' not in sys.abiflags). (http://bugs.python.org/issue28401) + + On Windows, with CPython <= 3.4, it's better not to use py_limited_api + because virtualenv *still* doesn't copy PYTHON3.DLL on these versions. + Recently (2020) we started shipping only >= 3.5 wheels, though. So + we'll give it another try and set py_limited_api on Windows >= 3.5. + """ + from cffi import recompiler + + if ('py_limited_api' not in kwds and not hasattr(sys, 'gettotalrefcount') + and recompiler.USE_LIMITED_API): + import setuptools + try: + setuptools_major_version = int(setuptools.__version__.partition('.')[0]) + if setuptools_major_version >= 26: + kwds['py_limited_api'] = True + except ValueError: # certain development versions of setuptools + # If we don't know the version number of setuptools, we + # try to set 'py_limited_api' anyway. At worst, we get a + # warning. + kwds['py_limited_api'] = True + return kwds + +def _add_c_module(dist, ffi, module_name, source, source_extension, kwds): + # We are a setuptools extension. Need this build_ext for py_limited_api. + from setuptools.command.build_ext import build_ext + from cffi._shimmed_dist_utils import Extension, log, mkpath + from cffi import recompiler + + allsources = ['$PLACEHOLDER'] + allsources.extend(kwds.pop('sources', [])) + kwds = _set_py_limited_api(Extension, kwds) + ext = Extension(name=module_name, sources=allsources, **kwds) + + def make_mod(tmpdir, pre_run=None): + c_file = os.path.join(tmpdir, module_name + source_extension) + log.info("generating cffi module %r" % c_file) + mkpath(tmpdir) + # a setuptools-only, API-only hook: called with the "ext" and "ffi" + # arguments just before we turn the ffi into C code. To use it, + # subclass the 'distutils.command.build_ext.build_ext' class and + # add a method 'def pre_run(self, ext, ffi)'. + if pre_run is not None: + pre_run(ext, ffi) + updated = recompiler.make_c_source(ffi, module_name, source, c_file) + if not updated: + log.info("already up-to-date") + return c_file + + if dist.ext_modules is None: + dist.ext_modules = [] + dist.ext_modules.append(ext) + + base_class = dist.cmdclass.get('build_ext', build_ext) + class build_ext_make_mod(base_class): + def run(self): + if ext.sources[0] == '$PLACEHOLDER': + pre_run = getattr(self, 'pre_run', None) + ext.sources[0] = make_mod(self.build_temp, pre_run) + base_class.run(self) + dist.cmdclass['build_ext'] = build_ext_make_mod + # NB. multiple runs here will create multiple 'build_ext_make_mod' + # classes. Even in this case the 'build_ext' command should be + # run once; but just in case, the logic above does nothing if + # called again. + + +def _add_py_module(dist, ffi, module_name): + from setuptools.command.build_py import build_py + from setuptools.command.build_ext import build_ext + from cffi._shimmed_dist_utils import log, mkpath + from cffi import recompiler + + def generate_mod(py_file): + log.info("generating cffi module %r" % py_file) + mkpath(os.path.dirname(py_file)) + updated = recompiler.make_py_source(ffi, module_name, py_file) + if not updated: + log.info("already up-to-date") + + base_class = dist.cmdclass.get('build_py', build_py) + class build_py_make_mod(base_class): + def run(self): + base_class.run(self) + module_path = module_name.split('.') + module_path[-1] += '.py' + generate_mod(os.path.join(self.build_lib, *module_path)) + def get_source_files(self): + # This is called from 'setup.py sdist' only. Exclude + # the generate .py module in this case. + saved_py_modules = self.py_modules + try: + if saved_py_modules: + self.py_modules = [m for m in saved_py_modules + if m != module_name] + return base_class.get_source_files(self) + finally: + self.py_modules = saved_py_modules + dist.cmdclass['build_py'] = build_py_make_mod + + # distutils and setuptools have no notion I could find of a + # generated python module. If we don't add module_name to + # dist.py_modules, then things mostly work but there are some + # combination of options (--root and --record) that will miss + # the module. So we add it here, which gives a few apparently + # harmless warnings about not finding the file outside the + # build directory. + # Then we need to hack more in get_source_files(); see above. + if dist.py_modules is None: + dist.py_modules = [] + dist.py_modules.append(module_name) + + # the following is only for "build_ext -i" + base_class_2 = dist.cmdclass.get('build_ext', build_ext) + class build_ext_make_mod(base_class_2): + def run(self): + base_class_2.run(self) + if self.inplace: + # from get_ext_fullpath() in distutils/command/build_ext.py + module_path = module_name.split('.') + package = '.'.join(module_path[:-1]) + build_py = self.get_finalized_command('build_py') + package_dir = build_py.get_package_dir(package) + file_name = module_path[-1] + '.py' + generate_mod(os.path.join(package_dir, file_name)) + dist.cmdclass['build_ext'] = build_ext_make_mod + +def cffi_modules(dist, attr, value): + assert attr == 'cffi_modules' + if isinstance(value, basestring): + value = [value] + + for cffi_module in value: + add_cffi_module(dist, cffi_module) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/vengine_cpy.py b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/vengine_cpy.py new file mode 100644 index 000000000..49727d36e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/vengine_cpy.py @@ -0,0 +1,1077 @@ +# +# DEPRECATED: implementation for ffi.verify() +# +import sys +from . import model +from .error import VerificationError +from . import _imp_emulation as imp + + +class VCPythonEngine(object): + _class_key = 'x' + _gen_python_module = True + + def __init__(self, verifier): + self.verifier = verifier + self.ffi = verifier.ffi + self._struct_pending_verification = {} + self._types_of_builtin_functions = {} + + def patch_extension_kwds(self, kwds): + pass + + def find_module(self, module_name, path, so_suffixes): + try: + f, filename, descr = imp.find_module(module_name, path) + except ImportError: + return None + if f is not None: + f.close() + # Note that after a setuptools installation, there are both .py + # and .so files with the same basename. The code here relies on + # imp.find_module() locating the .so in priority. + if descr[0] not in so_suffixes: + return None + return filename + + def collect_types(self): + self._typesdict = {} + self._generate("collecttype") + + def _prnt(self, what=''): + self._f.write(what + '\n') + + def _gettypenum(self, type): + # a KeyError here is a bug. please report it! :-) + return self._typesdict[type] + + def _do_collect_type(self, tp): + if ((not isinstance(tp, model.PrimitiveType) + or tp.name == 'long double') + and tp not in self._typesdict): + num = len(self._typesdict) + self._typesdict[tp] = num + + def write_source_to_f(self): + self.collect_types() + # + # The new module will have a _cffi_setup() function that receives + # objects from the ffi world, and that calls some setup code in + # the module. This setup code is split in several independent + # functions, e.g. one per constant. The functions are "chained" + # by ending in a tail call to each other. + # + # This is further split in two chained lists, depending on if we + # can do it at import-time or if we must wait for _cffi_setup() to + # provide us with the objects. This is needed because we + # need the values of the enum constants in order to build the + # that we may have to pass to _cffi_setup(). + # + # The following two 'chained_list_constants' items contains + # the head of these two chained lists, as a string that gives the + # call to do, if any. + self._chained_list_constants = ['((void)lib,0)', '((void)lib,0)'] + # + prnt = self._prnt + # first paste some standard set of lines that are mostly '#define' + prnt(cffimod_header) + prnt() + # then paste the C source given by the user, verbatim. + prnt(self.verifier.preamble) + prnt() + # + # call generate_cpy_xxx_decl(), for every xxx found from + # ffi._parser._declarations. This generates all the functions. + self._generate("decl") + # + # implement the function _cffi_setup_custom() as calling the + # head of the chained list. + self._generate_setup_custom() + prnt() + # + # produce the method table, including the entries for the + # generated Python->C function wrappers, which are done + # by generate_cpy_function_method(). + prnt('static PyMethodDef _cffi_methods[] = {') + self._generate("method") + prnt(' {"_cffi_setup", _cffi_setup, METH_VARARGS, NULL},') + prnt(' {NULL, NULL, 0, NULL} /* Sentinel */') + prnt('};') + prnt() + # + # standard init. + modname = self.verifier.get_module_name() + constants = self._chained_list_constants[False] + prnt('#if PY_MAJOR_VERSION >= 3') + prnt() + prnt('static struct PyModuleDef _cffi_module_def = {') + prnt(' PyModuleDef_HEAD_INIT,') + prnt(' "%s",' % modname) + prnt(' NULL,') + prnt(' -1,') + prnt(' _cffi_methods,') + prnt(' NULL, NULL, NULL, NULL') + prnt('};') + prnt() + prnt('PyMODINIT_FUNC') + prnt('PyInit_%s(void)' % modname) + prnt('{') + prnt(' PyObject *lib;') + prnt(' lib = PyModule_Create(&_cffi_module_def);') + prnt(' if (lib == NULL)') + prnt(' return NULL;') + prnt(' if (%s < 0 || _cffi_init() < 0) {' % (constants,)) + prnt(' Py_DECREF(lib);') + prnt(' return NULL;') + prnt(' }') + prnt(' return lib;') + prnt('}') + prnt() + prnt('#else') + prnt() + prnt('PyMODINIT_FUNC') + prnt('init%s(void)' % modname) + prnt('{') + prnt(' PyObject *lib;') + prnt(' lib = Py_InitModule("%s", _cffi_methods);' % modname) + prnt(' if (lib == NULL)') + prnt(' return;') + prnt(' if (%s < 0 || _cffi_init() < 0)' % (constants,)) + prnt(' return;') + prnt(' return;') + prnt('}') + prnt() + prnt('#endif') + + def load_library(self, flags=None): + # XXX review all usages of 'self' here! + # import it as a new extension module + imp.acquire_lock() + try: + if hasattr(sys, "getdlopenflags"): + previous_flags = sys.getdlopenflags() + try: + if hasattr(sys, "setdlopenflags") and flags is not None: + sys.setdlopenflags(flags) + module = imp.load_dynamic(self.verifier.get_module_name(), + self.verifier.modulefilename) + except ImportError as e: + error = "importing %r: %s" % (self.verifier.modulefilename, e) + raise VerificationError(error) + finally: + if hasattr(sys, "setdlopenflags"): + sys.setdlopenflags(previous_flags) + finally: + imp.release_lock() + # + # call loading_cpy_struct() to get the struct layout inferred by + # the C compiler + self._load(module, 'loading') + # + # the C code will need the objects. Collect them in + # order in a list. + revmapping = dict([(value, key) + for (key, value) in self._typesdict.items()]) + lst = [revmapping[i] for i in range(len(revmapping))] + lst = list(map(self.ffi._get_cached_btype, lst)) + # + # build the FFILibrary class and instance and call _cffi_setup(). + # this will set up some fields like '_cffi_types', and only then + # it will invoke the chained list of functions that will really + # build (notably) the constant objects, as if they are + # pointers, and store them as attributes on the 'library' object. + class FFILibrary(object): + _cffi_python_module = module + _cffi_ffi = self.ffi + _cffi_dir = [] + def __dir__(self): + return FFILibrary._cffi_dir + list(self.__dict__) + library = FFILibrary() + if module._cffi_setup(lst, VerificationError, library): + import warnings + warnings.warn("reimporting %r might overwrite older definitions" + % (self.verifier.get_module_name())) + # + # finally, call the loaded_cpy_xxx() functions. This will perform + # the final adjustments, like copying the Python->C wrapper + # functions from the module to the 'library' object, and setting + # up the FFILibrary class with properties for the global C variables. + self._load(module, 'loaded', library=library) + module._cffi_original_ffi = self.ffi + module._cffi_types_of_builtin_funcs = self._types_of_builtin_functions + return library + + def _get_declarations(self): + lst = [(key, tp) for (key, (tp, qual)) in + self.ffi._parser._declarations.items()] + lst.sort() + return lst + + def _generate(self, step_name): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + try: + method = getattr(self, '_generate_cpy_%s_%s' % (kind, + step_name)) + except AttributeError: + raise VerificationError( + "not implemented in verify(): %r" % name) + try: + method(tp, realname) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _load(self, module, step_name, **kwds): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + method = getattr(self, '_%s_cpy_%s' % (step_name, kind)) + try: + method(tp, realname, module, **kwds) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _generate_nothing(self, tp, name): + pass + + def _loaded_noop(self, tp, name, module, **kwds): + pass + + # ---------- + + def _convert_funcarg_to_c(self, tp, fromvar, tovar, errcode): + extraarg = '' + if isinstance(tp, model.PrimitiveType): + if tp.is_integer_type() and tp.name != '_Bool': + converter = '_cffi_to_c_int' + extraarg = ', %s' % tp.name + else: + converter = '(%s)_cffi_to_c_%s' % (tp.get_c_name(''), + tp.name.replace(' ', '_')) + errvalue = '-1' + # + elif isinstance(tp, model.PointerType): + self._convert_funcarg_to_c_ptr_or_array(tp, fromvar, + tovar, errcode) + return + # + elif isinstance(tp, (model.StructOrUnion, model.EnumType)): + # a struct (not a struct pointer) as a function argument + self._prnt(' if (_cffi_to_c((char *)&%s, _cffi_type(%d), %s) < 0)' + % (tovar, self._gettypenum(tp), fromvar)) + self._prnt(' %s;' % errcode) + return + # + elif isinstance(tp, model.FunctionPtrType): + converter = '(%s)_cffi_to_c_pointer' % tp.get_c_name('') + extraarg = ', _cffi_type(%d)' % self._gettypenum(tp) + errvalue = 'NULL' + # + else: + raise NotImplementedError(tp) + # + self._prnt(' %s = %s(%s%s);' % (tovar, converter, fromvar, extraarg)) + self._prnt(' if (%s == (%s)%s && PyErr_Occurred())' % ( + tovar, tp.get_c_name(''), errvalue)) + self._prnt(' %s;' % errcode) + + def _extra_local_variables(self, tp, localvars, freelines): + if isinstance(tp, model.PointerType): + localvars.add('Py_ssize_t datasize') + localvars.add('struct _cffi_freeme_s *large_args_free = NULL') + freelines.add('if (large_args_free != NULL)' + ' _cffi_free_array_arguments(large_args_free);') + + def _convert_funcarg_to_c_ptr_or_array(self, tp, fromvar, tovar, errcode): + self._prnt(' datasize = _cffi_prepare_pointer_call_argument(') + self._prnt(' _cffi_type(%d), %s, (char **)&%s);' % ( + self._gettypenum(tp), fromvar, tovar)) + self._prnt(' if (datasize != 0) {') + self._prnt(' %s = ((size_t)datasize) <= 640 ? ' + 'alloca((size_t)datasize) : NULL;' % (tovar,)) + self._prnt(' if (_cffi_convert_array_argument(_cffi_type(%d), %s, ' + '(char **)&%s,' % (self._gettypenum(tp), fromvar, tovar)) + self._prnt(' datasize, &large_args_free) < 0)') + self._prnt(' %s;' % errcode) + self._prnt(' }') + + def _convert_expr_from_c(self, tp, var, context): + if isinstance(tp, model.PrimitiveType): + if tp.is_integer_type() and tp.name != '_Bool': + return '_cffi_from_c_int(%s, %s)' % (var, tp.name) + elif tp.name != 'long double': + return '_cffi_from_c_%s(%s)' % (tp.name.replace(' ', '_'), var) + else: + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, (model.PointerType, model.FunctionPtrType)): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.ArrayType): + return '_cffi_from_c_pointer((char *)%s, _cffi_type(%d))' % ( + var, self._gettypenum(model.PointerType(tp.item))) + elif isinstance(tp, model.StructOrUnion): + if tp.fldnames is None: + raise TypeError("'%s' is used as %s, but is opaque" % ( + tp._get_c_name(), context)) + return '_cffi_from_c_struct((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + elif isinstance(tp, model.EnumType): + return '_cffi_from_c_deref((char *)&%s, _cffi_type(%d))' % ( + var, self._gettypenum(tp)) + else: + raise NotImplementedError(tp) + + # ---------- + # typedefs: generates no code so far + + _generate_cpy_typedef_collecttype = _generate_nothing + _generate_cpy_typedef_decl = _generate_nothing + _generate_cpy_typedef_method = _generate_nothing + _loading_cpy_typedef = _loaded_noop + _loaded_cpy_typedef = _loaded_noop + + # ---------- + # function declarations + + def _generate_cpy_function_collecttype(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + self._do_collect_type(tp) + else: + # don't call _do_collect_type(tp) in this common case, + # otherwise test_autofilled_struct_as_argument fails + for type in tp.args: + self._do_collect_type(type) + self._do_collect_type(tp.result) + + def _generate_cpy_function_decl(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + # cannot support vararg functions better than this: check for its + # exact type (including the fixed arguments), and build it as a + # constant function pointer (no CPython wrapper) + self._generate_cpy_const(False, name, tp) + return + prnt = self._prnt + numargs = len(tp.args) + if numargs == 0: + argname = 'noarg' + elif numargs == 1: + argname = 'arg0' + else: + argname = 'args' + prnt('static PyObject *') + prnt('_cffi_f_%s(PyObject *self, PyObject *%s)' % (name, argname)) + prnt('{') + # + context = 'argument of %s' % name + for i, type in enumerate(tp.args): + prnt(' %s;' % type.get_c_name(' x%d' % i, context)) + # + localvars = set() + freelines = set() + for type in tp.args: + self._extra_local_variables(type, localvars, freelines) + for decl in sorted(localvars): + prnt(' %s;' % (decl,)) + # + if not isinstance(tp.result, model.VoidType): + result_code = 'result = ' + context = 'result of %s' % name + prnt(' %s;' % tp.result.get_c_name(' result', context)) + prnt(' PyObject *pyresult;') + else: + result_code = '' + # + if len(tp.args) > 1: + rng = range(len(tp.args)) + for i in rng: + prnt(' PyObject *arg%d;' % i) + prnt() + prnt(' if (!PyArg_ParseTuple(args, "%s:%s", %s))' % ( + 'O' * numargs, name, ', '.join(['&arg%d' % i for i in rng]))) + prnt(' return NULL;') + prnt() + # + for i, type in enumerate(tp.args): + self._convert_funcarg_to_c(type, 'arg%d' % i, 'x%d' % i, + 'return NULL') + prnt() + # + prnt(' Py_BEGIN_ALLOW_THREADS') + prnt(' _cffi_restore_errno();') + prnt(' { %s%s(%s); }' % ( + result_code, name, + ', '.join(['x%d' % i for i in range(len(tp.args))]))) + prnt(' _cffi_save_errno();') + prnt(' Py_END_ALLOW_THREADS') + prnt() + # + prnt(' (void)self; /* unused */') + if numargs == 0: + prnt(' (void)noarg; /* unused */') + if result_code: + prnt(' pyresult = %s;' % + self._convert_expr_from_c(tp.result, 'result', 'result type')) + for freeline in freelines: + prnt(' ' + freeline) + prnt(' return pyresult;') + else: + for freeline in freelines: + prnt(' ' + freeline) + prnt(' Py_INCREF(Py_None);') + prnt(' return Py_None;') + prnt('}') + prnt() + + def _generate_cpy_function_method(self, tp, name): + if tp.ellipsis: + return + numargs = len(tp.args) + if numargs == 0: + meth = 'METH_NOARGS' + elif numargs == 1: + meth = 'METH_O' + else: + meth = 'METH_VARARGS' + self._prnt(' {"%s", _cffi_f_%s, %s, NULL},' % (name, name, meth)) + + _loading_cpy_function = _loaded_noop + + def _loaded_cpy_function(self, tp, name, module, library): + if tp.ellipsis: + return + func = getattr(module, name) + setattr(library, name, func) + self._types_of_builtin_functions[func] = tp + + # ---------- + # named structs + + _generate_cpy_struct_collecttype = _generate_nothing + def _generate_cpy_struct_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'struct', name) + def _generate_cpy_struct_method(self, tp, name): + self._generate_struct_or_union_method(tp, 'struct', name) + def _loading_cpy_struct(self, tp, name, module): + self._loading_struct_or_union(tp, 'struct', name, module) + def _loaded_cpy_struct(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + _generate_cpy_union_collecttype = _generate_nothing + def _generate_cpy_union_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'union', name) + def _generate_cpy_union_method(self, tp, name): + self._generate_struct_or_union_method(tp, 'union', name) + def _loading_cpy_union(self, tp, name, module): + self._loading_struct_or_union(tp, 'union', name, module) + def _loaded_cpy_union(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + def _generate_struct_or_union_decl(self, tp, prefix, name): + if tp.fldnames is None: + return # nothing to do with opaque structs + checkfuncname = '_cffi_check_%s_%s' % (prefix, name) + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + cname = ('%s %s' % (prefix, name)).strip() + # + prnt = self._prnt + prnt('static void %s(%s *p)' % (checkfuncname, cname)) + prnt('{') + prnt(' /* only to generate compile-time warnings or errors */') + prnt(' (void)p;') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if (isinstance(ftype, model.PrimitiveType) + and ftype.is_integer_type()) or fbitsize >= 0: + # accept all integers, but complain on float or double + prnt(' (void)((p->%s) << 1);' % fname) + else: + # only accept exactly the type declared. + try: + prnt(' { %s = &p->%s; (void)tmp; }' % ( + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) + except VerificationError as e: + prnt(' /* %s */' % str(e)) # cannot verify it, ignore + prnt('}') + prnt('static PyObject *') + prnt('%s(PyObject *self, PyObject *noarg)' % (layoutfuncname,)) + prnt('{') + prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname) + prnt(' static Py_ssize_t nums[] = {') + prnt(' sizeof(%s),' % cname) + prnt(' offsetof(struct _cffi_aligncheck, y),') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + prnt(' offsetof(%s, %s),' % (cname, fname)) + if isinstance(ftype, model.ArrayType) and ftype.length is None: + prnt(' 0, /* %s */' % ftype._get_c_name()) + else: + prnt(' sizeof(((%s *)0)->%s),' % (cname, fname)) + prnt(' -1') + prnt(' };') + prnt(' (void)self; /* unused */') + prnt(' (void)noarg; /* unused */') + prnt(' return _cffi_get_struct_layout(nums);') + prnt(' /* the next line is not executed, but compiled */') + prnt(' %s(0);' % (checkfuncname,)) + prnt('}') + prnt() + + def _generate_struct_or_union_method(self, tp, prefix, name): + if tp.fldnames is None: + return # nothing to do with opaque structs + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + self._prnt(' {"%s", %s, METH_NOARGS, NULL},' % (layoutfuncname, + layoutfuncname)) + + def _loading_struct_or_union(self, tp, prefix, name, module): + if tp.fldnames is None: + return # nothing to do with opaque structs + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + # + function = getattr(module, layoutfuncname) + layout = function() + if isinstance(tp, model.StructOrUnion) and tp.partial: + # use the function()'s sizes and offsets to guide the + # layout of the struct + totalsize = layout[0] + totalalignment = layout[1] + fieldofs = layout[2::2] + fieldsize = layout[3::2] + tp.force_flatten() + assert len(fieldofs) == len(fieldsize) == len(tp.fldnames) + tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment + else: + cname = ('%s %s' % (prefix, name)).strip() + self._struct_pending_verification[tp] = layout, cname + + def _loaded_struct_or_union(self, tp): + if tp.fldnames is None: + return # nothing to do with opaque structs + self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered + + if tp in self._struct_pending_verification: + # check that the layout sizes and offsets match the real ones + def check(realvalue, expectedvalue, msg): + if realvalue != expectedvalue: + raise VerificationError( + "%s (we have %d, but C compiler says %d)" + % (msg, expectedvalue, realvalue)) + ffi = self.ffi + BStruct = ffi._get_cached_btype(tp) + layout, cname = self._struct_pending_verification.pop(tp) + check(layout[0], ffi.sizeof(BStruct), "wrong total size") + check(layout[1], ffi.alignof(BStruct), "wrong total alignment") + i = 2 + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + check(layout[i], ffi.offsetof(BStruct, fname), + "wrong offset for field %r" % (fname,)) + if layout[i+1] != 0: + BField = ffi._get_cached_btype(ftype) + check(layout[i+1], ffi.sizeof(BField), + "wrong size for field %r" % (fname,)) + i += 2 + assert i == len(layout) + + # ---------- + # 'anonymous' declarations. These are produced for anonymous structs + # or unions; the 'name' is obtained by a typedef. + + _generate_cpy_anonymous_collecttype = _generate_nothing + + def _generate_cpy_anonymous_decl(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_cpy_enum_decl(tp, name, '') + else: + self._generate_struct_or_union_decl(tp, '', name) + + def _generate_cpy_anonymous_method(self, tp, name): + if not isinstance(tp, model.EnumType): + self._generate_struct_or_union_method(tp, '', name) + + def _loading_cpy_anonymous(self, tp, name, module): + if isinstance(tp, model.EnumType): + self._loading_cpy_enum(tp, name, module) + else: + self._loading_struct_or_union(tp, '', name, module) + + def _loaded_cpy_anonymous(self, tp, name, module, **kwds): + if isinstance(tp, model.EnumType): + self._loaded_cpy_enum(tp, name, module, **kwds) + else: + self._loaded_struct_or_union(tp) + + # ---------- + # constants, likely declared with '#define' + + def _generate_cpy_const(self, is_int, name, tp=None, category='const', + vartp=None, delayed=True, size_too=False, + check_value=None): + prnt = self._prnt + funcname = '_cffi_%s_%s' % (category, name) + prnt('static int %s(PyObject *lib)' % funcname) + prnt('{') + prnt(' PyObject *o;') + prnt(' int res;') + if not is_int: + prnt(' %s;' % (vartp or tp).get_c_name(' i', name)) + else: + assert category == 'const' + # + if check_value is not None: + self._check_int_constant_value(name, check_value) + # + if not is_int: + if category == 'var': + realexpr = '&' + name + else: + realexpr = name + prnt(' i = (%s);' % (realexpr,)) + prnt(' o = %s;' % (self._convert_expr_from_c(tp, 'i', + 'variable type'),)) + assert delayed + else: + prnt(' o = _cffi_from_c_int_const(%s);' % name) + prnt(' if (o == NULL)') + prnt(' return -1;') + if size_too: + prnt(' {') + prnt(' PyObject *o1 = o;') + prnt(' o = Py_BuildValue("On", o1, (Py_ssize_t)sizeof(%s));' + % (name,)) + prnt(' Py_DECREF(o1);') + prnt(' if (o == NULL)') + prnt(' return -1;') + prnt(' }') + prnt(' res = PyObject_SetAttrString(lib, "%s", o);' % name) + prnt(' Py_DECREF(o);') + prnt(' if (res < 0)') + prnt(' return -1;') + prnt(' return %s;' % self._chained_list_constants[delayed]) + self._chained_list_constants[delayed] = funcname + '(lib)' + prnt('}') + prnt() + + def _generate_cpy_constant_collecttype(self, tp, name): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + if not is_int: + self._do_collect_type(tp) + + def _generate_cpy_constant_decl(self, tp, name): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + self._generate_cpy_const(is_int, name, tp) + + _generate_cpy_constant_method = _generate_nothing + _loading_cpy_constant = _loaded_noop + _loaded_cpy_constant = _loaded_noop + + # ---------- + # enums + + def _check_int_constant_value(self, name, value, err_prefix=''): + prnt = self._prnt + if value <= 0: + prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % ( + name, name, value)) + else: + prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % ( + name, name, value)) + prnt(' char buf[64];') + prnt(' if ((%s) <= 0)' % name) + prnt(' snprintf(buf, 63, "%%ld", (long)(%s));' % name) + prnt(' else') + prnt(' snprintf(buf, 63, "%%lu", (unsigned long)(%s));' % + name) + prnt(' PyErr_Format(_cffi_VerificationError,') + prnt(' "%s%s has the real value %s, not %s",') + prnt(' "%s", "%s", buf, "%d");' % ( + err_prefix, name, value)) + prnt(' return -1;') + prnt(' }') + + def _enum_funcname(self, prefix, name): + # "$enum_$1" => "___D_enum____D_1" + name = name.replace('$', '___D_') + return '_cffi_e_%s_%s' % (prefix, name) + + def _generate_cpy_enum_decl(self, tp, name, prefix='enum'): + if tp.partial: + for enumerator in tp.enumerators: + self._generate_cpy_const(True, enumerator, delayed=False) + return + # + funcname = self._enum_funcname(prefix, name) + prnt = self._prnt + prnt('static int %s(PyObject *lib)' % funcname) + prnt('{') + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + self._check_int_constant_value(enumerator, enumvalue, + "enum %s: " % name) + prnt(' return %s;' % self._chained_list_constants[True]) + self._chained_list_constants[True] = funcname + '(lib)' + prnt('}') + prnt() + + _generate_cpy_enum_collecttype = _generate_nothing + _generate_cpy_enum_method = _generate_nothing + + def _loading_cpy_enum(self, tp, name, module): + if tp.partial: + enumvalues = [getattr(module, enumerator) + for enumerator in tp.enumerators] + tp.enumvalues = tuple(enumvalues) + tp.partial_resolved = True + + def _loaded_cpy_enum(self, tp, name, module, library): + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + setattr(library, enumerator, enumvalue) + + # ---------- + # macros: for now only for integers + + def _generate_cpy_macro_decl(self, tp, name): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + self._generate_cpy_const(True, name, check_value=check_value) + + _generate_cpy_macro_collecttype = _generate_nothing + _generate_cpy_macro_method = _generate_nothing + _loading_cpy_macro = _loaded_noop + _loaded_cpy_macro = _loaded_noop + + # ---------- + # global variables + + def _generate_cpy_variable_collecttype(self, tp, name): + if isinstance(tp, model.ArrayType): + tp_ptr = model.PointerType(tp.item) + else: + tp_ptr = model.PointerType(tp) + self._do_collect_type(tp_ptr) + + def _generate_cpy_variable_decl(self, tp, name): + if isinstance(tp, model.ArrayType): + tp_ptr = model.PointerType(tp.item) + self._generate_cpy_const(False, name, tp, vartp=tp_ptr, + size_too = tp.length_is_unknown()) + else: + tp_ptr = model.PointerType(tp) + self._generate_cpy_const(False, name, tp_ptr, category='var') + + _generate_cpy_variable_method = _generate_nothing + _loading_cpy_variable = _loaded_noop + + def _loaded_cpy_variable(self, tp, name, module, library): + value = getattr(library, name) + if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the + # sense that "a=..." is forbidden + if tp.length_is_unknown(): + assert isinstance(value, tuple) + (value, size) = value + BItemType = self.ffi._get_cached_btype(tp.item) + length, rest = divmod(size, self.ffi.sizeof(BItemType)) + if rest != 0: + raise VerificationError( + "bad size: %r does not seem to be an array of %s" % + (name, tp.item)) + tp = tp.resolve_length(length) + # 'value' is a which we have to replace with + # a if the N is actually known + if tp.length is not None: + BArray = self.ffi._get_cached_btype(tp) + value = self.ffi.cast(BArray, value) + setattr(library, name, value) + return + # remove ptr= from the library instance, and replace + # it by a property on the class, which reads/writes into ptr[0]. + ptr = value + delattr(library, name) + def getter(library): + return ptr[0] + def setter(library, value): + ptr[0] = value + setattr(type(library), name, property(getter, setter)) + type(library)._cffi_dir.append(name) + + # ---------- + + def _generate_setup_custom(self): + prnt = self._prnt + prnt('static int _cffi_setup_custom(PyObject *lib)') + prnt('{') + prnt(' return %s;' % self._chained_list_constants[True]) + prnt('}') + +cffimod_header = r''' +#include +#include + +/* this block of #ifs should be kept exactly identical between + c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py + and cffi/_cffi_include.h */ +#if defined(_MSC_VER) +# include /* for alloca() */ +# if _MSC_VER < 1600 /* MSVC < 2010 */ + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int8 int_least8_t; + typedef __int16 int_least16_t; + typedef __int32 int_least32_t; + typedef __int64 int_least64_t; + typedef unsigned __int8 uint_least8_t; + typedef unsigned __int16 uint_least16_t; + typedef unsigned __int32 uint_least32_t; + typedef unsigned __int64 uint_least64_t; + typedef __int8 int_fast8_t; + typedef __int16 int_fast16_t; + typedef __int32 int_fast32_t; + typedef __int64 int_fast64_t; + typedef unsigned __int8 uint_fast8_t; + typedef unsigned __int16 uint_fast16_t; + typedef unsigned __int32 uint_fast32_t; + typedef unsigned __int64 uint_fast64_t; + typedef __int64 intmax_t; + typedef unsigned __int64 uintmax_t; +# else +# include +# endif +# if _MSC_VER < 1800 /* MSVC < 2013 */ +# ifndef __cplusplus + typedef unsigned char _Bool; +# endif +# endif +#else +# include +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) +# include +# endif +#endif + +#if PY_MAJOR_VERSION < 3 +# undef PyCapsule_CheckExact +# undef PyCapsule_GetPointer +# define PyCapsule_CheckExact(capsule) (PyCObject_Check(capsule)) +# define PyCapsule_GetPointer(capsule, name) \ + (PyCObject_AsVoidPtr(capsule)) +#endif + +#if PY_MAJOR_VERSION >= 3 +# define PyInt_FromLong PyLong_FromLong +#endif + +#define _cffi_from_c_double PyFloat_FromDouble +#define _cffi_from_c_float PyFloat_FromDouble +#define _cffi_from_c_long PyInt_FromLong +#define _cffi_from_c_ulong PyLong_FromUnsignedLong +#define _cffi_from_c_longlong PyLong_FromLongLong +#define _cffi_from_c_ulonglong PyLong_FromUnsignedLongLong +#define _cffi_from_c__Bool PyBool_FromLong + +#define _cffi_to_c_double PyFloat_AsDouble +#define _cffi_to_c_float PyFloat_AsDouble + +#define _cffi_from_c_int_const(x) \ + (((x) > 0) ? \ + ((unsigned long long)(x) <= (unsigned long long)LONG_MAX) ? \ + PyInt_FromLong((long)(x)) : \ + PyLong_FromUnsignedLongLong((unsigned long long)(x)) : \ + ((long long)(x) >= (long long)LONG_MIN) ? \ + PyInt_FromLong((long)(x)) : \ + PyLong_FromLongLong((long long)(x))) + +#define _cffi_from_c_int(x, type) \ + (((type)-1) > 0 ? /* unsigned */ \ + (sizeof(type) < sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + sizeof(type) == sizeof(long) ? \ + PyLong_FromUnsignedLong((unsigned long)x) : \ + PyLong_FromUnsignedLongLong((unsigned long long)x)) : \ + (sizeof(type) <= sizeof(long) ? \ + PyInt_FromLong((long)x) : \ + PyLong_FromLongLong((long long)x))) + +#define _cffi_to_c_int(o, type) \ + ((type)( \ + sizeof(type) == 1 ? (((type)-1) > 0 ? (type)_cffi_to_c_u8(o) \ + : (type)_cffi_to_c_i8(o)) : \ + sizeof(type) == 2 ? (((type)-1) > 0 ? (type)_cffi_to_c_u16(o) \ + : (type)_cffi_to_c_i16(o)) : \ + sizeof(type) == 4 ? (((type)-1) > 0 ? (type)_cffi_to_c_u32(o) \ + : (type)_cffi_to_c_i32(o)) : \ + sizeof(type) == 8 ? (((type)-1) > 0 ? (type)_cffi_to_c_u64(o) \ + : (type)_cffi_to_c_i64(o)) : \ + (Py_FatalError("unsupported size for type " #type), (type)0))) + +#define _cffi_to_c_i8 \ + ((int(*)(PyObject *))_cffi_exports[1]) +#define _cffi_to_c_u8 \ + ((int(*)(PyObject *))_cffi_exports[2]) +#define _cffi_to_c_i16 \ + ((int(*)(PyObject *))_cffi_exports[3]) +#define _cffi_to_c_u16 \ + ((int(*)(PyObject *))_cffi_exports[4]) +#define _cffi_to_c_i32 \ + ((int(*)(PyObject *))_cffi_exports[5]) +#define _cffi_to_c_u32 \ + ((unsigned int(*)(PyObject *))_cffi_exports[6]) +#define _cffi_to_c_i64 \ + ((long long(*)(PyObject *))_cffi_exports[7]) +#define _cffi_to_c_u64 \ + ((unsigned long long(*)(PyObject *))_cffi_exports[8]) +#define _cffi_to_c_char \ + ((int(*)(PyObject *))_cffi_exports[9]) +#define _cffi_from_c_pointer \ + ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[10]) +#define _cffi_to_c_pointer \ + ((char *(*)(PyObject *, CTypeDescrObject *))_cffi_exports[11]) +#define _cffi_get_struct_layout \ + ((PyObject *(*)(Py_ssize_t[]))_cffi_exports[12]) +#define _cffi_restore_errno \ + ((void(*)(void))_cffi_exports[13]) +#define _cffi_save_errno \ + ((void(*)(void))_cffi_exports[14]) +#define _cffi_from_c_char \ + ((PyObject *(*)(char))_cffi_exports[15]) +#define _cffi_from_c_deref \ + ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[16]) +#define _cffi_to_c \ + ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[17]) +#define _cffi_from_c_struct \ + ((PyObject *(*)(char *, CTypeDescrObject *))_cffi_exports[18]) +#define _cffi_to_c_wchar_t \ + ((wchar_t(*)(PyObject *))_cffi_exports[19]) +#define _cffi_from_c_wchar_t \ + ((PyObject *(*)(wchar_t))_cffi_exports[20]) +#define _cffi_to_c_long_double \ + ((long double(*)(PyObject *))_cffi_exports[21]) +#define _cffi_to_c__Bool \ + ((_Bool(*)(PyObject *))_cffi_exports[22]) +#define _cffi_prepare_pointer_call_argument \ + ((Py_ssize_t(*)(CTypeDescrObject *, PyObject *, char **))_cffi_exports[23]) +#define _cffi_convert_array_from_object \ + ((int(*)(char *, CTypeDescrObject *, PyObject *))_cffi_exports[24]) +#define _CFFI_NUM_EXPORTS 25 + +typedef struct _ctypedescr CTypeDescrObject; + +static void *_cffi_exports[_CFFI_NUM_EXPORTS]; +static PyObject *_cffi_types, *_cffi_VerificationError; + +static int _cffi_setup_custom(PyObject *lib); /* forward */ + +static PyObject *_cffi_setup(PyObject *self, PyObject *args) +{ + PyObject *library; + int was_alive = (_cffi_types != NULL); + (void)self; /* unused */ + if (!PyArg_ParseTuple(args, "OOO", &_cffi_types, &_cffi_VerificationError, + &library)) + return NULL; + Py_INCREF(_cffi_types); + Py_INCREF(_cffi_VerificationError); + if (_cffi_setup_custom(library) < 0) + return NULL; + return PyBool_FromLong(was_alive); +} + +union _cffi_union_alignment_u { + unsigned char m_char; + unsigned short m_short; + unsigned int m_int; + unsigned long m_long; + unsigned long long m_longlong; + float m_float; + double m_double; + long double m_longdouble; +}; + +struct _cffi_freeme_s { + struct _cffi_freeme_s *next; + union _cffi_union_alignment_u alignment; +}; + +#ifdef __GNUC__ + __attribute__((unused)) +#endif +static int _cffi_convert_array_argument(CTypeDescrObject *ctptr, PyObject *arg, + char **output_data, Py_ssize_t datasize, + struct _cffi_freeme_s **freeme) +{ + char *p; + if (datasize < 0) + return -1; + + p = *output_data; + if (p == NULL) { + struct _cffi_freeme_s *fp = (struct _cffi_freeme_s *)PyObject_Malloc( + offsetof(struct _cffi_freeme_s, alignment) + (size_t)datasize); + if (fp == NULL) + return -1; + fp->next = *freeme; + *freeme = fp; + p = *output_data = (char *)&fp->alignment; + } + memset((void *)p, 0, (size_t)datasize); + return _cffi_convert_array_from_object(p, ctptr, arg); +} + +#ifdef __GNUC__ + __attribute__((unused)) +#endif +static void _cffi_free_array_arguments(struct _cffi_freeme_s *freeme) +{ + do { + void *p = (void *)freeme; + freeme = freeme->next; + PyObject_Free(p); + } while (freeme != NULL); +} + +static int _cffi_init(void) +{ + PyObject *module, *c_api_object = NULL; + + module = PyImport_ImportModule("_cffi_backend"); + if (module == NULL) + goto failure; + + c_api_object = PyObject_GetAttrString(module, "_C_API"); + if (c_api_object == NULL) + goto failure; + if (!PyCapsule_CheckExact(c_api_object)) { + PyErr_SetNone(PyExc_ImportError); + goto failure; + } + memcpy(_cffi_exports, PyCapsule_GetPointer(c_api_object, "cffi"), + _CFFI_NUM_EXPORTS * sizeof(void *)); + + Py_DECREF(module); + Py_DECREF(c_api_object); + return 0; + + failure: + Py_XDECREF(module); + Py_XDECREF(c_api_object); + return -1; +} + +#define _cffi_type(num) ((CTypeDescrObject *)PyList_GET_ITEM(_cffi_types, num)) + +/**********/ +''' diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/vengine_gen.py b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/vengine_gen.py new file mode 100644 index 000000000..26421526f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/vengine_gen.py @@ -0,0 +1,675 @@ +# +# DEPRECATED: implementation for ffi.verify() +# +import sys, os +import types + +from . import model +from .error import VerificationError + + +class VGenericEngine(object): + _class_key = 'g' + _gen_python_module = False + + def __init__(self, verifier): + self.verifier = verifier + self.ffi = verifier.ffi + self.export_symbols = [] + self._struct_pending_verification = {} + + def patch_extension_kwds(self, kwds): + # add 'export_symbols' to the dictionary. Note that we add the + # list before filling it. When we fill it, it will thus also show + # up in kwds['export_symbols']. + kwds.setdefault('export_symbols', self.export_symbols) + + def find_module(self, module_name, path, so_suffixes): + for so_suffix in so_suffixes: + basename = module_name + so_suffix + if path is None: + path = sys.path + for dirname in path: + filename = os.path.join(dirname, basename) + if os.path.isfile(filename): + return filename + + def collect_types(self): + pass # not needed in the generic engine + + def _prnt(self, what=''): + self._f.write(what + '\n') + + def write_source_to_f(self): + prnt = self._prnt + # first paste some standard set of lines that are mostly '#include' + prnt(cffimod_header) + # then paste the C source given by the user, verbatim. + prnt(self.verifier.preamble) + # + # call generate_gen_xxx_decl(), for every xxx found from + # ffi._parser._declarations. This generates all the functions. + self._generate('decl') + # + # on Windows, distutils insists on putting init_cffi_xyz in + # 'export_symbols', so instead of fighting it, just give up and + # give it one + if sys.platform == 'win32': + if sys.version_info >= (3,): + prefix = 'PyInit_' + else: + prefix = 'init' + modname = self.verifier.get_module_name() + prnt("void %s%s(void) { }\n" % (prefix, modname)) + + def load_library(self, flags=0): + # import it with the CFFI backend + backend = self.ffi._backend + # needs to make a path that contains '/', on Posix + filename = os.path.join(os.curdir, self.verifier.modulefilename) + module = backend.load_library(filename, flags) + # + # call loading_gen_struct() to get the struct layout inferred by + # the C compiler + self._load(module, 'loading') + + # build the FFILibrary class and instance, this is a module subclass + # because modules are expected to have usually-constant-attributes and + # in PyPy this means the JIT is able to treat attributes as constant, + # which we want. + class FFILibrary(types.ModuleType): + _cffi_generic_module = module + _cffi_ffi = self.ffi + _cffi_dir = [] + def __dir__(self): + return FFILibrary._cffi_dir + library = FFILibrary("") + # + # finally, call the loaded_gen_xxx() functions. This will set + # up the 'library' object. + self._load(module, 'loaded', library=library) + return library + + def _get_declarations(self): + lst = [(key, tp) for (key, (tp, qual)) in + self.ffi._parser._declarations.items()] + lst.sort() + return lst + + def _generate(self, step_name): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + try: + method = getattr(self, '_generate_gen_%s_%s' % (kind, + step_name)) + except AttributeError: + raise VerificationError( + "not implemented in verify(): %r" % name) + try: + method(tp, realname) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _load(self, module, step_name, **kwds): + for name, tp in self._get_declarations(): + kind, realname = name.split(' ', 1) + method = getattr(self, '_%s_gen_%s' % (step_name, kind)) + try: + method(tp, realname, module, **kwds) + except Exception as e: + model.attach_exception_info(e, name) + raise + + def _generate_nothing(self, tp, name): + pass + + def _loaded_noop(self, tp, name, module, **kwds): + pass + + # ---------- + # typedefs: generates no code so far + + _generate_gen_typedef_decl = _generate_nothing + _loading_gen_typedef = _loaded_noop + _loaded_gen_typedef = _loaded_noop + + # ---------- + # function declarations + + def _generate_gen_function_decl(self, tp, name): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + # cannot support vararg functions better than this: check for its + # exact type (including the fixed arguments), and build it as a + # constant function pointer (no _cffi_f_%s wrapper) + self._generate_gen_const(False, name, tp) + return + prnt = self._prnt + numargs = len(tp.args) + argnames = [] + for i, type in enumerate(tp.args): + indirection = '' + if isinstance(type, model.StructOrUnion): + indirection = '*' + argnames.append('%sx%d' % (indirection, i)) + context = 'argument of %s' % name + arglist = [type.get_c_name(' %s' % arg, context) + for type, arg in zip(tp.args, argnames)] + tpresult = tp.result + if isinstance(tpresult, model.StructOrUnion): + arglist.insert(0, tpresult.get_c_name(' *r', context)) + tpresult = model.void_type + arglist = ', '.join(arglist) or 'void' + wrappername = '_cffi_f_%s' % name + self.export_symbols.append(wrappername) + if tp.abi: + abi = tp.abi + ' ' + else: + abi = '' + funcdecl = ' %s%s(%s)' % (abi, wrappername, arglist) + context = 'result of %s' % name + prnt(tpresult.get_c_name(funcdecl, context)) + prnt('{') + # + if isinstance(tp.result, model.StructOrUnion): + result_code = '*r = ' + elif not isinstance(tp.result, model.VoidType): + result_code = 'return ' + else: + result_code = '' + prnt(' %s%s(%s);' % (result_code, name, ', '.join(argnames))) + prnt('}') + prnt() + + _loading_gen_function = _loaded_noop + + def _loaded_gen_function(self, tp, name, module, library): + assert isinstance(tp, model.FunctionPtrType) + if tp.ellipsis: + newfunction = self._load_constant(False, tp, name, module) + else: + indirections = [] + base_tp = tp + if (any(isinstance(typ, model.StructOrUnion) for typ in tp.args) + or isinstance(tp.result, model.StructOrUnion)): + indirect_args = [] + for i, typ in enumerate(tp.args): + if isinstance(typ, model.StructOrUnion): + typ = model.PointerType(typ) + indirections.append((i, typ)) + indirect_args.append(typ) + indirect_result = tp.result + if isinstance(indirect_result, model.StructOrUnion): + if indirect_result.fldtypes is None: + raise TypeError("'%s' is used as result type, " + "but is opaque" % ( + indirect_result._get_c_name(),)) + indirect_result = model.PointerType(indirect_result) + indirect_args.insert(0, indirect_result) + indirections.insert(0, ("result", indirect_result)) + indirect_result = model.void_type + tp = model.FunctionPtrType(tuple(indirect_args), + indirect_result, tp.ellipsis) + BFunc = self.ffi._get_cached_btype(tp) + wrappername = '_cffi_f_%s' % name + newfunction = module.load_function(BFunc, wrappername) + for i, typ in indirections: + newfunction = self._make_struct_wrapper(newfunction, i, typ, + base_tp) + setattr(library, name, newfunction) + type(library)._cffi_dir.append(name) + + def _make_struct_wrapper(self, oldfunc, i, tp, base_tp): + backend = self.ffi._backend + BType = self.ffi._get_cached_btype(tp) + if i == "result": + ffi = self.ffi + def newfunc(*args): + res = ffi.new(BType) + oldfunc(res, *args) + return res[0] + else: + def newfunc(*args): + args = args[:i] + (backend.newp(BType, args[i]),) + args[i+1:] + return oldfunc(*args) + newfunc._cffi_base_type = base_tp + return newfunc + + # ---------- + # named structs + + def _generate_gen_struct_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'struct', name) + + def _loading_gen_struct(self, tp, name, module): + self._loading_struct_or_union(tp, 'struct', name, module) + + def _loaded_gen_struct(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + def _generate_gen_union_decl(self, tp, name): + assert name == tp.name + self._generate_struct_or_union_decl(tp, 'union', name) + + def _loading_gen_union(self, tp, name, module): + self._loading_struct_or_union(tp, 'union', name, module) + + def _loaded_gen_union(self, tp, name, module, **kwds): + self._loaded_struct_or_union(tp) + + def _generate_struct_or_union_decl(self, tp, prefix, name): + if tp.fldnames is None: + return # nothing to do with opaque structs + checkfuncname = '_cffi_check_%s_%s' % (prefix, name) + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + cname = ('%s %s' % (prefix, name)).strip() + # + prnt = self._prnt + prnt('static void %s(%s *p)' % (checkfuncname, cname)) + prnt('{') + prnt(' /* only to generate compile-time warnings or errors */') + prnt(' (void)p;') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if (isinstance(ftype, model.PrimitiveType) + and ftype.is_integer_type()) or fbitsize >= 0: + # accept all integers, but complain on float or double + prnt(' (void)((p->%s) << 1);' % fname) + else: + # only accept exactly the type declared. + try: + prnt(' { %s = &p->%s; (void)tmp; }' % ( + ftype.get_c_name('*tmp', 'field %r'%fname, quals=fqual), + fname)) + except VerificationError as e: + prnt(' /* %s */' % str(e)) # cannot verify it, ignore + prnt('}') + self.export_symbols.append(layoutfuncname) + prnt('intptr_t %s(intptr_t i)' % (layoutfuncname,)) + prnt('{') + prnt(' struct _cffi_aligncheck { char x; %s y; };' % cname) + prnt(' static intptr_t nums[] = {') + prnt(' sizeof(%s),' % cname) + prnt(' offsetof(struct _cffi_aligncheck, y),') + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + prnt(' offsetof(%s, %s),' % (cname, fname)) + if isinstance(ftype, model.ArrayType) and ftype.length is None: + prnt(' 0, /* %s */' % ftype._get_c_name()) + else: + prnt(' sizeof(((%s *)0)->%s),' % (cname, fname)) + prnt(' -1') + prnt(' };') + prnt(' return nums[i];') + prnt(' /* the next line is not executed, but compiled */') + prnt(' %s(0);' % (checkfuncname,)) + prnt('}') + prnt() + + def _loading_struct_or_union(self, tp, prefix, name, module): + if tp.fldnames is None: + return # nothing to do with opaque structs + layoutfuncname = '_cffi_layout_%s_%s' % (prefix, name) + # + BFunc = self.ffi._typeof_locked("intptr_t(*)(intptr_t)")[0] + function = module.load_function(BFunc, layoutfuncname) + layout = [] + num = 0 + while True: + x = function(num) + if x < 0: break + layout.append(x) + num += 1 + if isinstance(tp, model.StructOrUnion) and tp.partial: + # use the function()'s sizes and offsets to guide the + # layout of the struct + totalsize = layout[0] + totalalignment = layout[1] + fieldofs = layout[2::2] + fieldsize = layout[3::2] + tp.force_flatten() + assert len(fieldofs) == len(fieldsize) == len(tp.fldnames) + tp.fixedlayout = fieldofs, fieldsize, totalsize, totalalignment + else: + cname = ('%s %s' % (prefix, name)).strip() + self._struct_pending_verification[tp] = layout, cname + + def _loaded_struct_or_union(self, tp): + if tp.fldnames is None: + return # nothing to do with opaque structs + self.ffi._get_cached_btype(tp) # force 'fixedlayout' to be considered + + if tp in self._struct_pending_verification: + # check that the layout sizes and offsets match the real ones + def check(realvalue, expectedvalue, msg): + if realvalue != expectedvalue: + raise VerificationError( + "%s (we have %d, but C compiler says %d)" + % (msg, expectedvalue, realvalue)) + ffi = self.ffi + BStruct = ffi._get_cached_btype(tp) + layout, cname = self._struct_pending_verification.pop(tp) + check(layout[0], ffi.sizeof(BStruct), "wrong total size") + check(layout[1], ffi.alignof(BStruct), "wrong total alignment") + i = 2 + for fname, ftype, fbitsize, fqual in tp.enumfields(): + if fbitsize >= 0: + continue # xxx ignore fbitsize for now + check(layout[i], ffi.offsetof(BStruct, fname), + "wrong offset for field %r" % (fname,)) + if layout[i+1] != 0: + BField = ffi._get_cached_btype(ftype) + check(layout[i+1], ffi.sizeof(BField), + "wrong size for field %r" % (fname,)) + i += 2 + assert i == len(layout) + + # ---------- + # 'anonymous' declarations. These are produced for anonymous structs + # or unions; the 'name' is obtained by a typedef. + + def _generate_gen_anonymous_decl(self, tp, name): + if isinstance(tp, model.EnumType): + self._generate_gen_enum_decl(tp, name, '') + else: + self._generate_struct_or_union_decl(tp, '', name) + + def _loading_gen_anonymous(self, tp, name, module): + if isinstance(tp, model.EnumType): + self._loading_gen_enum(tp, name, module, '') + else: + self._loading_struct_or_union(tp, '', name, module) + + def _loaded_gen_anonymous(self, tp, name, module, **kwds): + if isinstance(tp, model.EnumType): + self._loaded_gen_enum(tp, name, module, **kwds) + else: + self._loaded_struct_or_union(tp) + + # ---------- + # constants, likely declared with '#define' + + def _generate_gen_const(self, is_int, name, tp=None, category='const', + check_value=None): + prnt = self._prnt + funcname = '_cffi_%s_%s' % (category, name) + self.export_symbols.append(funcname) + if check_value is not None: + assert is_int + assert category == 'const' + prnt('int %s(char *out_error)' % funcname) + prnt('{') + self._check_int_constant_value(name, check_value) + prnt(' return 0;') + prnt('}') + elif is_int: + assert category == 'const' + prnt('int %s(long long *out_value)' % funcname) + prnt('{') + prnt(' *out_value = (long long)(%s);' % (name,)) + prnt(' return (%s) <= 0;' % (name,)) + prnt('}') + else: + assert tp is not None + assert check_value is None + if category == 'var': + ampersand = '&' + else: + ampersand = '' + extra = '' + if category == 'const' and isinstance(tp, model.StructOrUnion): + extra = 'const *' + ampersand = '&' + prnt(tp.get_c_name(' %s%s(void)' % (extra, funcname), name)) + prnt('{') + prnt(' return (%s%s);' % (ampersand, name)) + prnt('}') + prnt() + + def _generate_gen_constant_decl(self, tp, name): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + self._generate_gen_const(is_int, name, tp) + + _loading_gen_constant = _loaded_noop + + def _load_constant(self, is_int, tp, name, module, check_value=None): + funcname = '_cffi_const_%s' % name + if check_value is not None: + assert is_int + self._load_known_int_constant(module, funcname) + value = check_value + elif is_int: + BType = self.ffi._typeof_locked("long long*")[0] + BFunc = self.ffi._typeof_locked("int(*)(long long*)")[0] + function = module.load_function(BFunc, funcname) + p = self.ffi.new(BType) + negative = function(p) + value = int(p[0]) + if value < 0 and not negative: + BLongLong = self.ffi._typeof_locked("long long")[0] + value += (1 << (8*self.ffi.sizeof(BLongLong))) + else: + assert check_value is None + fntypeextra = '(*)(void)' + if isinstance(tp, model.StructOrUnion): + fntypeextra = '*' + fntypeextra + BFunc = self.ffi._typeof_locked(tp.get_c_name(fntypeextra, name))[0] + function = module.load_function(BFunc, funcname) + value = function() + if isinstance(tp, model.StructOrUnion): + value = value[0] + return value + + def _loaded_gen_constant(self, tp, name, module, library): + is_int = isinstance(tp, model.PrimitiveType) and tp.is_integer_type() + value = self._load_constant(is_int, tp, name, module) + setattr(library, name, value) + type(library)._cffi_dir.append(name) + + # ---------- + # enums + + def _check_int_constant_value(self, name, value): + prnt = self._prnt + if value <= 0: + prnt(' if ((%s) > 0 || (long)(%s) != %dL) {' % ( + name, name, value)) + else: + prnt(' if ((%s) <= 0 || (unsigned long)(%s) != %dUL) {' % ( + name, name, value)) + prnt(' char buf[64];') + prnt(' if ((%s) <= 0)' % name) + prnt(' sprintf(buf, "%%ld", (long)(%s));' % name) + prnt(' else') + prnt(' sprintf(buf, "%%lu", (unsigned long)(%s));' % + name) + prnt(' sprintf(out_error, "%s has the real value %s, not %s",') + prnt(' "%s", buf, "%d");' % (name[:100], value)) + prnt(' return -1;') + prnt(' }') + + def _load_known_int_constant(self, module, funcname): + BType = self.ffi._typeof_locked("char[]")[0] + BFunc = self.ffi._typeof_locked("int(*)(char*)")[0] + function = module.load_function(BFunc, funcname) + p = self.ffi.new(BType, 256) + if function(p) < 0: + error = self.ffi.string(p) + if sys.version_info >= (3,): + error = str(error, 'utf-8') + raise VerificationError(error) + + def _enum_funcname(self, prefix, name): + # "$enum_$1" => "___D_enum____D_1" + name = name.replace('$', '___D_') + return '_cffi_e_%s_%s' % (prefix, name) + + def _generate_gen_enum_decl(self, tp, name, prefix='enum'): + if tp.partial: + for enumerator in tp.enumerators: + self._generate_gen_const(True, enumerator) + return + # + funcname = self._enum_funcname(prefix, name) + self.export_symbols.append(funcname) + prnt = self._prnt + prnt('int %s(char *out_error)' % funcname) + prnt('{') + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + self._check_int_constant_value(enumerator, enumvalue) + prnt(' return 0;') + prnt('}') + prnt() + + def _loading_gen_enum(self, tp, name, module, prefix='enum'): + if tp.partial: + enumvalues = [self._load_constant(True, tp, enumerator, module) + for enumerator in tp.enumerators] + tp.enumvalues = tuple(enumvalues) + tp.partial_resolved = True + else: + funcname = self._enum_funcname(prefix, name) + self._load_known_int_constant(module, funcname) + + def _loaded_gen_enum(self, tp, name, module, library): + for enumerator, enumvalue in zip(tp.enumerators, tp.enumvalues): + setattr(library, enumerator, enumvalue) + type(library)._cffi_dir.append(enumerator) + + # ---------- + # macros: for now only for integers + + def _generate_gen_macro_decl(self, tp, name): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + self._generate_gen_const(True, name, check_value=check_value) + + _loading_gen_macro = _loaded_noop + + def _loaded_gen_macro(self, tp, name, module, library): + if tp == '...': + check_value = None + else: + check_value = tp # an integer + value = self._load_constant(True, tp, name, module, + check_value=check_value) + setattr(library, name, value) + type(library)._cffi_dir.append(name) + + # ---------- + # global variables + + def _generate_gen_variable_decl(self, tp, name): + if isinstance(tp, model.ArrayType): + if tp.length_is_unknown(): + prnt = self._prnt + funcname = '_cffi_sizeof_%s' % (name,) + self.export_symbols.append(funcname) + prnt("size_t %s(void)" % funcname) + prnt("{") + prnt(" return sizeof(%s);" % (name,)) + prnt("}") + tp_ptr = model.PointerType(tp.item) + self._generate_gen_const(False, name, tp_ptr) + else: + tp_ptr = model.PointerType(tp) + self._generate_gen_const(False, name, tp_ptr, category='var') + + _loading_gen_variable = _loaded_noop + + def _loaded_gen_variable(self, tp, name, module, library): + if isinstance(tp, model.ArrayType): # int a[5] is "constant" in the + # sense that "a=..." is forbidden + if tp.length_is_unknown(): + funcname = '_cffi_sizeof_%s' % (name,) + BFunc = self.ffi._typeof_locked('size_t(*)(void)')[0] + function = module.load_function(BFunc, funcname) + size = function() + BItemType = self.ffi._get_cached_btype(tp.item) + length, rest = divmod(size, self.ffi.sizeof(BItemType)) + if rest != 0: + raise VerificationError( + "bad size: %r does not seem to be an array of %s" % + (name, tp.item)) + tp = tp.resolve_length(length) + tp_ptr = model.PointerType(tp.item) + value = self._load_constant(False, tp_ptr, name, module) + # 'value' is a which we have to replace with + # a if the N is actually known + if tp.length is not None: + BArray = self.ffi._get_cached_btype(tp) + value = self.ffi.cast(BArray, value) + setattr(library, name, value) + type(library)._cffi_dir.append(name) + return + # remove ptr= from the library instance, and replace + # it by a property on the class, which reads/writes into ptr[0]. + funcname = '_cffi_var_%s' % name + BFunc = self.ffi._typeof_locked(tp.get_c_name('*(*)(void)', name))[0] + function = module.load_function(BFunc, funcname) + ptr = function() + def getter(library): + return ptr[0] + def setter(library, value): + ptr[0] = value + setattr(type(library), name, property(getter, setter)) + type(library)._cffi_dir.append(name) + +cffimod_header = r''' +#include +#include +#include +#include +#include /* XXX for ssize_t on some platforms */ + +/* this block of #ifs should be kept exactly identical between + c/_cffi_backend.c, cffi/vengine_cpy.py, cffi/vengine_gen.py + and cffi/_cffi_include.h */ +#if defined(_MSC_VER) +# include /* for alloca() */ +# if _MSC_VER < 1600 /* MSVC < 2010 */ + typedef __int8 int8_t; + typedef __int16 int16_t; + typedef __int32 int32_t; + typedef __int64 int64_t; + typedef unsigned __int8 uint8_t; + typedef unsigned __int16 uint16_t; + typedef unsigned __int32 uint32_t; + typedef unsigned __int64 uint64_t; + typedef __int8 int_least8_t; + typedef __int16 int_least16_t; + typedef __int32 int_least32_t; + typedef __int64 int_least64_t; + typedef unsigned __int8 uint_least8_t; + typedef unsigned __int16 uint_least16_t; + typedef unsigned __int32 uint_least32_t; + typedef unsigned __int64 uint_least64_t; + typedef __int8 int_fast8_t; + typedef __int16 int_fast16_t; + typedef __int32 int_fast32_t; + typedef __int64 int_fast64_t; + typedef unsigned __int8 uint_fast8_t; + typedef unsigned __int16 uint_fast16_t; + typedef unsigned __int32 uint_fast32_t; + typedef unsigned __int64 uint_fast64_t; + typedef __int64 intmax_t; + typedef unsigned __int64 uintmax_t; +# else +# include +# endif +# if _MSC_VER < 1800 /* MSVC < 2013 */ +# ifndef __cplusplus + typedef unsigned char _Bool; +# endif +# endif +#else +# include +# if (defined (__SVR4) && defined (__sun)) || defined(_AIX) || defined(__hpux) +# include +# endif +#endif +''' diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cffi/verifier.py b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/verifier.py new file mode 100644 index 000000000..e392a2b7f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cffi/verifier.py @@ -0,0 +1,306 @@ +# +# DEPRECATED: implementation for ffi.verify() +# +import sys, os, binascii, shutil, io +from . import __version_verifier_modules__ +from . import ffiplatform +from .error import VerificationError + +if sys.version_info >= (3, 3): + import importlib.machinery + def _extension_suffixes(): + return importlib.machinery.EXTENSION_SUFFIXES[:] +else: + import imp + def _extension_suffixes(): + return [suffix for suffix, _, type in imp.get_suffixes() + if type == imp.C_EXTENSION] + + +if sys.version_info >= (3,): + NativeIO = io.StringIO +else: + class NativeIO(io.BytesIO): + def write(self, s): + if isinstance(s, unicode): + s = s.encode('ascii') + super(NativeIO, self).write(s) + + +class Verifier(object): + + def __init__(self, ffi, preamble, tmpdir=None, modulename=None, + ext_package=None, tag='', force_generic_engine=False, + source_extension='.c', flags=None, relative_to=None, **kwds): + if ffi._parser._uses_new_feature: + raise VerificationError( + "feature not supported with ffi.verify(), but only " + "with ffi.set_source(): %s" % (ffi._parser._uses_new_feature,)) + self.ffi = ffi + self.preamble = preamble + if not modulename: + flattened_kwds = ffiplatform.flatten(kwds) + vengine_class = _locate_engine_class(ffi, force_generic_engine) + self._vengine = vengine_class(self) + self._vengine.patch_extension_kwds(kwds) + self.flags = flags + self.kwds = self.make_relative_to(kwds, relative_to) + # + if modulename: + if tag: + raise TypeError("can't specify both 'modulename' and 'tag'") + else: + key = '\x00'.join(['%d.%d' % sys.version_info[:2], + __version_verifier_modules__, + preamble, flattened_kwds] + + ffi._cdefsources) + if sys.version_info >= (3,): + key = key.encode('utf-8') + k1 = hex(binascii.crc32(key[0::2]) & 0xffffffff) + k1 = k1.lstrip('0x').rstrip('L') + k2 = hex(binascii.crc32(key[1::2]) & 0xffffffff) + k2 = k2.lstrip('0').rstrip('L') + modulename = '_cffi_%s_%s%s%s' % (tag, self._vengine._class_key, + k1, k2) + suffix = _get_so_suffixes()[0] + self.tmpdir = tmpdir or _caller_dir_pycache() + self.sourcefilename = os.path.join(self.tmpdir, modulename + source_extension) + self.modulefilename = os.path.join(self.tmpdir, modulename + suffix) + self.ext_package = ext_package + self._has_source = False + self._has_module = False + + def write_source(self, file=None): + """Write the C source code. It is produced in 'self.sourcefilename', + which can be tweaked beforehand.""" + with self.ffi._lock: + if self._has_source and file is None: + raise VerificationError( + "source code already written") + self._write_source(file) + + def compile_module(self): + """Write the C source code (if not done already) and compile it. + This produces a dynamic link library in 'self.modulefilename'.""" + with self.ffi._lock: + if self._has_module: + raise VerificationError("module already compiled") + if not self._has_source: + self._write_source() + self._compile_module() + + def load_library(self): + """Get a C module from this Verifier instance. + Returns an instance of a FFILibrary class that behaves like the + objects returned by ffi.dlopen(), but that delegates all + operations to the C module. If necessary, the C code is written + and compiled first. + """ + with self.ffi._lock: + if not self._has_module: + self._locate_module() + if not self._has_module: + if not self._has_source: + self._write_source() + self._compile_module() + return self._load_library() + + def get_module_name(self): + basename = os.path.basename(self.modulefilename) + # kill both the .so extension and the other .'s, as introduced + # by Python 3: 'basename.cpython-33m.so' + basename = basename.split('.', 1)[0] + # and the _d added in Python 2 debug builds --- but try to be + # conservative and not kill a legitimate _d + if basename.endswith('_d') and hasattr(sys, 'gettotalrefcount'): + basename = basename[:-2] + return basename + + def get_extension(self): + if not self._has_source: + with self.ffi._lock: + if not self._has_source: + self._write_source() + sourcename = ffiplatform.maybe_relative_path(self.sourcefilename) + modname = self.get_module_name() + return ffiplatform.get_extension(sourcename, modname, **self.kwds) + + def generates_python_module(self): + return self._vengine._gen_python_module + + def make_relative_to(self, kwds, relative_to): + if relative_to and os.path.dirname(relative_to): + dirname = os.path.dirname(relative_to) + kwds = kwds.copy() + for key in ffiplatform.LIST_OF_FILE_NAMES: + if key in kwds: + lst = kwds[key] + if not isinstance(lst, (list, tuple)): + raise TypeError("keyword '%s' should be a list or tuple" + % (key,)) + lst = [os.path.join(dirname, fn) for fn in lst] + kwds[key] = lst + return kwds + + # ---------- + + def _locate_module(self): + if not os.path.isfile(self.modulefilename): + if self.ext_package: + try: + pkg = __import__(self.ext_package, None, None, ['__doc__']) + except ImportError: + return # cannot import the package itself, give up + # (e.g. it might be called differently before installation) + path = pkg.__path__ + else: + path = None + filename = self._vengine.find_module(self.get_module_name(), path, + _get_so_suffixes()) + if filename is None: + return + self.modulefilename = filename + self._vengine.collect_types() + self._has_module = True + + def _write_source_to(self, file): + self._vengine._f = file + try: + self._vengine.write_source_to_f() + finally: + del self._vengine._f + + def _write_source(self, file=None): + if file is not None: + self._write_source_to(file) + else: + # Write our source file to an in memory file. + f = NativeIO() + self._write_source_to(f) + source_data = f.getvalue() + + # Determine if this matches the current file + if os.path.exists(self.sourcefilename): + with open(self.sourcefilename, "r") as fp: + needs_written = not (fp.read() == source_data) + else: + needs_written = True + + # Actually write the file out if it doesn't match + if needs_written: + _ensure_dir(self.sourcefilename) + with open(self.sourcefilename, "w") as fp: + fp.write(source_data) + + # Set this flag + self._has_source = True + + def _compile_module(self): + # compile this C source + tmpdir = os.path.dirname(self.sourcefilename) + outputfilename = ffiplatform.compile(tmpdir, self.get_extension()) + try: + same = ffiplatform.samefile(outputfilename, self.modulefilename) + except OSError: + same = False + if not same: + _ensure_dir(self.modulefilename) + shutil.move(outputfilename, self.modulefilename) + self._has_module = True + + def _load_library(self): + assert self._has_module + if self.flags is not None: + return self._vengine.load_library(self.flags) + else: + return self._vengine.load_library() + +# ____________________________________________________________ + +_FORCE_GENERIC_ENGINE = False # for tests + +def _locate_engine_class(ffi, force_generic_engine): + if _FORCE_GENERIC_ENGINE: + force_generic_engine = True + if not force_generic_engine: + if '__pypy__' in sys.builtin_module_names: + force_generic_engine = True + else: + try: + import _cffi_backend + except ImportError: + _cffi_backend = '?' + if ffi._backend is not _cffi_backend: + force_generic_engine = True + if force_generic_engine: + from . import vengine_gen + return vengine_gen.VGenericEngine + else: + from . import vengine_cpy + return vengine_cpy.VCPythonEngine + +# ____________________________________________________________ + +_TMPDIR = None + +def _caller_dir_pycache(): + if _TMPDIR: + return _TMPDIR + result = os.environ.get('CFFI_TMPDIR') + if result: + return result + filename = sys._getframe(2).f_code.co_filename + return os.path.abspath(os.path.join(os.path.dirname(filename), + '__pycache__')) + +def set_tmpdir(dirname): + """Set the temporary directory to use instead of __pycache__.""" + global _TMPDIR + _TMPDIR = dirname + +def cleanup_tmpdir(tmpdir=None, keep_so=False): + """Clean up the temporary directory by removing all files in it + called `_cffi_*.{c,so}` as well as the `build` subdirectory.""" + tmpdir = tmpdir or _caller_dir_pycache() + try: + filelist = os.listdir(tmpdir) + except OSError: + return + if keep_so: + suffix = '.c' # only remove .c files + else: + suffix = _get_so_suffixes()[0].lower() + for fn in filelist: + if fn.lower().startswith('_cffi_') and ( + fn.lower().endswith(suffix) or fn.lower().endswith('.c')): + try: + os.unlink(os.path.join(tmpdir, fn)) + except OSError: + pass + clean_dir = [os.path.join(tmpdir, 'build')] + for dir in clean_dir: + try: + for fn in os.listdir(dir): + fn = os.path.join(dir, fn) + if os.path.isdir(fn): + clean_dir.append(fn) + else: + os.unlink(fn) + except OSError: + pass + +def _get_so_suffixes(): + suffixes = _extension_suffixes() + if not suffixes: + # bah, no C_EXTENSION available. Occurs on pypy without cpyext + if sys.platform == 'win32': + suffixes = [".pyd"] + else: + suffixes = [".so"] + + return suffixes + +def _ensure_dir(filename): + dirname = os.path.dirname(filename) + if dirname and not os.path.isdir(dirname): + os.makedirs(dirname) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/INSTALLER b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/LICENSE b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/LICENSE new file mode 100644 index 000000000..ad82355b8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 TAHRI Ahmed R. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/METADATA b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/METADATA new file mode 100644 index 000000000..822550e36 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/METADATA @@ -0,0 +1,683 @@ +Metadata-Version: 2.1 +Name: charset-normalizer +Version: 3.3.2 +Summary: The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet. +Home-page: https://github.com/Ousret/charset_normalizer +Author: Ahmed TAHRI +Author-email: ahmed.tahri@cloudnursery.dev +License: MIT +Project-URL: Bug Reports, https://github.com/Ousret/charset_normalizer/issues +Project-URL: Documentation, https://charset-normalizer.readthedocs.io/en/latest +Keywords: encoding,charset,charset-detector,detector,normalization,unicode,chardet,detect +Classifier: Development Status :: 5 - Production/Stable +Classifier: License :: OSI Approved :: MIT License +Classifier: Intended Audience :: Developers +Classifier: Topic :: Software Development :: Libraries :: Python Modules +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: 3.11 +Classifier: Programming Language :: Python :: 3.12 +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Text Processing :: Linguistic +Classifier: Topic :: Utilities +Classifier: Typing :: Typed +Requires-Python: >=3.7.0 +Description-Content-Type: text/markdown +License-File: LICENSE +Provides-Extra: unicode_backport + +

Charset Detection, for Everyone 👋

+ +

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

+

+ Featured Packages
+ + Static Badge + + + Static Badge + +

+

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

+ +> A library that helps you read text from an unknown charset encoding.
Motivated by `chardet`, +> I'm trying to resolve the issue by taking a new approach. +> All IANA character set names for which the Python core library provides codecs are supported. + +

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

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

+Reading Normalized TextCat Reading Text +

+ +*\*\* : They are clearly using specific code for a specific encoding even if covering most of used one*
+Did you got there because of the logs? See [https://charset-normalizer.readthedocs.io/en/latest/user/miscellaneous.html](https://charset-normalizer.readthedocs.io/en/latest/user/miscellaneous.html) + +## ⚡ Performance + +This package offer better performance than its counterpart Chardet. Here are some numbers. + +| Package | Accuracy | Mean per file (ms) | File per sec (est) | +|-----------------------------------------------|:--------:|:------------------:|:------------------:| +| [chardet](https://github.com/chardet/chardet) | 86 % | 200 ms | 5 file/sec | +| charset-normalizer | **98 %** | **10 ms** | 100 file/sec | + +| Package | 99th percentile | 95th percentile | 50th percentile | +|-----------------------------------------------|:---------------:|:---------------:|:---------------:| +| [chardet](https://github.com/chardet/chardet) | 1200 ms | 287 ms | 23 ms | +| charset-normalizer | 100 ms | 50 ms | 5 ms | + +Chardet's performance on larger file (1MB+) are very poor. Expect huge difference on large payload. + +> Stats are generated using 400+ files using default parameters. More details on used files, see GHA workflows. +> And yes, these results might change at any time. The dataset can be updated to include more files. +> The actual delays heavily depends on your CPU capabilities. The factors should remain the same. +> Keep in mind that the stats are generous and that Chardet accuracy vs our is measured using Chardet initial capability +> (eg. Supported Encoding) Challenge-them if you want. + +## ✨ Installation + +Using pip: + +```sh +pip install charset-normalizer -U +``` + +## 🚀 Basic Usage + +### CLI +This package comes with a CLI. + +``` +usage: normalizer [-h] [-v] [-a] [-n] [-m] [-r] [-f] [-t THRESHOLD] + file [file ...] + +The Real First Universal Charset Detector. Discover originating encoding used +on text file. Normalize text to unicode. + +positional arguments: + files File(s) to be analysed + +optional arguments: + -h, --help show this help message and exit + -v, --verbose Display complementary information about file if any. + Stdout will contain logs about the detection process. + -a, --with-alternative + Output complementary possibilities if any. Top-level + JSON WILL be a list. + -n, --normalize Permit to normalize input file. If not set, program + does not write anything. + -m, --minimal Only output the charset detected to STDOUT. Disabling + JSON output. + -r, --replace Replace file when trying to normalize it instead of + creating a new one. + -f, --force Replace file without asking if you are sure, use this + flag with caution. + -t THRESHOLD, --threshold THRESHOLD + Define a custom maximum amount of chaos allowed in + decoded content. 0. <= chaos <= 1. + --version Show version information and exit. +``` + +```bash +normalizer ./data/sample.1.fr.srt +``` + +or + +```bash +python -m charset_normalizer ./data/sample.1.fr.srt +``` + +🎉 Since version 1.4.0 the CLI produce easily usable stdout result in JSON format. + +```json +{ + "path": "/home/default/projects/charset_normalizer/data/sample.1.fr.srt", + "encoding": "cp1252", + "encoding_aliases": [ + "1252", + "windows_1252" + ], + "alternative_encodings": [ + "cp1254", + "cp1256", + "cp1258", + "iso8859_14", + "iso8859_15", + "iso8859_16", + "iso8859_3", + "iso8859_9", + "latin_1", + "mbcs" + ], + "language": "French", + "alphabets": [ + "Basic Latin", + "Latin-1 Supplement" + ], + "has_sig_or_bom": false, + "chaos": 0.149, + "coherence": 97.152, + "unicode_path": null, + "is_preferred": true +} +``` + +### Python +*Just print out normalized text* +```python +from charset_normalizer import from_path + +results = from_path('./my_subtitle.srt') + +print(str(results.best())) +``` + +*Upgrade your code without effort* +```python +from charset_normalizer import detect +``` + +The above code will behave the same as **chardet**. We ensure that we offer the best (reasonable) BC result possible. + +See the docs for advanced usage : [readthedocs.io](https://charset-normalizer.readthedocs.io/en/latest/) + +## 😇 Why + +When I started using Chardet, I noticed that it was not suited to my expectations, and I wanted to propose a +reliable alternative using a completely different method. Also! I never back down on a good challenge! + +I **don't care** about the **originating charset** encoding, because **two different tables** can +produce **two identical rendered string.** +What I want is to get readable text, the best I can. + +In a way, **I'm brute forcing text decoding.** How cool is that ? 😎 + +Don't confuse package **ftfy** with charset-normalizer or chardet. ftfy goal is to repair unicode string whereas charset-normalizer to convert raw file in unknown encoding to unicode. + +## 🍰 How + + - Discard all charset encoding table that could not fit the binary content. + - Measure noise, or the mess once opened (by chunks) with a corresponding charset encoding. + - Extract matches with the lowest mess detected. + - Additionally, we measure coherence / probe for a language. + +**Wait a minute**, what is noise/mess and coherence according to **YOU ?** + +*Noise :* I opened hundred of text files, **written by humans**, with the wrong encoding table. **I observed**, then +**I established** some ground rules about **what is obvious** when **it seems like** a mess. + I know that my interpretation of what is noise is probably incomplete, feel free to contribute in order to + improve or rewrite it. + +*Coherence :* For each language there is on earth, we have computed ranked letter appearance occurrences (the best we can). So I thought +that intel is worth something here. So I use those records against decoded text to check if I can detect intelligent design. + +## ⚡ Known limitations + + - Language detection is unreliable when text contains two or more languages sharing identical letters. (eg. HTML (english tags) + Turkish content (Sharing Latin characters)) + - Every charset detector heavily depends on sufficient content. In common cases, do not bother run detection on very tiny content. + +## ⚠️ About Python EOLs + +**If you are running:** + +- Python >=2.7,<3.5: Unsupported +- Python 3.5: charset-normalizer < 2.1 +- Python 3.6: charset-normalizer < 3.1 +- Python 3.7: charset-normalizer < 4.0 + +Upgrade your Python interpreter as soon as possible. + +## 👤 Contributing + +Contributions, issues and feature requests are very much welcome.
+Feel free to check [issues page](https://github.com/ousret/charset_normalizer/issues) if you want to contribute. + +## 📝 License + +Copyright © [Ahmed TAHRI @Ousret](https://github.com/Ousret).
+This project is [MIT](https://github.com/Ousret/charset_normalizer/blob/master/LICENSE) licensed. + +Characters frequencies used in this project © 2012 [Denny Vrandečić](http://simia.net/letters/) + +## 💼 For Enterprise + +Professional support for charset-normalizer is available as part of the [Tidelift +Subscription][1]. Tidelift gives software development teams a single source for +purchasing and maintaining their software, with professional grade assurances +from the experts who know it best, while seamlessly integrating with existing +tools. + +[1]: https://tidelift.com/subscription/pkg/pypi-charset-normalizer?utm_source=pypi-charset-normalizer&utm_medium=readme + +# Changelog +All notable changes to charset-normalizer will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## [3.3.2](https://github.com/Ousret/charset_normalizer/compare/3.3.1...3.3.2) (2023-10-31) + +### Fixed +- Unintentional memory usage regression when using large payload that match several encoding (#376) +- Regression on some detection case showcased in the documentation (#371) + +### Added +- Noise (md) probe that identify malformed arabic representation due to the presence of letters in isolated form (credit to my wife) + +## [3.3.1](https://github.com/Ousret/charset_normalizer/compare/3.3.0...3.3.1) (2023-10-22) + +### Changed +- Optional mypyc compilation upgraded to version 1.6.1 for Python >= 3.8 +- Improved the general detection reliability based on reports from the community + +## [3.3.0](https://github.com/Ousret/charset_normalizer/compare/3.2.0...3.3.0) (2023-09-30) + +### Added +- Allow to execute the CLI (e.g. normalizer) through `python -m charset_normalizer.cli` or `python -m charset_normalizer` +- Support for 9 forgotten encoding that are supported by Python but unlisted in `encoding.aliases` as they have no alias (#323) + +### Removed +- (internal) Redundant utils.is_ascii function and unused function is_private_use_only +- (internal) charset_normalizer.assets is moved inside charset_normalizer.constant + +### Changed +- (internal) Unicode code blocks in constants are updated using the latest v15.0.0 definition to improve detection +- Optional mypyc compilation upgraded to version 1.5.1 for Python >= 3.8 + +### Fixed +- Unable to properly sort CharsetMatch when both chaos/noise and coherence were close due to an unreachable condition in \_\_lt\_\_ (#350) + +## [3.2.0](https://github.com/Ousret/charset_normalizer/compare/3.1.0...3.2.0) (2023-06-07) + +### Changed +- Typehint for function `from_path` no longer enforce `PathLike` as its first argument +- Minor improvement over the global detection reliability + +### Added +- Introduce function `is_binary` that relies on main capabilities, and optimized to detect binaries +- Propagate `enable_fallback` argument throughout `from_bytes`, `from_path`, and `from_fp` that allow a deeper control over the detection (default True) +- Explicit support for Python 3.12 + +### Fixed +- Edge case detection failure where a file would contain 'very-long' camel cased word (Issue #289) + +## [3.1.0](https://github.com/Ousret/charset_normalizer/compare/3.0.1...3.1.0) (2023-03-06) + +### Added +- Argument `should_rename_legacy` for legacy function `detect` and disregard any new arguments without errors (PR #262) + +### Removed +- Support for Python 3.6 (PR #260) + +### Changed +- Optional speedup provided by mypy/c 1.0.1 + +## [3.0.1](https://github.com/Ousret/charset_normalizer/compare/3.0.0...3.0.1) (2022-11-18) + +### Fixed +- Multi-bytes cutter/chunk generator did not always cut correctly (PR #233) + +### Changed +- Speedup provided by mypy/c 0.990 on Python >= 3.7 + +## [3.0.0](https://github.com/Ousret/charset_normalizer/compare/2.1.1...3.0.0) (2022-10-20) + +### Added +- Extend the capability of explain=True when cp_isolation contains at most two entries (min one), will log in details of the Mess-detector results +- Support for alternative language frequency set in charset_normalizer.assets.FREQUENCIES +- Add parameter `language_threshold` in `from_bytes`, `from_path` and `from_fp` to adjust the minimum expected coherence ratio +- `normalizer --version` now specify if current version provide extra speedup (meaning mypyc compilation whl) + +### Changed +- Build with static metadata using 'build' frontend +- Make the language detection stricter +- Optional: Module `md.py` can be compiled using Mypyc to provide an extra speedup up to 4x faster than v2.1 + +### Fixed +- CLI with opt --normalize fail when using full path for files +- TooManyAccentuatedPlugin induce false positive on the mess detection when too few alpha character have been fed to it +- Sphinx warnings when generating the documentation + +### Removed +- Coherence detector no longer return 'Simple English' instead return 'English' +- Coherence detector no longer return 'Classical Chinese' instead return 'Chinese' +- Breaking: Method `first()` and `best()` from CharsetMatch +- UTF-7 will no longer appear as "detected" without a recognized SIG/mark (is unreliable/conflict with ASCII) +- Breaking: Class aliases CharsetDetector, CharsetDoctor, CharsetNormalizerMatch and CharsetNormalizerMatches +- Breaking: Top-level function `normalize` +- Breaking: Properties `chaos_secondary_pass`, `coherence_non_latin` and `w_counter` from CharsetMatch +- Support for the backport `unicodedata2` + +## [3.0.0rc1](https://github.com/Ousret/charset_normalizer/compare/3.0.0b2...3.0.0rc1) (2022-10-18) + +### Added +- Extend the capability of explain=True when cp_isolation contains at most two entries (min one), will log in details of the Mess-detector results +- Support for alternative language frequency set in charset_normalizer.assets.FREQUENCIES +- Add parameter `language_threshold` in `from_bytes`, `from_path` and `from_fp` to adjust the minimum expected coherence ratio + +### Changed +- Build with static metadata using 'build' frontend +- Make the language detection stricter + +### Fixed +- CLI with opt --normalize fail when using full path for files +- TooManyAccentuatedPlugin induce false positive on the mess detection when too few alpha character have been fed to it + +### Removed +- Coherence detector no longer return 'Simple English' instead return 'English' +- Coherence detector no longer return 'Classical Chinese' instead return 'Chinese' + +## [3.0.0b2](https://github.com/Ousret/charset_normalizer/compare/3.0.0b1...3.0.0b2) (2022-08-21) + +### Added +- `normalizer --version` now specify if current version provide extra speedup (meaning mypyc compilation whl) + +### Removed +- Breaking: Method `first()` and `best()` from CharsetMatch +- UTF-7 will no longer appear as "detected" without a recognized SIG/mark (is unreliable/conflict with ASCII) + +### Fixed +- Sphinx warnings when generating the documentation + +## [3.0.0b1](https://github.com/Ousret/charset_normalizer/compare/2.1.0...3.0.0b1) (2022-08-15) + +### Changed +- Optional: Module `md.py` can be compiled using Mypyc to provide an extra speedup up to 4x faster than v2.1 + +### Removed +- Breaking: Class aliases CharsetDetector, CharsetDoctor, CharsetNormalizerMatch and CharsetNormalizerMatches +- Breaking: Top-level function `normalize` +- Breaking: Properties `chaos_secondary_pass`, `coherence_non_latin` and `w_counter` from CharsetMatch +- Support for the backport `unicodedata2` + +## [2.1.1](https://github.com/Ousret/charset_normalizer/compare/2.1.0...2.1.1) (2022-08-19) + +### Deprecated +- Function `normalize` scheduled for removal in 3.0 + +### Changed +- Removed useless call to decode in fn is_unprintable (#206) + +### Fixed +- Third-party library (i18n xgettext) crashing not recognizing utf_8 (PEP 263) with underscore from [@aleksandernovikov](https://github.com/aleksandernovikov) (#204) + +## [2.1.0](https://github.com/Ousret/charset_normalizer/compare/2.0.12...2.1.0) (2022-06-19) + +### Added +- Output the Unicode table version when running the CLI with `--version` (PR #194) + +### Changed +- Re-use decoded buffer for single byte character sets from [@nijel](https://github.com/nijel) (PR #175) +- Fixing some performance bottlenecks from [@deedy5](https://github.com/deedy5) (PR #183) + +### Fixed +- Workaround potential bug in cpython with Zero Width No-Break Space located in Arabic Presentation Forms-B, Unicode 1.1 not acknowledged as space (PR #175) +- CLI default threshold aligned with the API threshold from [@oleksandr-kuzmenko](https://github.com/oleksandr-kuzmenko) (PR #181) + +### Removed +- Support for Python 3.5 (PR #192) + +### Deprecated +- Use of backport unicodedata from `unicodedata2` as Python is quickly catching up, scheduled for removal in 3.0 (PR #194) + +## [2.0.12](https://github.com/Ousret/charset_normalizer/compare/2.0.11...2.0.12) (2022-02-12) + +### Fixed +- ASCII miss-detection on rare cases (PR #170) + +## [2.0.11](https://github.com/Ousret/charset_normalizer/compare/2.0.10...2.0.11) (2022-01-30) + +### Added +- Explicit support for Python 3.11 (PR #164) + +### Changed +- The logging behavior have been completely reviewed, now using only TRACE and DEBUG levels (PR #163 #165) + +## [2.0.10](https://github.com/Ousret/charset_normalizer/compare/2.0.9...2.0.10) (2022-01-04) + +### Fixed +- Fallback match entries might lead to UnicodeDecodeError for large bytes sequence (PR #154) + +### Changed +- Skipping the language-detection (CD) on ASCII (PR #155) + +## [2.0.9](https://github.com/Ousret/charset_normalizer/compare/2.0.8...2.0.9) (2021-12-03) + +### Changed +- Moderating the logging impact (since 2.0.8) for specific environments (PR #147) + +### Fixed +- Wrong logging level applied when setting kwarg `explain` to True (PR #146) + +## [2.0.8](https://github.com/Ousret/charset_normalizer/compare/2.0.7...2.0.8) (2021-11-24) +### Changed +- Improvement over Vietnamese detection (PR #126) +- MD improvement on trailing data and long foreign (non-pure latin) data (PR #124) +- Efficiency improvements in cd/alphabet_languages from [@adbar](https://github.com/adbar) (PR #122) +- call sum() without an intermediary list following PEP 289 recommendations from [@adbar](https://github.com/adbar) (PR #129) +- Code style as refactored by Sourcery-AI (PR #131) +- Minor adjustment on the MD around european words (PR #133) +- Remove and replace SRTs from assets / tests (PR #139) +- Initialize the library logger with a `NullHandler` by default from [@nmaynes](https://github.com/nmaynes) (PR #135) +- Setting kwarg `explain` to True will add provisionally (bounded to function lifespan) a specific stream handler (PR #135) + +### Fixed +- Fix large (misleading) sequence giving UnicodeDecodeError (PR #137) +- Avoid using too insignificant chunk (PR #137) + +### Added +- Add and expose function `set_logging_handler` to configure a specific StreamHandler from [@nmaynes](https://github.com/nmaynes) (PR #135) +- Add `CHANGELOG.md` entries, format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) (PR #141) + +## [2.0.7](https://github.com/Ousret/charset_normalizer/compare/2.0.6...2.0.7) (2021-10-11) +### Added +- Add support for Kazakh (Cyrillic) language detection (PR #109) + +### Changed +- Further, improve inferring the language from a given single-byte code page (PR #112) +- Vainly trying to leverage PEP263 when PEP3120 is not supported (PR #116) +- Refactoring for potential performance improvements in loops from [@adbar](https://github.com/adbar) (PR #113) +- Various detection improvement (MD+CD) (PR #117) + +### Removed +- Remove redundant logging entry about detected language(s) (PR #115) + +### Fixed +- Fix a minor inconsistency between Python 3.5 and other versions regarding language detection (PR #117 #102) + +## [2.0.6](https://github.com/Ousret/charset_normalizer/compare/2.0.5...2.0.6) (2021-09-18) +### Fixed +- Unforeseen regression with the loss of the backward-compatibility with some older minor of Python 3.5.x (PR #100) +- Fix CLI crash when using --minimal output in certain cases (PR #103) + +### Changed +- Minor improvement to the detection efficiency (less than 1%) (PR #106 #101) + +## [2.0.5](https://github.com/Ousret/charset_normalizer/compare/2.0.4...2.0.5) (2021-09-14) +### Changed +- The project now comply with: flake8, mypy, isort and black to ensure a better overall quality (PR #81) +- The BC-support with v1.x was improved, the old staticmethods are restored (PR #82) +- The Unicode detection is slightly improved (PR #93) +- Add syntax sugar \_\_bool\_\_ for results CharsetMatches list-container (PR #91) + +### Removed +- The project no longer raise warning on tiny content given for detection, will be simply logged as warning instead (PR #92) + +### Fixed +- In some rare case, the chunks extractor could cut in the middle of a multi-byte character and could mislead the mess detection (PR #95) +- Some rare 'space' characters could trip up the UnprintablePlugin/Mess detection (PR #96) +- The MANIFEST.in was not exhaustive (PR #78) + +## [2.0.4](https://github.com/Ousret/charset_normalizer/compare/2.0.3...2.0.4) (2021-07-30) +### Fixed +- The CLI no longer raise an unexpected exception when no encoding has been found (PR #70) +- Fix accessing the 'alphabets' property when the payload contains surrogate characters (PR #68) +- The logger could mislead (explain=True) on detected languages and the impact of one MBCS match (PR #72) +- Submatch factoring could be wrong in rare edge cases (PR #72) +- Multiple files given to the CLI were ignored when publishing results to STDOUT. (After the first path) (PR #72) +- Fix line endings from CRLF to LF for certain project files (PR #67) + +### Changed +- Adjust the MD to lower the sensitivity, thus improving the global detection reliability (PR #69 #76) +- Allow fallback on specified encoding if any (PR #71) + +## [2.0.3](https://github.com/Ousret/charset_normalizer/compare/2.0.2...2.0.3) (2021-07-16) +### Changed +- Part of the detection mechanism has been improved to be less sensitive, resulting in more accurate detection results. Especially ASCII. (PR #63) +- According to the community wishes, the detection will fall back on ASCII or UTF-8 in a last-resort case. (PR #64) + +## [2.0.2](https://github.com/Ousret/charset_normalizer/compare/2.0.1...2.0.2) (2021-07-15) +### Fixed +- Empty/Too small JSON payload miss-detection fixed. Report from [@tseaver](https://github.com/tseaver) (PR #59) + +### Changed +- Don't inject unicodedata2 into sys.modules from [@akx](https://github.com/akx) (PR #57) + +## [2.0.1](https://github.com/Ousret/charset_normalizer/compare/2.0.0...2.0.1) (2021-07-13) +### Fixed +- Make it work where there isn't a filesystem available, dropping assets frequencies.json. Report from [@sethmlarson](https://github.com/sethmlarson). (PR #55) +- Using explain=False permanently disable the verbose output in the current runtime (PR #47) +- One log entry (language target preemptive) was not show in logs when using explain=True (PR #47) +- Fix undesired exception (ValueError) on getitem of instance CharsetMatches (PR #52) + +### Changed +- Public function normalize default args values were not aligned with from_bytes (PR #53) + +### Added +- You may now use charset aliases in cp_isolation and cp_exclusion arguments (PR #47) + +## [2.0.0](https://github.com/Ousret/charset_normalizer/compare/1.4.1...2.0.0) (2021-07-02) +### Changed +- 4x to 5 times faster than the previous 1.4.0 release. At least 2x faster than Chardet. +- Accent has been made on UTF-8 detection, should perform rather instantaneous. +- The backward compatibility with Chardet has been greatly improved. The legacy detect function returns an identical charset name whenever possible. +- The detection mechanism has been slightly improved, now Turkish content is detected correctly (most of the time) +- The program has been rewritten to ease the readability and maintainability. (+Using static typing)+ +- utf_7 detection has been reinstated. + +### Removed +- This package no longer require anything when used with Python 3.5 (Dropped cached_property) +- Removed support for these languages: Catalan, Esperanto, Kazakh, Baque, Volapük, Azeri, Galician, Nynorsk, Macedonian, and Serbocroatian. +- The exception hook on UnicodeDecodeError has been removed. + +### Deprecated +- Methods coherence_non_latin, w_counter, chaos_secondary_pass of the class CharsetMatch are now deprecated and scheduled for removal in v3.0 + +### Fixed +- The CLI output used the relative path of the file(s). Should be absolute. + +## [1.4.1](https://github.com/Ousret/charset_normalizer/compare/1.4.0...1.4.1) (2021-05-28) +### Fixed +- Logger configuration/usage no longer conflict with others (PR #44) + +## [1.4.0](https://github.com/Ousret/charset_normalizer/compare/1.3.9...1.4.0) (2021-05-21) +### Removed +- Using standard logging instead of using the package loguru. +- Dropping nose test framework in favor of the maintained pytest. +- Choose to not use dragonmapper package to help with gibberish Chinese/CJK text. +- Require cached_property only for Python 3.5 due to constraint. Dropping for every other interpreter version. +- Stop support for UTF-7 that does not contain a SIG. +- Dropping PrettyTable, replaced with pure JSON output in CLI. + +### Fixed +- BOM marker in a CharsetNormalizerMatch instance could be False in rare cases even if obviously present. Due to the sub-match factoring process. +- Not searching properly for the BOM when trying utf32/16 parent codec. + +### Changed +- Improving the package final size by compressing frequencies.json. +- Huge improvement over the larges payload. + +### Added +- CLI now produces JSON consumable output. +- Return ASCII if given sequences fit. Given reasonable confidence. + +## [1.3.9](https://github.com/Ousret/charset_normalizer/compare/1.3.8...1.3.9) (2021-05-13) + +### Fixed +- In some very rare cases, you may end up getting encode/decode errors due to a bad bytes payload (PR #40) + +## [1.3.8](https://github.com/Ousret/charset_normalizer/compare/1.3.7...1.3.8) (2021-05-12) + +### Fixed +- Empty given payload for detection may cause an exception if trying to access the `alphabets` property. (PR #39) + +## [1.3.7](https://github.com/Ousret/charset_normalizer/compare/1.3.6...1.3.7) (2021-05-12) + +### Fixed +- The legacy detect function should return UTF-8-SIG if sig is present in the payload. (PR #38) + +## [1.3.6](https://github.com/Ousret/charset_normalizer/compare/1.3.5...1.3.6) (2021-02-09) + +### Changed +- Amend the previous release to allow prettytable 2.0 (PR #35) + +## [1.3.5](https://github.com/Ousret/charset_normalizer/compare/1.3.4...1.3.5) (2021-02-08) + +### Fixed +- Fix error while using the package with a python pre-release interpreter (PR #33) + +### Changed +- Dependencies refactoring, constraints revised. + +### Added +- Add python 3.9 and 3.10 to the supported interpreters + +MIT License + +Copyright (c) 2019 TAHRI Ahmed R. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/RECORD b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/RECORD new file mode 100644 index 000000000..dd4cd6204 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/RECORD @@ -0,0 +1,35 @@ +../../../bin/normalizer,sha256=YpoRsavC2qLLx_Yy98A6U7KDeAQGX5Zn5K8__uHL9Hc,290 +charset_normalizer-3.3.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +charset_normalizer-3.3.2.dist-info/LICENSE,sha256=6zGgxaT7Cbik4yBV0lweX5w1iidS_vPNcgIT0cz-4kE,1070 +charset_normalizer-3.3.2.dist-info/METADATA,sha256=cfLhl5A6SI-F0oclm8w8ux9wshL1nipdeCdVnYb4AaA,33550 +charset_normalizer-3.3.2.dist-info/RECORD,, +charset_normalizer-3.3.2.dist-info/WHEEL,sha256=48wUIcZcdQ2pWN7qt0HP02Cvv6HIQZGsSgx3PsepNj8,152 +charset_normalizer-3.3.2.dist-info/entry_points.txt,sha256=ADSTKrkXZ3hhdOVFi6DcUEHQRS0xfxDIE_pEz4wLIXA,65 +charset_normalizer-3.3.2.dist-info/top_level.txt,sha256=7ASyzePr8_xuZWJsnqJjIBtyV8vhEo0wBCv1MPRRi3Q,19 +charset_normalizer/__init__.py,sha256=UzI3xC8PhmcLRMzSgPb6minTmRq0kWznnCBJ8ZCc2XI,1577 +charset_normalizer/__main__.py,sha256=JxY8bleaENOFlLRb9HfoeZCzAMnn2A1oGR5Xm2eyqg0,73 +charset_normalizer/__pycache__/__init__.cpython-311.pyc,, +charset_normalizer/__pycache__/__main__.cpython-311.pyc,, +charset_normalizer/__pycache__/api.cpython-311.pyc,, +charset_normalizer/__pycache__/cd.cpython-311.pyc,, +charset_normalizer/__pycache__/constant.cpython-311.pyc,, +charset_normalizer/__pycache__/legacy.cpython-311.pyc,, +charset_normalizer/__pycache__/md.cpython-311.pyc,, +charset_normalizer/__pycache__/models.cpython-311.pyc,, +charset_normalizer/__pycache__/utils.cpython-311.pyc,, +charset_normalizer/__pycache__/version.cpython-311.pyc,, +charset_normalizer/api.py,sha256=WOlWjy6wT8SeMYFpaGbXZFN1TMXa-s8vZYfkL4G29iQ,21097 +charset_normalizer/cd.py,sha256=xwZliZcTQFA3jU0c00PRiu9MNxXTFxQkFLWmMW24ZzI,12560 +charset_normalizer/cli/__init__.py,sha256=D5ERp8P62llm2FuoMzydZ7d9rs8cvvLXqE-1_6oViPc,100 +charset_normalizer/cli/__main__.py,sha256=2F-xURZJzo063Ye-2RLJ2wcmURpbKeAzKwpiws65dAs,9744 +charset_normalizer/cli/__pycache__/__init__.cpython-311.pyc,, +charset_normalizer/cli/__pycache__/__main__.cpython-311.pyc,, +charset_normalizer/constant.py,sha256=p0IsOVcEbPWYPOdWhnhRbjK1YVBy6fs05C5vKC-zoxU,40481 +charset_normalizer/legacy.py,sha256=T-QuVMsMeDiQEk8WSszMrzVJg_14AMeSkmHdRYhdl1k,2071 +charset_normalizer/md.cpython-311-x86_64-linux-gnu.so,sha256=Y7QSLD5QLoSFAWys0-tL7R6QB7oi5864zM6zr7RWek4,16064 +charset_normalizer/md.py,sha256=NkSuVLK13_a8c7BxZ4cGIQ5vOtGIWOdh22WZEvjp-7U,19624 +charset_normalizer/md__mypyc.cpython-311-x86_64-linux-gnu.so,sha256=93T0C_hoJxReTevc7NpjM7P7fae_U-scv5B-AhkKKtY,264392 +charset_normalizer/models.py,sha256=I5i0s4aKCCgLPY2tUY3pwkgFA-BUbbNxQ7hVkVTt62s,11624 +charset_normalizer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +charset_normalizer/utils.py,sha256=teiosMqzKjXyAHXnGdjSBOgnBZwx-SkBbCLrx0UXy8M,11894 +charset_normalizer/version.py,sha256=iHKUfHD3kDRSyrh_BN2ojh43TA5-UZQjvbVIEFfpHDs,79 diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/WHEEL b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/WHEEL new file mode 100644 index 000000000..6919a7b65 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.41.2) +Root-Is-Purelib: false +Tag: cp311-cp311-manylinux_2_17_x86_64 +Tag: cp311-cp311-manylinux2014_x86_64 + diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/entry_points.txt b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/entry_points.txt new file mode 100644 index 000000000..65619e73e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +normalizer = charset_normalizer.cli:cli_detect diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/top_level.txt b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/top_level.txt new file mode 100644 index 000000000..66958f0a0 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer-3.3.2.dist-info/top_level.txt @@ -0,0 +1 @@ +charset_normalizer diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/__init__.py new file mode 100644 index 000000000..55991fc38 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/__init__.py @@ -0,0 +1,46 @@ +# -*- coding: utf-8 -*- +""" +Charset-Normalizer +~~~~~~~~~~~~~~ +The Real First Universal Charset Detector. +A library that helps you read text from an unknown charset encoding. +Motivated by chardet, This package is trying to resolve the issue by taking a new approach. +All IANA character set names for which the Python core library provides codecs are supported. + +Basic usage: + >>> from charset_normalizer import from_bytes + >>> results = from_bytes('Bсеки човек има право на образование. Oбразованието!'.encode('utf_8')) + >>> best_guess = results.best() + >>> str(best_guess) + 'Bсеки човек има право на образование. Oбразованието!' + +Others methods and usages are available - see the full documentation +at . +:copyright: (c) 2021 by Ahmed TAHRI +:license: MIT, see LICENSE for more details. +""" +import logging + +from .api import from_bytes, from_fp, from_path, is_binary +from .legacy import detect +from .models import CharsetMatch, CharsetMatches +from .utils import set_logging_handler +from .version import VERSION, __version__ + +__all__ = ( + "from_fp", + "from_path", + "from_bytes", + "is_binary", + "detect", + "CharsetMatch", + "CharsetMatches", + "__version__", + "VERSION", + "set_logging_handler", +) + +# Attach a NullHandler to the top level logger by default +# https://docs.python.org/3.3/howto/logging.html#configuring-logging-for-a-library + +logging.getLogger("charset_normalizer").addHandler(logging.NullHandler()) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/__main__.py b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/__main__.py new file mode 100644 index 000000000..beae2ef77 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/__main__.py @@ -0,0 +1,4 @@ +from .cli import cli_detect + +if __name__ == "__main__": + cli_detect() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/api.py b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/api.py new file mode 100644 index 000000000..0ba08e3a5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/api.py @@ -0,0 +1,626 @@ +import logging +from os import PathLike +from typing import BinaryIO, List, Optional, Set, Union + +from .cd import ( + coherence_ratio, + encoding_languages, + mb_encoding_languages, + merge_coherence_ratios, +) +from .constant import IANA_SUPPORTED, TOO_BIG_SEQUENCE, TOO_SMALL_SEQUENCE, TRACE +from .md import mess_ratio +from .models import CharsetMatch, CharsetMatches +from .utils import ( + any_specified_encoding, + cut_sequence_chunks, + iana_name, + identify_sig_or_bom, + is_cp_similar, + is_multi_byte_encoding, + should_strip_sig_or_bom, +) + +# Will most likely be controversial +# logging.addLevelName(TRACE, "TRACE") +logger = logging.getLogger("charset_normalizer") +explain_handler = logging.StreamHandler() +explain_handler.setFormatter( + logging.Formatter("%(asctime)s | %(levelname)s | %(message)s") +) + + +def from_bytes( + sequences: Union[bytes, bytearray], + steps: int = 5, + chunk_size: int = 512, + threshold: float = 0.2, + cp_isolation: Optional[List[str]] = None, + cp_exclusion: Optional[List[str]] = None, + preemptive_behaviour: bool = True, + explain: bool = False, + language_threshold: float = 0.1, + enable_fallback: bool = True, +) -> CharsetMatches: + """ + Given a raw bytes sequence, return the best possibles charset usable to render str objects. + If there is no results, it is a strong indicator that the source is binary/not text. + By default, the process will extract 5 blocks of 512o each to assess the mess and coherence of a given sequence. + And will give up a particular code page after 20% of measured mess. Those criteria are customizable at will. + + The preemptive behavior DOES NOT replace the traditional detection workflow, it prioritize a particular code page + but never take it for granted. Can improve the performance. + + You may want to focus your attention to some code page or/and not others, use cp_isolation and cp_exclusion for that + purpose. + + This function will strip the SIG in the payload/sequence every time except on UTF-16, UTF-32. + By default the library does not setup any handler other than the NullHandler, if you choose to set the 'explain' + toggle to True it will alter the logger configuration to add a StreamHandler that is suitable for debugging. + Custom logging format and handler can be set manually. + """ + + if not isinstance(sequences, (bytearray, bytes)): + raise TypeError( + "Expected object of type bytes or bytearray, got: {0}".format( + type(sequences) + ) + ) + + if explain: + previous_logger_level: int = logger.level + logger.addHandler(explain_handler) + logger.setLevel(TRACE) + + length: int = len(sequences) + + if length == 0: + logger.debug("Encoding detection on empty bytes, assuming utf_8 intention.") + if explain: + logger.removeHandler(explain_handler) + logger.setLevel(previous_logger_level or logging.WARNING) + return CharsetMatches([CharsetMatch(sequences, "utf_8", 0.0, False, [], "")]) + + if cp_isolation is not None: + logger.log( + TRACE, + "cp_isolation is set. use this flag for debugging purpose. " + "limited list of encoding allowed : %s.", + ", ".join(cp_isolation), + ) + cp_isolation = [iana_name(cp, False) for cp in cp_isolation] + else: + cp_isolation = [] + + if cp_exclusion is not None: + logger.log( + TRACE, + "cp_exclusion is set. use this flag for debugging purpose. " + "limited list of encoding excluded : %s.", + ", ".join(cp_exclusion), + ) + cp_exclusion = [iana_name(cp, False) for cp in cp_exclusion] + else: + cp_exclusion = [] + + if length <= (chunk_size * steps): + logger.log( + TRACE, + "override steps (%i) and chunk_size (%i) as content does not fit (%i byte(s) given) parameters.", + steps, + chunk_size, + length, + ) + steps = 1 + chunk_size = length + + if steps > 1 and length / steps < chunk_size: + chunk_size = int(length / steps) + + is_too_small_sequence: bool = len(sequences) < TOO_SMALL_SEQUENCE + is_too_large_sequence: bool = len(sequences) >= TOO_BIG_SEQUENCE + + if is_too_small_sequence: + logger.log( + TRACE, + "Trying to detect encoding from a tiny portion of ({}) byte(s).".format( + length + ), + ) + elif is_too_large_sequence: + logger.log( + TRACE, + "Using lazy str decoding because the payload is quite large, ({}) byte(s).".format( + length + ), + ) + + prioritized_encodings: List[str] = [] + + specified_encoding: Optional[str] = ( + any_specified_encoding(sequences) if preemptive_behaviour else None + ) + + if specified_encoding is not None: + prioritized_encodings.append(specified_encoding) + logger.log( + TRACE, + "Detected declarative mark in sequence. Priority +1 given for %s.", + specified_encoding, + ) + + tested: Set[str] = set() + tested_but_hard_failure: List[str] = [] + tested_but_soft_failure: List[str] = [] + + fallback_ascii: Optional[CharsetMatch] = None + fallback_u8: Optional[CharsetMatch] = None + fallback_specified: Optional[CharsetMatch] = None + + results: CharsetMatches = CharsetMatches() + + sig_encoding, sig_payload = identify_sig_or_bom(sequences) + + if sig_encoding is not None: + prioritized_encodings.append(sig_encoding) + logger.log( + TRACE, + "Detected a SIG or BOM mark on first %i byte(s). Priority +1 given for %s.", + len(sig_payload), + sig_encoding, + ) + + prioritized_encodings.append("ascii") + + if "utf_8" not in prioritized_encodings: + prioritized_encodings.append("utf_8") + + for encoding_iana in prioritized_encodings + IANA_SUPPORTED: + if cp_isolation and encoding_iana not in cp_isolation: + continue + + if cp_exclusion and encoding_iana in cp_exclusion: + continue + + if encoding_iana in tested: + continue + + tested.add(encoding_iana) + + decoded_payload: Optional[str] = None + bom_or_sig_available: bool = sig_encoding == encoding_iana + strip_sig_or_bom: bool = bom_or_sig_available and should_strip_sig_or_bom( + encoding_iana + ) + + if encoding_iana in {"utf_16", "utf_32"} and not bom_or_sig_available: + logger.log( + TRACE, + "Encoding %s won't be tested as-is because it require a BOM. Will try some sub-encoder LE/BE.", + encoding_iana, + ) + continue + if encoding_iana in {"utf_7"} and not bom_or_sig_available: + logger.log( + TRACE, + "Encoding %s won't be tested as-is because detection is unreliable without BOM/SIG.", + encoding_iana, + ) + continue + + try: + is_multi_byte_decoder: bool = is_multi_byte_encoding(encoding_iana) + except (ModuleNotFoundError, ImportError): + logger.log( + TRACE, + "Encoding %s does not provide an IncrementalDecoder", + encoding_iana, + ) + continue + + try: + if is_too_large_sequence and is_multi_byte_decoder is False: + str( + sequences[: int(50e4)] + if strip_sig_or_bom is False + else sequences[len(sig_payload) : int(50e4)], + encoding=encoding_iana, + ) + else: + decoded_payload = str( + sequences + if strip_sig_or_bom is False + else sequences[len(sig_payload) :], + encoding=encoding_iana, + ) + except (UnicodeDecodeError, LookupError) as e: + if not isinstance(e, LookupError): + logger.log( + TRACE, + "Code page %s does not fit given bytes sequence at ALL. %s", + encoding_iana, + str(e), + ) + tested_but_hard_failure.append(encoding_iana) + continue + + similar_soft_failure_test: bool = False + + for encoding_soft_failed in tested_but_soft_failure: + if is_cp_similar(encoding_iana, encoding_soft_failed): + similar_soft_failure_test = True + break + + if similar_soft_failure_test: + logger.log( + TRACE, + "%s is deemed too similar to code page %s and was consider unsuited already. Continuing!", + encoding_iana, + encoding_soft_failed, + ) + continue + + r_ = range( + 0 if not bom_or_sig_available else len(sig_payload), + length, + int(length / steps), + ) + + multi_byte_bonus: bool = ( + is_multi_byte_decoder + and decoded_payload is not None + and len(decoded_payload) < length + ) + + if multi_byte_bonus: + logger.log( + TRACE, + "Code page %s is a multi byte encoding table and it appear that at least one character " + "was encoded using n-bytes.", + encoding_iana, + ) + + max_chunk_gave_up: int = int(len(r_) / 4) + + max_chunk_gave_up = max(max_chunk_gave_up, 2) + early_stop_count: int = 0 + lazy_str_hard_failure = False + + md_chunks: List[str] = [] + md_ratios = [] + + try: + for chunk in cut_sequence_chunks( + sequences, + encoding_iana, + r_, + chunk_size, + bom_or_sig_available, + strip_sig_or_bom, + sig_payload, + is_multi_byte_decoder, + decoded_payload, + ): + md_chunks.append(chunk) + + md_ratios.append( + mess_ratio( + chunk, + threshold, + explain is True and 1 <= len(cp_isolation) <= 2, + ) + ) + + if md_ratios[-1] >= threshold: + early_stop_count += 1 + + if (early_stop_count >= max_chunk_gave_up) or ( + bom_or_sig_available and strip_sig_or_bom is False + ): + break + except ( + UnicodeDecodeError + ) as e: # Lazy str loading may have missed something there + logger.log( + TRACE, + "LazyStr Loading: After MD chunk decode, code page %s does not fit given bytes sequence at ALL. %s", + encoding_iana, + str(e), + ) + early_stop_count = max_chunk_gave_up + lazy_str_hard_failure = True + + # We might want to check the sequence again with the whole content + # Only if initial MD tests passes + if ( + not lazy_str_hard_failure + and is_too_large_sequence + and not is_multi_byte_decoder + ): + try: + sequences[int(50e3) :].decode(encoding_iana, errors="strict") + except UnicodeDecodeError as e: + logger.log( + TRACE, + "LazyStr Loading: After final lookup, code page %s does not fit given bytes sequence at ALL. %s", + encoding_iana, + str(e), + ) + tested_but_hard_failure.append(encoding_iana) + continue + + mean_mess_ratio: float = sum(md_ratios) / len(md_ratios) if md_ratios else 0.0 + if mean_mess_ratio >= threshold or early_stop_count >= max_chunk_gave_up: + tested_but_soft_failure.append(encoding_iana) + logger.log( + TRACE, + "%s was excluded because of initial chaos probing. Gave up %i time(s). " + "Computed mean chaos is %f %%.", + encoding_iana, + early_stop_count, + round(mean_mess_ratio * 100, ndigits=3), + ) + # Preparing those fallbacks in case we got nothing. + if ( + enable_fallback + and encoding_iana in ["ascii", "utf_8", specified_encoding] + and not lazy_str_hard_failure + ): + fallback_entry = CharsetMatch( + sequences, encoding_iana, threshold, False, [], decoded_payload + ) + if encoding_iana == specified_encoding: + fallback_specified = fallback_entry + elif encoding_iana == "ascii": + fallback_ascii = fallback_entry + else: + fallback_u8 = fallback_entry + continue + + logger.log( + TRACE, + "%s passed initial chaos probing. Mean measured chaos is %f %%", + encoding_iana, + round(mean_mess_ratio * 100, ndigits=3), + ) + + if not is_multi_byte_decoder: + target_languages: List[str] = encoding_languages(encoding_iana) + else: + target_languages = mb_encoding_languages(encoding_iana) + + if target_languages: + logger.log( + TRACE, + "{} should target any language(s) of {}".format( + encoding_iana, str(target_languages) + ), + ) + + cd_ratios = [] + + # We shall skip the CD when its about ASCII + # Most of the time its not relevant to run "language-detection" on it. + if encoding_iana != "ascii": + for chunk in md_chunks: + chunk_languages = coherence_ratio( + chunk, + language_threshold, + ",".join(target_languages) if target_languages else None, + ) + + cd_ratios.append(chunk_languages) + + cd_ratios_merged = merge_coherence_ratios(cd_ratios) + + if cd_ratios_merged: + logger.log( + TRACE, + "We detected language {} using {}".format( + cd_ratios_merged, encoding_iana + ), + ) + + results.append( + CharsetMatch( + sequences, + encoding_iana, + mean_mess_ratio, + bom_or_sig_available, + cd_ratios_merged, + decoded_payload, + ) + ) + + if ( + encoding_iana in [specified_encoding, "ascii", "utf_8"] + and mean_mess_ratio < 0.1 + ): + logger.debug( + "Encoding detection: %s is most likely the one.", encoding_iana + ) + if explain: + logger.removeHandler(explain_handler) + logger.setLevel(previous_logger_level) + return CharsetMatches([results[encoding_iana]]) + + if encoding_iana == sig_encoding: + logger.debug( + "Encoding detection: %s is most likely the one as we detected a BOM or SIG within " + "the beginning of the sequence.", + encoding_iana, + ) + if explain: + logger.removeHandler(explain_handler) + logger.setLevel(previous_logger_level) + return CharsetMatches([results[encoding_iana]]) + + if len(results) == 0: + if fallback_u8 or fallback_ascii or fallback_specified: + logger.log( + TRACE, + "Nothing got out of the detection process. Using ASCII/UTF-8/Specified fallback.", + ) + + if fallback_specified: + logger.debug( + "Encoding detection: %s will be used as a fallback match", + fallback_specified.encoding, + ) + results.append(fallback_specified) + elif ( + (fallback_u8 and fallback_ascii is None) + or ( + fallback_u8 + and fallback_ascii + and fallback_u8.fingerprint != fallback_ascii.fingerprint + ) + or (fallback_u8 is not None) + ): + logger.debug("Encoding detection: utf_8 will be used as a fallback match") + results.append(fallback_u8) + elif fallback_ascii: + logger.debug("Encoding detection: ascii will be used as a fallback match") + results.append(fallback_ascii) + + if results: + logger.debug( + "Encoding detection: Found %s as plausible (best-candidate) for content. With %i alternatives.", + results.best().encoding, # type: ignore + len(results) - 1, + ) + else: + logger.debug("Encoding detection: Unable to determine any suitable charset.") + + if explain: + logger.removeHandler(explain_handler) + logger.setLevel(previous_logger_level) + + return results + + +def from_fp( + fp: BinaryIO, + steps: int = 5, + chunk_size: int = 512, + threshold: float = 0.20, + cp_isolation: Optional[List[str]] = None, + cp_exclusion: Optional[List[str]] = None, + preemptive_behaviour: bool = True, + explain: bool = False, + language_threshold: float = 0.1, + enable_fallback: bool = True, +) -> CharsetMatches: + """ + Same thing than the function from_bytes but using a file pointer that is already ready. + Will not close the file pointer. + """ + return from_bytes( + fp.read(), + steps, + chunk_size, + threshold, + cp_isolation, + cp_exclusion, + preemptive_behaviour, + explain, + language_threshold, + enable_fallback, + ) + + +def from_path( + path: Union[str, bytes, PathLike], # type: ignore[type-arg] + steps: int = 5, + chunk_size: int = 512, + threshold: float = 0.20, + cp_isolation: Optional[List[str]] = None, + cp_exclusion: Optional[List[str]] = None, + preemptive_behaviour: bool = True, + explain: bool = False, + language_threshold: float = 0.1, + enable_fallback: bool = True, +) -> CharsetMatches: + """ + Same thing than the function from_bytes but with one extra step. Opening and reading given file path in binary mode. + Can raise IOError. + """ + with open(path, "rb") as fp: + return from_fp( + fp, + steps, + chunk_size, + threshold, + cp_isolation, + cp_exclusion, + preemptive_behaviour, + explain, + language_threshold, + enable_fallback, + ) + + +def is_binary( + fp_or_path_or_payload: Union[PathLike, str, BinaryIO, bytes], # type: ignore[type-arg] + steps: int = 5, + chunk_size: int = 512, + threshold: float = 0.20, + cp_isolation: Optional[List[str]] = None, + cp_exclusion: Optional[List[str]] = None, + preemptive_behaviour: bool = True, + explain: bool = False, + language_threshold: float = 0.1, + enable_fallback: bool = False, +) -> bool: + """ + Detect if the given input (file, bytes, or path) points to a binary file. aka. not a string. + Based on the same main heuristic algorithms and default kwargs at the sole exception that fallbacks match + are disabled to be stricter around ASCII-compatible but unlikely to be a string. + """ + if isinstance(fp_or_path_or_payload, (str, PathLike)): + guesses = from_path( + fp_or_path_or_payload, + steps=steps, + chunk_size=chunk_size, + threshold=threshold, + cp_isolation=cp_isolation, + cp_exclusion=cp_exclusion, + preemptive_behaviour=preemptive_behaviour, + explain=explain, + language_threshold=language_threshold, + enable_fallback=enable_fallback, + ) + elif isinstance( + fp_or_path_or_payload, + ( + bytes, + bytearray, + ), + ): + guesses = from_bytes( + fp_or_path_or_payload, + steps=steps, + chunk_size=chunk_size, + threshold=threshold, + cp_isolation=cp_isolation, + cp_exclusion=cp_exclusion, + preemptive_behaviour=preemptive_behaviour, + explain=explain, + language_threshold=language_threshold, + enable_fallback=enable_fallback, + ) + else: + guesses = from_fp( + fp_or_path_or_payload, + steps=steps, + chunk_size=chunk_size, + threshold=threshold, + cp_isolation=cp_isolation, + cp_exclusion=cp_exclusion, + preemptive_behaviour=preemptive_behaviour, + explain=explain, + language_threshold=language_threshold, + enable_fallback=enable_fallback, + ) + + return not guesses diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/cd.py b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/cd.py new file mode 100644 index 000000000..4ea6760c4 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/cd.py @@ -0,0 +1,395 @@ +import importlib +from codecs import IncrementalDecoder +from collections import Counter +from functools import lru_cache +from typing import Counter as TypeCounter, Dict, List, Optional, Tuple + +from .constant import ( + FREQUENCIES, + KO_NAMES, + LANGUAGE_SUPPORTED_COUNT, + TOO_SMALL_SEQUENCE, + ZH_NAMES, +) +from .md import is_suspiciously_successive_range +from .models import CoherenceMatches +from .utils import ( + is_accentuated, + is_latin, + is_multi_byte_encoding, + is_unicode_range_secondary, + unicode_range, +) + + +def encoding_unicode_range(iana_name: str) -> List[str]: + """ + Return associated unicode ranges in a single byte code page. + """ + if is_multi_byte_encoding(iana_name): + raise IOError("Function not supported on multi-byte code page") + + decoder = importlib.import_module( + "encodings.{}".format(iana_name) + ).IncrementalDecoder + + p: IncrementalDecoder = decoder(errors="ignore") + seen_ranges: Dict[str, int] = {} + character_count: int = 0 + + for i in range(0x40, 0xFF): + chunk: str = p.decode(bytes([i])) + + if chunk: + character_range: Optional[str] = unicode_range(chunk) + + if character_range is None: + continue + + if is_unicode_range_secondary(character_range) is False: + if character_range not in seen_ranges: + seen_ranges[character_range] = 0 + seen_ranges[character_range] += 1 + character_count += 1 + + return sorted( + [ + character_range + for character_range in seen_ranges + if seen_ranges[character_range] / character_count >= 0.15 + ] + ) + + +def unicode_range_languages(primary_range: str) -> List[str]: + """ + Return inferred languages used with a unicode range. + """ + languages: List[str] = [] + + for language, characters in FREQUENCIES.items(): + for character in characters: + if unicode_range(character) == primary_range: + languages.append(language) + break + + return languages + + +@lru_cache() +def encoding_languages(iana_name: str) -> List[str]: + """ + Single-byte encoding language association. Some code page are heavily linked to particular language(s). + This function does the correspondence. + """ + unicode_ranges: List[str] = encoding_unicode_range(iana_name) + primary_range: Optional[str] = None + + for specified_range in unicode_ranges: + if "Latin" not in specified_range: + primary_range = specified_range + break + + if primary_range is None: + return ["Latin Based"] + + return unicode_range_languages(primary_range) + + +@lru_cache() +def mb_encoding_languages(iana_name: str) -> List[str]: + """ + Multi-byte encoding language association. Some code page are heavily linked to particular language(s). + This function does the correspondence. + """ + if ( + iana_name.startswith("shift_") + or iana_name.startswith("iso2022_jp") + or iana_name.startswith("euc_j") + or iana_name == "cp932" + ): + return ["Japanese"] + if iana_name.startswith("gb") or iana_name in ZH_NAMES: + return ["Chinese"] + if iana_name.startswith("iso2022_kr") or iana_name in KO_NAMES: + return ["Korean"] + + return [] + + +@lru_cache(maxsize=LANGUAGE_SUPPORTED_COUNT) +def get_target_features(language: str) -> Tuple[bool, bool]: + """ + Determine main aspects from a supported language if it contains accents and if is pure Latin. + """ + target_have_accents: bool = False + target_pure_latin: bool = True + + for character in FREQUENCIES[language]: + if not target_have_accents and is_accentuated(character): + target_have_accents = True + if target_pure_latin and is_latin(character) is False: + target_pure_latin = False + + return target_have_accents, target_pure_latin + + +def alphabet_languages( + characters: List[str], ignore_non_latin: bool = False +) -> List[str]: + """ + Return associated languages associated to given characters. + """ + languages: List[Tuple[str, float]] = [] + + source_have_accents = any(is_accentuated(character) for character in characters) + + for language, language_characters in FREQUENCIES.items(): + target_have_accents, target_pure_latin = get_target_features(language) + + if ignore_non_latin and target_pure_latin is False: + continue + + if target_have_accents is False and source_have_accents: + continue + + character_count: int = len(language_characters) + + character_match_count: int = len( + [c for c in language_characters if c in characters] + ) + + ratio: float = character_match_count / character_count + + if ratio >= 0.2: + languages.append((language, ratio)) + + languages = sorted(languages, key=lambda x: x[1], reverse=True) + + return [compatible_language[0] for compatible_language in languages] + + +def characters_popularity_compare( + language: str, ordered_characters: List[str] +) -> float: + """ + Determine if a ordered characters list (by occurrence from most appearance to rarest) match a particular language. + The result is a ratio between 0. (absolutely no correspondence) and 1. (near perfect fit). + Beware that is function is not strict on the match in order to ease the detection. (Meaning close match is 1.) + """ + if language not in FREQUENCIES: + raise ValueError("{} not available".format(language)) + + character_approved_count: int = 0 + FREQUENCIES_language_set = set(FREQUENCIES[language]) + + ordered_characters_count: int = len(ordered_characters) + target_language_characters_count: int = len(FREQUENCIES[language]) + + large_alphabet: bool = target_language_characters_count > 26 + + for character, character_rank in zip( + ordered_characters, range(0, ordered_characters_count) + ): + if character not in FREQUENCIES_language_set: + continue + + character_rank_in_language: int = FREQUENCIES[language].index(character) + expected_projection_ratio: float = ( + target_language_characters_count / ordered_characters_count + ) + character_rank_projection: int = int(character_rank * expected_projection_ratio) + + if ( + large_alphabet is False + and abs(character_rank_projection - character_rank_in_language) > 4 + ): + continue + + if ( + large_alphabet is True + and abs(character_rank_projection - character_rank_in_language) + < target_language_characters_count / 3 + ): + character_approved_count += 1 + continue + + characters_before_source: List[str] = FREQUENCIES[language][ + 0:character_rank_in_language + ] + characters_after_source: List[str] = FREQUENCIES[language][ + character_rank_in_language: + ] + characters_before: List[str] = ordered_characters[0:character_rank] + characters_after: List[str] = ordered_characters[character_rank:] + + before_match_count: int = len( + set(characters_before) & set(characters_before_source) + ) + + after_match_count: int = len( + set(characters_after) & set(characters_after_source) + ) + + if len(characters_before_source) == 0 and before_match_count <= 4: + character_approved_count += 1 + continue + + if len(characters_after_source) == 0 and after_match_count <= 4: + character_approved_count += 1 + continue + + if ( + before_match_count / len(characters_before_source) >= 0.4 + or after_match_count / len(characters_after_source) >= 0.4 + ): + character_approved_count += 1 + continue + + return character_approved_count / len(ordered_characters) + + +def alpha_unicode_split(decoded_sequence: str) -> List[str]: + """ + Given a decoded text sequence, return a list of str. Unicode range / alphabet separation. + Ex. a text containing English/Latin with a bit a Hebrew will return two items in the resulting list; + One containing the latin letters and the other hebrew. + """ + layers: Dict[str, str] = {} + + for character in decoded_sequence: + if character.isalpha() is False: + continue + + character_range: Optional[str] = unicode_range(character) + + if character_range is None: + continue + + layer_target_range: Optional[str] = None + + for discovered_range in layers: + if ( + is_suspiciously_successive_range(discovered_range, character_range) + is False + ): + layer_target_range = discovered_range + break + + if layer_target_range is None: + layer_target_range = character_range + + if layer_target_range not in layers: + layers[layer_target_range] = character.lower() + continue + + layers[layer_target_range] += character.lower() + + return list(layers.values()) + + +def merge_coherence_ratios(results: List[CoherenceMatches]) -> CoherenceMatches: + """ + This function merge results previously given by the function coherence_ratio. + The return type is the same as coherence_ratio. + """ + per_language_ratios: Dict[str, List[float]] = {} + for result in results: + for sub_result in result: + language, ratio = sub_result + if language not in per_language_ratios: + per_language_ratios[language] = [ratio] + continue + per_language_ratios[language].append(ratio) + + merge = [ + ( + language, + round( + sum(per_language_ratios[language]) / len(per_language_ratios[language]), + 4, + ), + ) + for language in per_language_ratios + ] + + return sorted(merge, key=lambda x: x[1], reverse=True) + + +def filter_alt_coherence_matches(results: CoherenceMatches) -> CoherenceMatches: + """ + We shall NOT return "English—" in CoherenceMatches because it is an alternative + of "English". This function only keeps the best match and remove the em-dash in it. + """ + index_results: Dict[str, List[float]] = dict() + + for result in results: + language, ratio = result + no_em_name: str = language.replace("—", "") + + if no_em_name not in index_results: + index_results[no_em_name] = [] + + index_results[no_em_name].append(ratio) + + if any(len(index_results[e]) > 1 for e in index_results): + filtered_results: CoherenceMatches = [] + + for language in index_results: + filtered_results.append((language, max(index_results[language]))) + + return filtered_results + + return results + + +@lru_cache(maxsize=2048) +def coherence_ratio( + decoded_sequence: str, threshold: float = 0.1, lg_inclusion: Optional[str] = None +) -> CoherenceMatches: + """ + Detect ANY language that can be identified in given sequence. The sequence will be analysed by layers. + A layer = Character extraction by alphabets/ranges. + """ + + results: List[Tuple[str, float]] = [] + ignore_non_latin: bool = False + + sufficient_match_count: int = 0 + + lg_inclusion_list = lg_inclusion.split(",") if lg_inclusion is not None else [] + if "Latin Based" in lg_inclusion_list: + ignore_non_latin = True + lg_inclusion_list.remove("Latin Based") + + for layer in alpha_unicode_split(decoded_sequence): + sequence_frequencies: TypeCounter[str] = Counter(layer) + most_common = sequence_frequencies.most_common() + + character_count: int = sum(o for c, o in most_common) + + if character_count <= TOO_SMALL_SEQUENCE: + continue + + popular_character_ordered: List[str] = [c for c, o in most_common] + + for language in lg_inclusion_list or alphabet_languages( + popular_character_ordered, ignore_non_latin + ): + ratio: float = characters_popularity_compare( + language, popular_character_ordered + ) + + if ratio < threshold: + continue + elif ratio >= 0.8: + sufficient_match_count += 1 + + results.append((language, round(ratio, 4))) + + if sufficient_match_count >= 3: + break + + return sorted( + filter_alt_coherence_matches(results), key=lambda x: x[1], reverse=True + ) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/cli/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/cli/__init__.py new file mode 100644 index 000000000..d95fedfe5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/cli/__init__.py @@ -0,0 +1,6 @@ +from .__main__ import cli_detect, query_yes_no + +__all__ = ( + "cli_detect", + "query_yes_no", +) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/cli/__main__.py b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/cli/__main__.py new file mode 100644 index 000000000..f4bcbaac0 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/cli/__main__.py @@ -0,0 +1,296 @@ +import argparse +import sys +from json import dumps +from os.path import abspath, basename, dirname, join, realpath +from platform import python_version +from typing import List, Optional +from unicodedata import unidata_version + +import charset_normalizer.md as md_module +from charset_normalizer import from_fp +from charset_normalizer.models import CliDetectionResult +from charset_normalizer.version import __version__ + + +def query_yes_no(question: str, default: str = "yes") -> bool: + """Ask a yes/no question via input() and return their answer. + + "question" is a string that is presented to the user. + "default" is the presumed answer if the user just hits . + It must be "yes" (the default), "no" or None (meaning + an answer is required of the user). + + The "answer" return value is True for "yes" or False for "no". + + Credit goes to (c) https://stackoverflow.com/questions/3041986/apt-command-line-interface-like-yes-no-input + """ + valid = {"yes": True, "y": True, "ye": True, "no": False, "n": False} + if default is None: + prompt = " [y/n] " + elif default == "yes": + prompt = " [Y/n] " + elif default == "no": + prompt = " [y/N] " + else: + raise ValueError("invalid default answer: '%s'" % default) + + while True: + sys.stdout.write(question + prompt) + choice = input().lower() + if default is not None and choice == "": + return valid[default] + elif choice in valid: + return valid[choice] + else: + sys.stdout.write("Please respond with 'yes' or 'no' " "(or 'y' or 'n').\n") + + +def cli_detect(argv: Optional[List[str]] = None) -> int: + """ + CLI assistant using ARGV and ArgumentParser + :param argv: + :return: 0 if everything is fine, anything else equal trouble + """ + parser = argparse.ArgumentParser( + description="The Real First Universal Charset Detector. " + "Discover originating encoding used on text file. " + "Normalize text to unicode." + ) + + parser.add_argument( + "files", type=argparse.FileType("rb"), nargs="+", help="File(s) to be analysed" + ) + parser.add_argument( + "-v", + "--verbose", + action="store_true", + default=False, + dest="verbose", + help="Display complementary information about file if any. " + "Stdout will contain logs about the detection process.", + ) + parser.add_argument( + "-a", + "--with-alternative", + action="store_true", + default=False, + dest="alternatives", + help="Output complementary possibilities if any. Top-level JSON WILL be a list.", + ) + parser.add_argument( + "-n", + "--normalize", + action="store_true", + default=False, + dest="normalize", + help="Permit to normalize input file. If not set, program does not write anything.", + ) + parser.add_argument( + "-m", + "--minimal", + action="store_true", + default=False, + dest="minimal", + help="Only output the charset detected to STDOUT. Disabling JSON output.", + ) + parser.add_argument( + "-r", + "--replace", + action="store_true", + default=False, + dest="replace", + help="Replace file when trying to normalize it instead of creating a new one.", + ) + parser.add_argument( + "-f", + "--force", + action="store_true", + default=False, + dest="force", + help="Replace file without asking if you are sure, use this flag with caution.", + ) + parser.add_argument( + "-t", + "--threshold", + action="store", + default=0.2, + type=float, + dest="threshold", + help="Define a custom maximum amount of chaos allowed in decoded content. 0. <= chaos <= 1.", + ) + parser.add_argument( + "--version", + action="version", + version="Charset-Normalizer {} - Python {} - Unicode {} - SpeedUp {}".format( + __version__, + python_version(), + unidata_version, + "OFF" if md_module.__file__.lower().endswith(".py") else "ON", + ), + help="Show version information and exit.", + ) + + args = parser.parse_args(argv) + + if args.replace is True and args.normalize is False: + print("Use --replace in addition of --normalize only.", file=sys.stderr) + return 1 + + if args.force is True and args.replace is False: + print("Use --force in addition of --replace only.", file=sys.stderr) + return 1 + + if args.threshold < 0.0 or args.threshold > 1.0: + print("--threshold VALUE should be between 0. AND 1.", file=sys.stderr) + return 1 + + x_ = [] + + for my_file in args.files: + matches = from_fp(my_file, threshold=args.threshold, explain=args.verbose) + + best_guess = matches.best() + + if best_guess is None: + print( + 'Unable to identify originating encoding for "{}". {}'.format( + my_file.name, + "Maybe try increasing maximum amount of chaos." + if args.threshold < 1.0 + else "", + ), + file=sys.stderr, + ) + x_.append( + CliDetectionResult( + abspath(my_file.name), + None, + [], + [], + "Unknown", + [], + False, + 1.0, + 0.0, + None, + True, + ) + ) + else: + x_.append( + CliDetectionResult( + abspath(my_file.name), + best_guess.encoding, + best_guess.encoding_aliases, + [ + cp + for cp in best_guess.could_be_from_charset + if cp != best_guess.encoding + ], + best_guess.language, + best_guess.alphabets, + best_guess.bom, + best_guess.percent_chaos, + best_guess.percent_coherence, + None, + True, + ) + ) + + if len(matches) > 1 and args.alternatives: + for el in matches: + if el != best_guess: + x_.append( + CliDetectionResult( + abspath(my_file.name), + el.encoding, + el.encoding_aliases, + [ + cp + for cp in el.could_be_from_charset + if cp != el.encoding + ], + el.language, + el.alphabets, + el.bom, + el.percent_chaos, + el.percent_coherence, + None, + False, + ) + ) + + if args.normalize is True: + if best_guess.encoding.startswith("utf") is True: + print( + '"{}" file does not need to be normalized, as it already came from unicode.'.format( + my_file.name + ), + file=sys.stderr, + ) + if my_file.closed is False: + my_file.close() + continue + + dir_path = dirname(realpath(my_file.name)) + file_name = basename(realpath(my_file.name)) + + o_: List[str] = file_name.split(".") + + if args.replace is False: + o_.insert(-1, best_guess.encoding) + if my_file.closed is False: + my_file.close() + elif ( + args.force is False + and query_yes_no( + 'Are you sure to normalize "{}" by replacing it ?'.format( + my_file.name + ), + "no", + ) + is False + ): + if my_file.closed is False: + my_file.close() + continue + + try: + x_[0].unicode_path = join(dir_path, ".".join(o_)) + + with open(x_[0].unicode_path, "w", encoding="utf-8") as fp: + fp.write(str(best_guess)) + except IOError as e: + print(str(e), file=sys.stderr) + if my_file.closed is False: + my_file.close() + return 2 + + if my_file.closed is False: + my_file.close() + + if args.minimal is False: + print( + dumps( + [el.__dict__ for el in x_] if len(x_) > 1 else x_[0].__dict__, + ensure_ascii=True, + indent=4, + ) + ) + else: + for my_file in args.files: + print( + ", ".join( + [ + el.encoding or "undefined" + for el in x_ + if el.path == abspath(my_file.name) + ] + ) + ) + + return 0 + + +if __name__ == "__main__": + cli_detect() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/constant.py b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/constant.py new file mode 100644 index 000000000..863490461 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/constant.py @@ -0,0 +1,1995 @@ +# -*- coding: utf-8 -*- +from codecs import BOM_UTF8, BOM_UTF16_BE, BOM_UTF16_LE, BOM_UTF32_BE, BOM_UTF32_LE +from encodings.aliases import aliases +from re import IGNORECASE, compile as re_compile +from typing import Dict, List, Set, Union + +# Contain for each eligible encoding a list of/item bytes SIG/BOM +ENCODING_MARKS: Dict[str, Union[bytes, List[bytes]]] = { + "utf_8": BOM_UTF8, + "utf_7": [ + b"\x2b\x2f\x76\x38", + b"\x2b\x2f\x76\x39", + b"\x2b\x2f\x76\x2b", + b"\x2b\x2f\x76\x2f", + b"\x2b\x2f\x76\x38\x2d", + ], + "gb18030": b"\x84\x31\x95\x33", + "utf_32": [BOM_UTF32_BE, BOM_UTF32_LE], + "utf_16": [BOM_UTF16_BE, BOM_UTF16_LE], +} + +TOO_SMALL_SEQUENCE: int = 32 +TOO_BIG_SEQUENCE: int = int(10e6) + +UTF8_MAXIMAL_ALLOCATION: int = 1_112_064 + +# Up-to-date Unicode ucd/15.0.0 +UNICODE_RANGES_COMBINED: Dict[str, range] = { + "Control character": range(32), + "Basic Latin": range(32, 128), + "Latin-1 Supplement": range(128, 256), + "Latin Extended-A": range(256, 384), + "Latin Extended-B": range(384, 592), + "IPA Extensions": range(592, 688), + "Spacing Modifier Letters": range(688, 768), + "Combining Diacritical Marks": range(768, 880), + "Greek and Coptic": range(880, 1024), + "Cyrillic": range(1024, 1280), + "Cyrillic Supplement": range(1280, 1328), + "Armenian": range(1328, 1424), + "Hebrew": range(1424, 1536), + "Arabic": range(1536, 1792), + "Syriac": range(1792, 1872), + "Arabic Supplement": range(1872, 1920), + "Thaana": range(1920, 1984), + "NKo": range(1984, 2048), + "Samaritan": range(2048, 2112), + "Mandaic": range(2112, 2144), + "Syriac Supplement": range(2144, 2160), + "Arabic Extended-B": range(2160, 2208), + "Arabic Extended-A": range(2208, 2304), + "Devanagari": range(2304, 2432), + "Bengali": range(2432, 2560), + "Gurmukhi": range(2560, 2688), + "Gujarati": range(2688, 2816), + "Oriya": range(2816, 2944), + "Tamil": range(2944, 3072), + "Telugu": range(3072, 3200), + "Kannada": range(3200, 3328), + "Malayalam": range(3328, 3456), + "Sinhala": range(3456, 3584), + "Thai": range(3584, 3712), + "Lao": range(3712, 3840), + "Tibetan": range(3840, 4096), + "Myanmar": range(4096, 4256), + "Georgian": range(4256, 4352), + "Hangul Jamo": range(4352, 4608), + "Ethiopic": range(4608, 4992), + "Ethiopic Supplement": range(4992, 5024), + "Cherokee": range(5024, 5120), + "Unified Canadian Aboriginal Syllabics": range(5120, 5760), + "Ogham": range(5760, 5792), + "Runic": range(5792, 5888), + "Tagalog": range(5888, 5920), + "Hanunoo": range(5920, 5952), + "Buhid": range(5952, 5984), + "Tagbanwa": range(5984, 6016), + "Khmer": range(6016, 6144), + "Mongolian": range(6144, 6320), + "Unified Canadian Aboriginal Syllabics Extended": range(6320, 6400), + "Limbu": range(6400, 6480), + "Tai Le": range(6480, 6528), + "New Tai Lue": range(6528, 6624), + "Khmer Symbols": range(6624, 6656), + "Buginese": range(6656, 6688), + "Tai Tham": range(6688, 6832), + "Combining Diacritical Marks Extended": range(6832, 6912), + "Balinese": range(6912, 7040), + "Sundanese": range(7040, 7104), + "Batak": range(7104, 7168), + "Lepcha": range(7168, 7248), + "Ol Chiki": range(7248, 7296), + "Cyrillic Extended-C": range(7296, 7312), + "Georgian Extended": range(7312, 7360), + "Sundanese Supplement": range(7360, 7376), + "Vedic Extensions": range(7376, 7424), + "Phonetic Extensions": range(7424, 7552), + "Phonetic Extensions Supplement": range(7552, 7616), + "Combining Diacritical Marks Supplement": range(7616, 7680), + "Latin Extended Additional": range(7680, 7936), + "Greek Extended": range(7936, 8192), + "General Punctuation": range(8192, 8304), + "Superscripts and Subscripts": range(8304, 8352), + "Currency Symbols": range(8352, 8400), + "Combining Diacritical Marks for Symbols": range(8400, 8448), + "Letterlike Symbols": range(8448, 8528), + "Number Forms": range(8528, 8592), + "Arrows": range(8592, 8704), + "Mathematical Operators": range(8704, 8960), + "Miscellaneous Technical": range(8960, 9216), + "Control Pictures": range(9216, 9280), + "Optical Character Recognition": range(9280, 9312), + "Enclosed Alphanumerics": range(9312, 9472), + "Box Drawing": range(9472, 9600), + "Block Elements": range(9600, 9632), + "Geometric Shapes": range(9632, 9728), + "Miscellaneous Symbols": range(9728, 9984), + "Dingbats": range(9984, 10176), + "Miscellaneous Mathematical Symbols-A": range(10176, 10224), + "Supplemental Arrows-A": range(10224, 10240), + "Braille Patterns": range(10240, 10496), + "Supplemental Arrows-B": range(10496, 10624), + "Miscellaneous Mathematical Symbols-B": range(10624, 10752), + "Supplemental Mathematical Operators": range(10752, 11008), + "Miscellaneous Symbols and Arrows": range(11008, 11264), + "Glagolitic": range(11264, 11360), + "Latin Extended-C": range(11360, 11392), + "Coptic": range(11392, 11520), + "Georgian Supplement": range(11520, 11568), + "Tifinagh": range(11568, 11648), + "Ethiopic Extended": range(11648, 11744), + "Cyrillic Extended-A": range(11744, 11776), + "Supplemental Punctuation": range(11776, 11904), + "CJK Radicals Supplement": range(11904, 12032), + "Kangxi Radicals": range(12032, 12256), + "Ideographic Description Characters": range(12272, 12288), + "CJK Symbols and Punctuation": range(12288, 12352), + "Hiragana": range(12352, 12448), + "Katakana": range(12448, 12544), + "Bopomofo": range(12544, 12592), + "Hangul Compatibility Jamo": range(12592, 12688), + "Kanbun": range(12688, 12704), + "Bopomofo Extended": range(12704, 12736), + "CJK Strokes": range(12736, 12784), + "Katakana Phonetic Extensions": range(12784, 12800), + "Enclosed CJK Letters and Months": range(12800, 13056), + "CJK Compatibility": range(13056, 13312), + "CJK Unified Ideographs Extension A": range(13312, 19904), + "Yijing Hexagram Symbols": range(19904, 19968), + "CJK Unified Ideographs": range(19968, 40960), + "Yi Syllables": range(40960, 42128), + "Yi Radicals": range(42128, 42192), + "Lisu": range(42192, 42240), + "Vai": range(42240, 42560), + "Cyrillic Extended-B": range(42560, 42656), + "Bamum": range(42656, 42752), + "Modifier Tone Letters": range(42752, 42784), + "Latin Extended-D": range(42784, 43008), + "Syloti Nagri": range(43008, 43056), + "Common Indic Number Forms": range(43056, 43072), + "Phags-pa": range(43072, 43136), + "Saurashtra": range(43136, 43232), + "Devanagari Extended": range(43232, 43264), + "Kayah Li": range(43264, 43312), + "Rejang": range(43312, 43360), + "Hangul Jamo Extended-A": range(43360, 43392), + "Javanese": range(43392, 43488), + "Myanmar Extended-B": range(43488, 43520), + "Cham": range(43520, 43616), + "Myanmar Extended-A": range(43616, 43648), + "Tai Viet": range(43648, 43744), + "Meetei Mayek Extensions": range(43744, 43776), + "Ethiopic Extended-A": range(43776, 43824), + "Latin Extended-E": range(43824, 43888), + "Cherokee Supplement": range(43888, 43968), + "Meetei Mayek": range(43968, 44032), + "Hangul Syllables": range(44032, 55216), + "Hangul Jamo Extended-B": range(55216, 55296), + "High Surrogates": range(55296, 56192), + "High Private Use Surrogates": range(56192, 56320), + "Low Surrogates": range(56320, 57344), + "Private Use Area": range(57344, 63744), + "CJK Compatibility Ideographs": range(63744, 64256), + "Alphabetic Presentation Forms": range(64256, 64336), + "Arabic Presentation Forms-A": range(64336, 65024), + "Variation Selectors": range(65024, 65040), + "Vertical Forms": range(65040, 65056), + "Combining Half Marks": range(65056, 65072), + "CJK Compatibility Forms": range(65072, 65104), + "Small Form Variants": range(65104, 65136), + "Arabic Presentation Forms-B": range(65136, 65280), + "Halfwidth and Fullwidth Forms": range(65280, 65520), + "Specials": range(65520, 65536), + "Linear B Syllabary": range(65536, 65664), + "Linear B Ideograms": range(65664, 65792), + "Aegean Numbers": range(65792, 65856), + "Ancient Greek Numbers": range(65856, 65936), + "Ancient Symbols": range(65936, 66000), + "Phaistos Disc": range(66000, 66048), + "Lycian": range(66176, 66208), + "Carian": range(66208, 66272), + "Coptic Epact Numbers": range(66272, 66304), + "Old Italic": range(66304, 66352), + "Gothic": range(66352, 66384), + "Old Permic": range(66384, 66432), + "Ugaritic": range(66432, 66464), + "Old Persian": range(66464, 66528), + "Deseret": range(66560, 66640), + "Shavian": range(66640, 66688), + "Osmanya": range(66688, 66736), + "Osage": range(66736, 66816), + "Elbasan": range(66816, 66864), + "Caucasian Albanian": range(66864, 66928), + "Vithkuqi": range(66928, 67008), + "Linear A": range(67072, 67456), + "Latin Extended-F": range(67456, 67520), + "Cypriot Syllabary": range(67584, 67648), + "Imperial Aramaic": range(67648, 67680), + "Palmyrene": range(67680, 67712), + "Nabataean": range(67712, 67760), + "Hatran": range(67808, 67840), + "Phoenician": range(67840, 67872), + "Lydian": range(67872, 67904), + "Meroitic Hieroglyphs": range(67968, 68000), + "Meroitic Cursive": range(68000, 68096), + "Kharoshthi": range(68096, 68192), + "Old South Arabian": range(68192, 68224), + "Old North Arabian": range(68224, 68256), + "Manichaean": range(68288, 68352), + "Avestan": range(68352, 68416), + "Inscriptional Parthian": range(68416, 68448), + "Inscriptional Pahlavi": range(68448, 68480), + "Psalter Pahlavi": range(68480, 68528), + "Old Turkic": range(68608, 68688), + "Old Hungarian": range(68736, 68864), + "Hanifi Rohingya": range(68864, 68928), + "Rumi Numeral Symbols": range(69216, 69248), + "Yezidi": range(69248, 69312), + "Arabic Extended-C": range(69312, 69376), + "Old Sogdian": range(69376, 69424), + "Sogdian": range(69424, 69488), + "Old Uyghur": range(69488, 69552), + "Chorasmian": range(69552, 69600), + "Elymaic": range(69600, 69632), + "Brahmi": range(69632, 69760), + "Kaithi": range(69760, 69840), + "Sora Sompeng": range(69840, 69888), + "Chakma": range(69888, 69968), + "Mahajani": range(69968, 70016), + "Sharada": range(70016, 70112), + "Sinhala Archaic Numbers": range(70112, 70144), + "Khojki": range(70144, 70224), + "Multani": range(70272, 70320), + "Khudawadi": range(70320, 70400), + "Grantha": range(70400, 70528), + "Newa": range(70656, 70784), + "Tirhuta": range(70784, 70880), + "Siddham": range(71040, 71168), + "Modi": range(71168, 71264), + "Mongolian Supplement": range(71264, 71296), + "Takri": range(71296, 71376), + "Ahom": range(71424, 71504), + "Dogra": range(71680, 71760), + "Warang Citi": range(71840, 71936), + "Dives Akuru": range(71936, 72032), + "Nandinagari": range(72096, 72192), + "Zanabazar Square": range(72192, 72272), + "Soyombo": range(72272, 72368), + "Unified Canadian Aboriginal Syllabics Extended-A": range(72368, 72384), + "Pau Cin Hau": range(72384, 72448), + "Devanagari Extended-A": range(72448, 72544), + "Bhaiksuki": range(72704, 72816), + "Marchen": range(72816, 72896), + "Masaram Gondi": range(72960, 73056), + "Gunjala Gondi": range(73056, 73136), + "Makasar": range(73440, 73472), + "Kawi": range(73472, 73568), + "Lisu Supplement": range(73648, 73664), + "Tamil Supplement": range(73664, 73728), + "Cuneiform": range(73728, 74752), + "Cuneiform Numbers and Punctuation": range(74752, 74880), + "Early Dynastic Cuneiform": range(74880, 75088), + "Cypro-Minoan": range(77712, 77824), + "Egyptian Hieroglyphs": range(77824, 78896), + "Egyptian Hieroglyph Format Controls": range(78896, 78944), + "Anatolian Hieroglyphs": range(82944, 83584), + "Bamum Supplement": range(92160, 92736), + "Mro": range(92736, 92784), + "Tangsa": range(92784, 92880), + "Bassa Vah": range(92880, 92928), + "Pahawh Hmong": range(92928, 93072), + "Medefaidrin": range(93760, 93856), + "Miao": range(93952, 94112), + "Ideographic Symbols and Punctuation": range(94176, 94208), + "Tangut": range(94208, 100352), + "Tangut Components": range(100352, 101120), + "Khitan Small Script": range(101120, 101632), + "Tangut Supplement": range(101632, 101760), + "Kana Extended-B": range(110576, 110592), + "Kana Supplement": range(110592, 110848), + "Kana Extended-A": range(110848, 110896), + "Small Kana Extension": range(110896, 110960), + "Nushu": range(110960, 111360), + "Duployan": range(113664, 113824), + "Shorthand Format Controls": range(113824, 113840), + "Znamenny Musical Notation": range(118528, 118736), + "Byzantine Musical Symbols": range(118784, 119040), + "Musical Symbols": range(119040, 119296), + "Ancient Greek Musical Notation": range(119296, 119376), + "Kaktovik Numerals": range(119488, 119520), + "Mayan Numerals": range(119520, 119552), + "Tai Xuan Jing Symbols": range(119552, 119648), + "Counting Rod Numerals": range(119648, 119680), + "Mathematical Alphanumeric Symbols": range(119808, 120832), + "Sutton SignWriting": range(120832, 121520), + "Latin Extended-G": range(122624, 122880), + "Glagolitic Supplement": range(122880, 122928), + "Cyrillic Extended-D": range(122928, 123024), + "Nyiakeng Puachue Hmong": range(123136, 123216), + "Toto": range(123536, 123584), + "Wancho": range(123584, 123648), + "Nag Mundari": range(124112, 124160), + "Ethiopic Extended-B": range(124896, 124928), + "Mende Kikakui": range(124928, 125152), + "Adlam": range(125184, 125280), + "Indic Siyaq Numbers": range(126064, 126144), + "Ottoman Siyaq Numbers": range(126208, 126288), + "Arabic Mathematical Alphabetic Symbols": range(126464, 126720), + "Mahjong Tiles": range(126976, 127024), + "Domino Tiles": range(127024, 127136), + "Playing Cards": range(127136, 127232), + "Enclosed Alphanumeric Supplement": range(127232, 127488), + "Enclosed Ideographic Supplement": range(127488, 127744), + "Miscellaneous Symbols and Pictographs": range(127744, 128512), + "Emoticons range(Emoji)": range(128512, 128592), + "Ornamental Dingbats": range(128592, 128640), + "Transport and Map Symbols": range(128640, 128768), + "Alchemical Symbols": range(128768, 128896), + "Geometric Shapes Extended": range(128896, 129024), + "Supplemental Arrows-C": range(129024, 129280), + "Supplemental Symbols and Pictographs": range(129280, 129536), + "Chess Symbols": range(129536, 129648), + "Symbols and Pictographs Extended-A": range(129648, 129792), + "Symbols for Legacy Computing": range(129792, 130048), + "CJK Unified Ideographs Extension B": range(131072, 173792), + "CJK Unified Ideographs Extension C": range(173824, 177984), + "CJK Unified Ideographs Extension D": range(177984, 178208), + "CJK Unified Ideographs Extension E": range(178208, 183984), + "CJK Unified Ideographs Extension F": range(183984, 191472), + "CJK Compatibility Ideographs Supplement": range(194560, 195104), + "CJK Unified Ideographs Extension G": range(196608, 201552), + "CJK Unified Ideographs Extension H": range(201552, 205744), + "Tags": range(917504, 917632), + "Variation Selectors Supplement": range(917760, 918000), + "Supplementary Private Use Area-A": range(983040, 1048576), + "Supplementary Private Use Area-B": range(1048576, 1114112), +} + + +UNICODE_SECONDARY_RANGE_KEYWORD: List[str] = [ + "Supplement", + "Extended", + "Extensions", + "Modifier", + "Marks", + "Punctuation", + "Symbols", + "Forms", + "Operators", + "Miscellaneous", + "Drawing", + "Block", + "Shapes", + "Supplemental", + "Tags", +] + +RE_POSSIBLE_ENCODING_INDICATION = re_compile( + r"(?:(?:encoding)|(?:charset)|(?:coding))(?:[\:= ]{1,10})(?:[\"\']?)([a-zA-Z0-9\-_]+)(?:[\"\']?)", + IGNORECASE, +) + +IANA_NO_ALIASES = [ + "cp720", + "cp737", + "cp856", + "cp874", + "cp875", + "cp1006", + "koi8_r", + "koi8_t", + "koi8_u", +] + +IANA_SUPPORTED: List[str] = sorted( + filter( + lambda x: x.endswith("_codec") is False + and x not in {"rot_13", "tactis", "mbcs"}, + list(set(aliases.values())) + IANA_NO_ALIASES, + ) +) + +IANA_SUPPORTED_COUNT: int = len(IANA_SUPPORTED) + +# pre-computed code page that are similar using the function cp_similarity. +IANA_SUPPORTED_SIMILAR: Dict[str, List[str]] = { + "cp037": ["cp1026", "cp1140", "cp273", "cp500"], + "cp1026": ["cp037", "cp1140", "cp273", "cp500"], + "cp1125": ["cp866"], + "cp1140": ["cp037", "cp1026", "cp273", "cp500"], + "cp1250": ["iso8859_2"], + "cp1251": ["kz1048", "ptcp154"], + "cp1252": ["iso8859_15", "iso8859_9", "latin_1"], + "cp1253": ["iso8859_7"], + "cp1254": ["iso8859_15", "iso8859_9", "latin_1"], + "cp1257": ["iso8859_13"], + "cp273": ["cp037", "cp1026", "cp1140", "cp500"], + "cp437": ["cp850", "cp858", "cp860", "cp861", "cp862", "cp863", "cp865"], + "cp500": ["cp037", "cp1026", "cp1140", "cp273"], + "cp850": ["cp437", "cp857", "cp858", "cp865"], + "cp857": ["cp850", "cp858", "cp865"], + "cp858": ["cp437", "cp850", "cp857", "cp865"], + "cp860": ["cp437", "cp861", "cp862", "cp863", "cp865"], + "cp861": ["cp437", "cp860", "cp862", "cp863", "cp865"], + "cp862": ["cp437", "cp860", "cp861", "cp863", "cp865"], + "cp863": ["cp437", "cp860", "cp861", "cp862", "cp865"], + "cp865": ["cp437", "cp850", "cp857", "cp858", "cp860", "cp861", "cp862", "cp863"], + "cp866": ["cp1125"], + "iso8859_10": ["iso8859_14", "iso8859_15", "iso8859_4", "iso8859_9", "latin_1"], + "iso8859_11": ["tis_620"], + "iso8859_13": ["cp1257"], + "iso8859_14": [ + "iso8859_10", + "iso8859_15", + "iso8859_16", + "iso8859_3", + "iso8859_9", + "latin_1", + ], + "iso8859_15": [ + "cp1252", + "cp1254", + "iso8859_10", + "iso8859_14", + "iso8859_16", + "iso8859_3", + "iso8859_9", + "latin_1", + ], + "iso8859_16": [ + "iso8859_14", + "iso8859_15", + "iso8859_2", + "iso8859_3", + "iso8859_9", + "latin_1", + ], + "iso8859_2": ["cp1250", "iso8859_16", "iso8859_4"], + "iso8859_3": ["iso8859_14", "iso8859_15", "iso8859_16", "iso8859_9", "latin_1"], + "iso8859_4": ["iso8859_10", "iso8859_2", "iso8859_9", "latin_1"], + "iso8859_7": ["cp1253"], + "iso8859_9": [ + "cp1252", + "cp1254", + "cp1258", + "iso8859_10", + "iso8859_14", + "iso8859_15", + "iso8859_16", + "iso8859_3", + "iso8859_4", + "latin_1", + ], + "kz1048": ["cp1251", "ptcp154"], + "latin_1": [ + "cp1252", + "cp1254", + "cp1258", + "iso8859_10", + "iso8859_14", + "iso8859_15", + "iso8859_16", + "iso8859_3", + "iso8859_4", + "iso8859_9", + ], + "mac_iceland": ["mac_roman", "mac_turkish"], + "mac_roman": ["mac_iceland", "mac_turkish"], + "mac_turkish": ["mac_iceland", "mac_roman"], + "ptcp154": ["cp1251", "kz1048"], + "tis_620": ["iso8859_11"], +} + + +CHARDET_CORRESPONDENCE: Dict[str, str] = { + "iso2022_kr": "ISO-2022-KR", + "iso2022_jp": "ISO-2022-JP", + "euc_kr": "EUC-KR", + "tis_620": "TIS-620", + "utf_32": "UTF-32", + "euc_jp": "EUC-JP", + "koi8_r": "KOI8-R", + "iso8859_1": "ISO-8859-1", + "iso8859_2": "ISO-8859-2", + "iso8859_5": "ISO-8859-5", + "iso8859_6": "ISO-8859-6", + "iso8859_7": "ISO-8859-7", + "iso8859_8": "ISO-8859-8", + "utf_16": "UTF-16", + "cp855": "IBM855", + "mac_cyrillic": "MacCyrillic", + "gb2312": "GB2312", + "gb18030": "GB18030", + "cp932": "CP932", + "cp866": "IBM866", + "utf_8": "utf-8", + "utf_8_sig": "UTF-8-SIG", + "shift_jis": "SHIFT_JIS", + "big5": "Big5", + "cp1250": "windows-1250", + "cp1251": "windows-1251", + "cp1252": "Windows-1252", + "cp1253": "windows-1253", + "cp1255": "windows-1255", + "cp1256": "windows-1256", + "cp1254": "Windows-1254", + "cp949": "CP949", +} + + +COMMON_SAFE_ASCII_CHARACTERS: Set[str] = { + "<", + ">", + "=", + ":", + "/", + "&", + ";", + "{", + "}", + "[", + "]", + ",", + "|", + '"', + "-", +} + + +KO_NAMES: Set[str] = {"johab", "cp949", "euc_kr"} +ZH_NAMES: Set[str] = {"big5", "cp950", "big5hkscs", "hz"} + +# Logging LEVEL below DEBUG +TRACE: int = 5 + + +# Language label that contain the em dash "—" +# character are to be considered alternative seq to origin +FREQUENCIES: Dict[str, List[str]] = { + "English": [ + "e", + "a", + "t", + "i", + "o", + "n", + "s", + "r", + "h", + "l", + "d", + "c", + "u", + "m", + "f", + "p", + "g", + "w", + "y", + "b", + "v", + "k", + "x", + "j", + "z", + "q", + ], + "English—": [ + "e", + "a", + "t", + "i", + "o", + "n", + "s", + "r", + "h", + "l", + "d", + "c", + "m", + "u", + "f", + "p", + "g", + "w", + "b", + "y", + "v", + "k", + "j", + "x", + "z", + "q", + ], + "German": [ + "e", + "n", + "i", + "r", + "s", + "t", + "a", + "d", + "h", + "u", + "l", + "g", + "o", + "c", + "m", + "b", + "f", + "k", + "w", + "z", + "p", + "v", + "ü", + "ä", + "ö", + "j", + ], + "French": [ + "e", + "a", + "s", + "n", + "i", + "t", + "r", + "l", + "u", + "o", + "d", + "c", + "p", + "m", + "é", + "v", + "g", + "f", + "b", + "h", + "q", + "à", + "x", + "è", + "y", + "j", + ], + "Dutch": [ + "e", + "n", + "a", + "i", + "r", + "t", + "o", + "d", + "s", + "l", + "g", + "h", + "v", + "m", + "u", + "k", + "c", + "p", + "b", + "w", + "j", + "z", + "f", + "y", + "x", + "ë", + ], + "Italian": [ + "e", + "i", + "a", + "o", + "n", + "l", + "t", + "r", + "s", + "c", + "d", + "u", + "p", + "m", + "g", + "v", + "f", + "b", + "z", + "h", + "q", + "è", + "à", + "k", + "y", + "ò", + ], + "Polish": [ + "a", + "i", + "o", + "e", + "n", + "r", + "z", + "w", + "s", + "c", + "t", + "k", + "y", + "d", + "p", + "m", + "u", + "l", + "j", + "ł", + "g", + "b", + "h", + "ą", + "ę", + "ó", + ], + "Spanish": [ + "e", + "a", + "o", + "n", + "s", + "r", + "i", + "l", + "d", + "t", + "c", + "u", + "m", + "p", + "b", + "g", + "v", + "f", + "y", + "ó", + "h", + "q", + "í", + "j", + "z", + "á", + ], + "Russian": [ + "о", + "а", + "е", + "и", + "н", + "с", + "т", + "р", + "в", + "л", + "к", + "м", + "д", + "п", + "у", + "г", + "я", + "ы", + "з", + "б", + "й", + "ь", + "ч", + "х", + "ж", + "ц", + ], + # Jap-Kanji + "Japanese": [ + "人", + "一", + "大", + "亅", + "丁", + "丨", + "竹", + "笑", + "口", + "日", + "今", + "二", + "彳", + "行", + "十", + "土", + "丶", + "寸", + "寺", + "時", + "乙", + "丿", + "乂", + "气", + "気", + "冂", + "巾", + "亠", + "市", + "目", + "儿", + "見", + "八", + "小", + "凵", + "県", + "月", + "彐", + "門", + "間", + "木", + "東", + "山", + "出", + "本", + "中", + "刀", + "分", + "耳", + "又", + "取", + "最", + "言", + "田", + "心", + "思", + "刂", + "前", + "京", + "尹", + "事", + "生", + "厶", + "云", + "会", + "未", + "来", + "白", + "冫", + "楽", + "灬", + "馬", + "尸", + "尺", + "駅", + "明", + "耂", + "者", + "了", + "阝", + "都", + "高", + "卜", + "占", + "厂", + "广", + "店", + "子", + "申", + "奄", + "亻", + "俺", + "上", + "方", + "冖", + "学", + "衣", + "艮", + "食", + "自", + ], + # Jap-Katakana + "Japanese—": [ + "ー", + "ン", + "ス", + "・", + "ル", + "ト", + "リ", + "イ", + "ア", + "ラ", + "ッ", + "ク", + "ド", + "シ", + "レ", + "ジ", + "タ", + "フ", + "ロ", + "カ", + "テ", + "マ", + "ィ", + "グ", + "バ", + "ム", + "プ", + "オ", + "コ", + "デ", + "ニ", + "ウ", + "メ", + "サ", + "ビ", + "ナ", + "ブ", + "ャ", + "エ", + "ュ", + "チ", + "キ", + "ズ", + "ダ", + "パ", + "ミ", + "ェ", + "ョ", + "ハ", + "セ", + "ベ", + "ガ", + "モ", + "ツ", + "ネ", + "ボ", + "ソ", + "ノ", + "ァ", + "ヴ", + "ワ", + "ポ", + "ペ", + "ピ", + "ケ", + "ゴ", + "ギ", + "ザ", + "ホ", + "ゲ", + "ォ", + "ヤ", + "ヒ", + "ユ", + "ヨ", + "ヘ", + "ゼ", + "ヌ", + "ゥ", + "ゾ", + "ヶ", + "ヂ", + "ヲ", + "ヅ", + "ヵ", + "ヱ", + "ヰ", + "ヮ", + "ヽ", + "゠", + "ヾ", + "ヷ", + "ヿ", + "ヸ", + "ヹ", + "ヺ", + ], + # Jap-Hiragana + "Japanese——": [ + "の", + "に", + "る", + "た", + "と", + "は", + "し", + "い", + "を", + "で", + "て", + "が", + "な", + "れ", + "か", + "ら", + "さ", + "っ", + "り", + "す", + "あ", + "も", + "こ", + "ま", + "う", + "く", + "よ", + "き", + "ん", + "め", + "お", + "け", + "そ", + "つ", + "だ", + "や", + "え", + "ど", + "わ", + "ち", + "み", + "せ", + "じ", + "ば", + "へ", + "び", + "ず", + "ろ", + "ほ", + "げ", + "む", + "べ", + "ひ", + "ょ", + "ゆ", + "ぶ", + "ご", + "ゃ", + "ね", + "ふ", + "ぐ", + "ぎ", + "ぼ", + "ゅ", + "づ", + "ざ", + "ぞ", + "ぬ", + "ぜ", + "ぱ", + "ぽ", + "ぷ", + "ぴ", + "ぃ", + "ぁ", + "ぇ", + "ぺ", + "ゞ", + "ぢ", + "ぉ", + "ぅ", + "ゐ", + "ゝ", + "ゑ", + "゛", + "゜", + "ゎ", + "ゔ", + "゚", + "ゟ", + "゙", + "ゕ", + "ゖ", + ], + "Portuguese": [ + "a", + "e", + "o", + "s", + "i", + "r", + "d", + "n", + "t", + "m", + "u", + "c", + "l", + "p", + "g", + "v", + "b", + "f", + "h", + "ã", + "q", + "é", + "ç", + "á", + "z", + "í", + ], + "Swedish": [ + "e", + "a", + "n", + "r", + "t", + "s", + "i", + "l", + "d", + "o", + "m", + "k", + "g", + "v", + "h", + "f", + "u", + "p", + "ä", + "c", + "b", + "ö", + "å", + "y", + "j", + "x", + ], + "Chinese": [ + "的", + "一", + "是", + "不", + "了", + "在", + "人", + "有", + "我", + "他", + "这", + "个", + "们", + "中", + "来", + "上", + "大", + "为", + "和", + "国", + "地", + "到", + "以", + "说", + "时", + "要", + "就", + "出", + "会", + "可", + "也", + "你", + "对", + "生", + "能", + "而", + "子", + "那", + "得", + "于", + "着", + "下", + "自", + "之", + "年", + "过", + "发", + "后", + "作", + "里", + "用", + "道", + "行", + "所", + "然", + "家", + "种", + "事", + "成", + "方", + "多", + "经", + "么", + "去", + "法", + "学", + "如", + "都", + "同", + "现", + "当", + "没", + "动", + "面", + "起", + "看", + "定", + "天", + "分", + "还", + "进", + "好", + "小", + "部", + "其", + "些", + "主", + "样", + "理", + "心", + "她", + "本", + "前", + "开", + "但", + "因", + "只", + "从", + "想", + "实", + ], + "Ukrainian": [ + "о", + "а", + "н", + "і", + "и", + "р", + "в", + "т", + "е", + "с", + "к", + "л", + "у", + "д", + "м", + "п", + "з", + "я", + "ь", + "б", + "г", + "й", + "ч", + "х", + "ц", + "ї", + ], + "Norwegian": [ + "e", + "r", + "n", + "t", + "a", + "s", + "i", + "o", + "l", + "d", + "g", + "k", + "m", + "v", + "f", + "p", + "u", + "b", + "h", + "å", + "y", + "j", + "ø", + "c", + "æ", + "w", + ], + "Finnish": [ + "a", + "i", + "n", + "t", + "e", + "s", + "l", + "o", + "u", + "k", + "ä", + "m", + "r", + "v", + "j", + "h", + "p", + "y", + "d", + "ö", + "g", + "c", + "b", + "f", + "w", + "z", + ], + "Vietnamese": [ + "n", + "h", + "t", + "i", + "c", + "g", + "a", + "o", + "u", + "m", + "l", + "r", + "à", + "đ", + "s", + "e", + "v", + "p", + "b", + "y", + "ư", + "d", + "á", + "k", + "ộ", + "ế", + ], + "Czech": [ + "o", + "e", + "a", + "n", + "t", + "s", + "i", + "l", + "v", + "r", + "k", + "d", + "u", + "m", + "p", + "í", + "c", + "h", + "z", + "á", + "y", + "j", + "b", + "ě", + "é", + "ř", + ], + "Hungarian": [ + "e", + "a", + "t", + "l", + "s", + "n", + "k", + "r", + "i", + "o", + "z", + "á", + "é", + "g", + "m", + "b", + "y", + "v", + "d", + "h", + "u", + "p", + "j", + "ö", + "f", + "c", + ], + "Korean": [ + "이", + "다", + "에", + "의", + "는", + "로", + "하", + "을", + "가", + "고", + "지", + "서", + "한", + "은", + "기", + "으", + "년", + "대", + "사", + "시", + "를", + "리", + "도", + "인", + "스", + "일", + ], + "Indonesian": [ + "a", + "n", + "e", + "i", + "r", + "t", + "u", + "s", + "d", + "k", + "m", + "l", + "g", + "p", + "b", + "o", + "h", + "y", + "j", + "c", + "w", + "f", + "v", + "z", + "x", + "q", + ], + "Turkish": [ + "a", + "e", + "i", + "n", + "r", + "l", + "ı", + "k", + "d", + "t", + "s", + "m", + "y", + "u", + "o", + "b", + "ü", + "ş", + "v", + "g", + "z", + "h", + "c", + "p", + "ç", + "ğ", + ], + "Romanian": [ + "e", + "i", + "a", + "r", + "n", + "t", + "u", + "l", + "o", + "c", + "s", + "d", + "p", + "m", + "ă", + "f", + "v", + "î", + "g", + "b", + "ș", + "ț", + "z", + "h", + "â", + "j", + ], + "Farsi": [ + "ا", + "ی", + "ر", + "د", + "ن", + "ه", + "و", + "م", + "ت", + "ب", + "س", + "ل", + "ک", + "ش", + "ز", + "ف", + "گ", + "ع", + "خ", + "ق", + "ج", + "آ", + "پ", + "ح", + "ط", + "ص", + ], + "Arabic": [ + "ا", + "ل", + "ي", + "م", + "و", + "ن", + "ر", + "ت", + "ب", + "ة", + "ع", + "د", + "س", + "ف", + "ه", + "ك", + "ق", + "أ", + "ح", + "ج", + "ش", + "ط", + "ص", + "ى", + "خ", + "إ", + ], + "Danish": [ + "e", + "r", + "n", + "t", + "a", + "i", + "s", + "d", + "l", + "o", + "g", + "m", + "k", + "f", + "v", + "u", + "b", + "h", + "p", + "å", + "y", + "ø", + "æ", + "c", + "j", + "w", + ], + "Serbian": [ + "а", + "и", + "о", + "е", + "н", + "р", + "с", + "у", + "т", + "к", + "ј", + "в", + "д", + "м", + "п", + "л", + "г", + "з", + "б", + "a", + "i", + "e", + "o", + "n", + "ц", + "ш", + ], + "Lithuanian": [ + "i", + "a", + "s", + "o", + "r", + "e", + "t", + "n", + "u", + "k", + "m", + "l", + "p", + "v", + "d", + "j", + "g", + "ė", + "b", + "y", + "ų", + "š", + "ž", + "c", + "ą", + "į", + ], + "Slovene": [ + "e", + "a", + "i", + "o", + "n", + "r", + "s", + "l", + "t", + "j", + "v", + "k", + "d", + "p", + "m", + "u", + "z", + "b", + "g", + "h", + "č", + "c", + "š", + "ž", + "f", + "y", + ], + "Slovak": [ + "o", + "a", + "e", + "n", + "i", + "r", + "v", + "t", + "s", + "l", + "k", + "d", + "m", + "p", + "u", + "c", + "h", + "j", + "b", + "z", + "á", + "y", + "ý", + "í", + "č", + "é", + ], + "Hebrew": [ + "י", + "ו", + "ה", + "ל", + "ר", + "ב", + "ת", + "מ", + "א", + "ש", + "נ", + "ע", + "ם", + "ד", + "ק", + "ח", + "פ", + "ס", + "כ", + "ג", + "ט", + "צ", + "ן", + "ז", + "ך", + ], + "Bulgarian": [ + "а", + "и", + "о", + "е", + "н", + "т", + "р", + "с", + "в", + "л", + "к", + "д", + "п", + "м", + "з", + "г", + "я", + "ъ", + "у", + "б", + "ч", + "ц", + "й", + "ж", + "щ", + "х", + ], + "Croatian": [ + "a", + "i", + "o", + "e", + "n", + "r", + "j", + "s", + "t", + "u", + "k", + "l", + "v", + "d", + "m", + "p", + "g", + "z", + "b", + "c", + "č", + "h", + "š", + "ž", + "ć", + "f", + ], + "Hindi": [ + "क", + "र", + "स", + "न", + "त", + "म", + "ह", + "प", + "य", + "ल", + "व", + "ज", + "द", + "ग", + "ब", + "श", + "ट", + "अ", + "ए", + "थ", + "भ", + "ड", + "च", + "ध", + "ष", + "इ", + ], + "Estonian": [ + "a", + "i", + "e", + "s", + "t", + "l", + "u", + "n", + "o", + "k", + "r", + "d", + "m", + "v", + "g", + "p", + "j", + "h", + "ä", + "b", + "õ", + "ü", + "f", + "c", + "ö", + "y", + ], + "Thai": [ + "า", + "น", + "ร", + "อ", + "ก", + "เ", + "ง", + "ม", + "ย", + "ล", + "ว", + "ด", + "ท", + "ส", + "ต", + "ะ", + "ป", + "บ", + "ค", + "ห", + "แ", + "จ", + "พ", + "ช", + "ข", + "ใ", + ], + "Greek": [ + "α", + "τ", + "ο", + "ι", + "ε", + "ν", + "ρ", + "σ", + "κ", + "η", + "π", + "ς", + "υ", + "μ", + "λ", + "ί", + "ό", + "ά", + "γ", + "έ", + "δ", + "ή", + "ω", + "χ", + "θ", + "ύ", + ], + "Tamil": [ + "க", + "த", + "ப", + "ட", + "ர", + "ம", + "ல", + "ன", + "வ", + "ற", + "ய", + "ள", + "ச", + "ந", + "இ", + "ண", + "அ", + "ஆ", + "ழ", + "ங", + "எ", + "உ", + "ஒ", + "ஸ", + ], + "Kazakh": [ + "а", + "ы", + "е", + "н", + "т", + "р", + "л", + "і", + "д", + "с", + "м", + "қ", + "к", + "о", + "б", + "и", + "у", + "ғ", + "ж", + "ң", + "з", + "ш", + "й", + "п", + "г", + "ө", + ], +} + +LANGUAGE_SUPPORTED_COUNT: int = len(FREQUENCIES) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/legacy.py b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/legacy.py new file mode 100644 index 000000000..43aad21a9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/legacy.py @@ -0,0 +1,54 @@ +from typing import Any, Dict, Optional, Union +from warnings import warn + +from .api import from_bytes +from .constant import CHARDET_CORRESPONDENCE + + +def detect( + byte_str: bytes, should_rename_legacy: bool = False, **kwargs: Any +) -> Dict[str, Optional[Union[str, float]]]: + """ + chardet legacy method + Detect the encoding of the given byte string. It should be mostly backward-compatible. + Encoding name will match Chardet own writing whenever possible. (Not on encoding name unsupported by it) + This function is deprecated and should be used to migrate your project easily, consult the documentation for + further information. Not planned for removal. + + :param byte_str: The byte sequence to examine. + :param should_rename_legacy: Should we rename legacy encodings + to their more modern equivalents? + """ + if len(kwargs): + warn( + f"charset-normalizer disregard arguments '{','.join(list(kwargs.keys()))}' in legacy function detect()" + ) + + if not isinstance(byte_str, (bytearray, bytes)): + raise TypeError( # pragma: nocover + "Expected object of type bytes or bytearray, got: " + "{0}".format(type(byte_str)) + ) + + if isinstance(byte_str, bytearray): + byte_str = bytes(byte_str) + + r = from_bytes(byte_str).best() + + encoding = r.encoding if r is not None else None + language = r.language if r is not None and r.language != "Unknown" else "" + confidence = 1.0 - r.chaos if r is not None else None + + # Note: CharsetNormalizer does not return 'UTF-8-SIG' as the sig get stripped in the detection/normalization process + # but chardet does return 'utf-8-sig' and it is a valid codec name. + if r is not None and encoding == "utf_8" and r.bom: + encoding += "_sig" + + if should_rename_legacy is False and encoding in CHARDET_CORRESPONDENCE: + encoding = CHARDET_CORRESPONDENCE[encoding] + + return { + "encoding": encoding, + "language": language, + "confidence": confidence, + } diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/md.cpython-311-x86_64-linux-gnu.so b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/md.cpython-311-x86_64-linux-gnu.so new file mode 100755 index 000000000..3824a428f Binary files /dev/null and b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/md.cpython-311-x86_64-linux-gnu.so differ diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/md.py b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/md.py new file mode 100644 index 000000000..77897aae4 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/md.py @@ -0,0 +1,615 @@ +from functools import lru_cache +from logging import getLogger +from typing import List, Optional + +from .constant import ( + COMMON_SAFE_ASCII_CHARACTERS, + TRACE, + UNICODE_SECONDARY_RANGE_KEYWORD, +) +from .utils import ( + is_accentuated, + is_arabic, + is_arabic_isolated_form, + is_case_variable, + is_cjk, + is_emoticon, + is_hangul, + is_hiragana, + is_katakana, + is_latin, + is_punctuation, + is_separator, + is_symbol, + is_thai, + is_unprintable, + remove_accent, + unicode_range, +) + + +class MessDetectorPlugin: + """ + Base abstract class used for mess detection plugins. + All detectors MUST extend and implement given methods. + """ + + def eligible(self, character: str) -> bool: + """ + Determine if given character should be fed in. + """ + raise NotImplementedError # pragma: nocover + + def feed(self, character: str) -> None: + """ + The main routine to be executed upon character. + Insert the logic in witch the text would be considered chaotic. + """ + raise NotImplementedError # pragma: nocover + + def reset(self) -> None: # pragma: no cover + """ + Permit to reset the plugin to the initial state. + """ + raise NotImplementedError + + @property + def ratio(self) -> float: + """ + Compute the chaos ratio based on what your feed() has seen. + Must NOT be lower than 0.; No restriction gt 0. + """ + raise NotImplementedError # pragma: nocover + + +class TooManySymbolOrPunctuationPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._punctuation_count: int = 0 + self._symbol_count: int = 0 + self._character_count: int = 0 + + self._last_printable_char: Optional[str] = None + self._frenzy_symbol_in_word: bool = False + + def eligible(self, character: str) -> bool: + return character.isprintable() + + def feed(self, character: str) -> None: + self._character_count += 1 + + if ( + character != self._last_printable_char + and character not in COMMON_SAFE_ASCII_CHARACTERS + ): + if is_punctuation(character): + self._punctuation_count += 1 + elif ( + character.isdigit() is False + and is_symbol(character) + and is_emoticon(character) is False + ): + self._symbol_count += 2 + + self._last_printable_char = character + + def reset(self) -> None: # pragma: no cover + self._punctuation_count = 0 + self._character_count = 0 + self._symbol_count = 0 + + @property + def ratio(self) -> float: + if self._character_count == 0: + return 0.0 + + ratio_of_punctuation: float = ( + self._punctuation_count + self._symbol_count + ) / self._character_count + + return ratio_of_punctuation if ratio_of_punctuation >= 0.3 else 0.0 + + +class TooManyAccentuatedPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._character_count: int = 0 + self._accentuated_count: int = 0 + + def eligible(self, character: str) -> bool: + return character.isalpha() + + def feed(self, character: str) -> None: + self._character_count += 1 + + if is_accentuated(character): + self._accentuated_count += 1 + + def reset(self) -> None: # pragma: no cover + self._character_count = 0 + self._accentuated_count = 0 + + @property + def ratio(self) -> float: + if self._character_count < 8: + return 0.0 + + ratio_of_accentuation: float = self._accentuated_count / self._character_count + return ratio_of_accentuation if ratio_of_accentuation >= 0.35 else 0.0 + + +class UnprintablePlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._unprintable_count: int = 0 + self._character_count: int = 0 + + def eligible(self, character: str) -> bool: + return True + + def feed(self, character: str) -> None: + if is_unprintable(character): + self._unprintable_count += 1 + self._character_count += 1 + + def reset(self) -> None: # pragma: no cover + self._unprintable_count = 0 + + @property + def ratio(self) -> float: + if self._character_count == 0: + return 0.0 + + return (self._unprintable_count * 8) / self._character_count + + +class SuspiciousDuplicateAccentPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._successive_count: int = 0 + self._character_count: int = 0 + + self._last_latin_character: Optional[str] = None + + def eligible(self, character: str) -> bool: + return character.isalpha() and is_latin(character) + + def feed(self, character: str) -> None: + self._character_count += 1 + if ( + self._last_latin_character is not None + and is_accentuated(character) + and is_accentuated(self._last_latin_character) + ): + if character.isupper() and self._last_latin_character.isupper(): + self._successive_count += 1 + # Worse if its the same char duplicated with different accent. + if remove_accent(character) == remove_accent(self._last_latin_character): + self._successive_count += 1 + self._last_latin_character = character + + def reset(self) -> None: # pragma: no cover + self._successive_count = 0 + self._character_count = 0 + self._last_latin_character = None + + @property + def ratio(self) -> float: + if self._character_count == 0: + return 0.0 + + return (self._successive_count * 2) / self._character_count + + +class SuspiciousRange(MessDetectorPlugin): + def __init__(self) -> None: + self._suspicious_successive_range_count: int = 0 + self._character_count: int = 0 + self._last_printable_seen: Optional[str] = None + + def eligible(self, character: str) -> bool: + return character.isprintable() + + def feed(self, character: str) -> None: + self._character_count += 1 + + if ( + character.isspace() + or is_punctuation(character) + or character in COMMON_SAFE_ASCII_CHARACTERS + ): + self._last_printable_seen = None + return + + if self._last_printable_seen is None: + self._last_printable_seen = character + return + + unicode_range_a: Optional[str] = unicode_range(self._last_printable_seen) + unicode_range_b: Optional[str] = unicode_range(character) + + if is_suspiciously_successive_range(unicode_range_a, unicode_range_b): + self._suspicious_successive_range_count += 1 + + self._last_printable_seen = character + + def reset(self) -> None: # pragma: no cover + self._character_count = 0 + self._suspicious_successive_range_count = 0 + self._last_printable_seen = None + + @property + def ratio(self) -> float: + if self._character_count <= 24: + return 0.0 + + ratio_of_suspicious_range_usage: float = ( + self._suspicious_successive_range_count * 2 + ) / self._character_count + + return ratio_of_suspicious_range_usage + + +class SuperWeirdWordPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._word_count: int = 0 + self._bad_word_count: int = 0 + self._foreign_long_count: int = 0 + + self._is_current_word_bad: bool = False + self._foreign_long_watch: bool = False + + self._character_count: int = 0 + self._bad_character_count: int = 0 + + self._buffer: str = "" + self._buffer_accent_count: int = 0 + + def eligible(self, character: str) -> bool: + return True + + def feed(self, character: str) -> None: + if character.isalpha(): + self._buffer += character + if is_accentuated(character): + self._buffer_accent_count += 1 + if ( + self._foreign_long_watch is False + and (is_latin(character) is False or is_accentuated(character)) + and is_cjk(character) is False + and is_hangul(character) is False + and is_katakana(character) is False + and is_hiragana(character) is False + and is_thai(character) is False + ): + self._foreign_long_watch = True + return + if not self._buffer: + return + if ( + character.isspace() or is_punctuation(character) or is_separator(character) + ) and self._buffer: + self._word_count += 1 + buffer_length: int = len(self._buffer) + + self._character_count += buffer_length + + if buffer_length >= 4: + if self._buffer_accent_count / buffer_length > 0.34: + self._is_current_word_bad = True + # Word/Buffer ending with an upper case accentuated letter are so rare, + # that we will consider them all as suspicious. Same weight as foreign_long suspicious. + if ( + is_accentuated(self._buffer[-1]) + and self._buffer[-1].isupper() + and all(_.isupper() for _ in self._buffer) is False + ): + self._foreign_long_count += 1 + self._is_current_word_bad = True + if buffer_length >= 24 and self._foreign_long_watch: + camel_case_dst = [ + i + for c, i in zip(self._buffer, range(0, buffer_length)) + if c.isupper() + ] + probable_camel_cased: bool = False + + if camel_case_dst and (len(camel_case_dst) / buffer_length <= 0.3): + probable_camel_cased = True + + if not probable_camel_cased: + self._foreign_long_count += 1 + self._is_current_word_bad = True + + if self._is_current_word_bad: + self._bad_word_count += 1 + self._bad_character_count += len(self._buffer) + self._is_current_word_bad = False + + self._foreign_long_watch = False + self._buffer = "" + self._buffer_accent_count = 0 + elif ( + character not in {"<", ">", "-", "=", "~", "|", "_"} + and character.isdigit() is False + and is_symbol(character) + ): + self._is_current_word_bad = True + self._buffer += character + + def reset(self) -> None: # pragma: no cover + self._buffer = "" + self._is_current_word_bad = False + self._foreign_long_watch = False + self._bad_word_count = 0 + self._word_count = 0 + self._character_count = 0 + self._bad_character_count = 0 + self._foreign_long_count = 0 + + @property + def ratio(self) -> float: + if self._word_count <= 10 and self._foreign_long_count == 0: + return 0.0 + + return self._bad_character_count / self._character_count + + +class CjkInvalidStopPlugin(MessDetectorPlugin): + """ + GB(Chinese) based encoding often render the stop incorrectly when the content does not fit and + can be easily detected. Searching for the overuse of '丅' and '丄'. + """ + + def __init__(self) -> None: + self._wrong_stop_count: int = 0 + self._cjk_character_count: int = 0 + + def eligible(self, character: str) -> bool: + return True + + def feed(self, character: str) -> None: + if character in {"丅", "丄"}: + self._wrong_stop_count += 1 + return + if is_cjk(character): + self._cjk_character_count += 1 + + def reset(self) -> None: # pragma: no cover + self._wrong_stop_count = 0 + self._cjk_character_count = 0 + + @property + def ratio(self) -> float: + if self._cjk_character_count < 16: + return 0.0 + return self._wrong_stop_count / self._cjk_character_count + + +class ArchaicUpperLowerPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._buf: bool = False + + self._character_count_since_last_sep: int = 0 + + self._successive_upper_lower_count: int = 0 + self._successive_upper_lower_count_final: int = 0 + + self._character_count: int = 0 + + self._last_alpha_seen: Optional[str] = None + self._current_ascii_only: bool = True + + def eligible(self, character: str) -> bool: + return True + + def feed(self, character: str) -> None: + is_concerned = character.isalpha() and is_case_variable(character) + chunk_sep = is_concerned is False + + if chunk_sep and self._character_count_since_last_sep > 0: + if ( + self._character_count_since_last_sep <= 64 + and character.isdigit() is False + and self._current_ascii_only is False + ): + self._successive_upper_lower_count_final += ( + self._successive_upper_lower_count + ) + + self._successive_upper_lower_count = 0 + self._character_count_since_last_sep = 0 + self._last_alpha_seen = None + self._buf = False + self._character_count += 1 + self._current_ascii_only = True + + return + + if self._current_ascii_only is True and character.isascii() is False: + self._current_ascii_only = False + + if self._last_alpha_seen is not None: + if (character.isupper() and self._last_alpha_seen.islower()) or ( + character.islower() and self._last_alpha_seen.isupper() + ): + if self._buf is True: + self._successive_upper_lower_count += 2 + self._buf = False + else: + self._buf = True + else: + self._buf = False + + self._character_count += 1 + self._character_count_since_last_sep += 1 + self._last_alpha_seen = character + + def reset(self) -> None: # pragma: no cover + self._character_count = 0 + self._character_count_since_last_sep = 0 + self._successive_upper_lower_count = 0 + self._successive_upper_lower_count_final = 0 + self._last_alpha_seen = None + self._buf = False + self._current_ascii_only = True + + @property + def ratio(self) -> float: + if self._character_count == 0: + return 0.0 + + return self._successive_upper_lower_count_final / self._character_count + + +class ArabicIsolatedFormPlugin(MessDetectorPlugin): + def __init__(self) -> None: + self._character_count: int = 0 + self._isolated_form_count: int = 0 + + def reset(self) -> None: # pragma: no cover + self._character_count = 0 + self._isolated_form_count = 0 + + def eligible(self, character: str) -> bool: + return is_arabic(character) + + def feed(self, character: str) -> None: + self._character_count += 1 + + if is_arabic_isolated_form(character): + self._isolated_form_count += 1 + + @property + def ratio(self) -> float: + if self._character_count < 8: + return 0.0 + + isolated_form_usage: float = self._isolated_form_count / self._character_count + + return isolated_form_usage + + +@lru_cache(maxsize=1024) +def is_suspiciously_successive_range( + unicode_range_a: Optional[str], unicode_range_b: Optional[str] +) -> bool: + """ + Determine if two Unicode range seen next to each other can be considered as suspicious. + """ + if unicode_range_a is None or unicode_range_b is None: + return True + + if unicode_range_a == unicode_range_b: + return False + + if "Latin" in unicode_range_a and "Latin" in unicode_range_b: + return False + + if "Emoticons" in unicode_range_a or "Emoticons" in unicode_range_b: + return False + + # Latin characters can be accompanied with a combining diacritical mark + # eg. Vietnamese. + if ("Latin" in unicode_range_a or "Latin" in unicode_range_b) and ( + "Combining" in unicode_range_a or "Combining" in unicode_range_b + ): + return False + + keywords_range_a, keywords_range_b = unicode_range_a.split( + " " + ), unicode_range_b.split(" ") + + for el in keywords_range_a: + if el in UNICODE_SECONDARY_RANGE_KEYWORD: + continue + if el in keywords_range_b: + return False + + # Japanese Exception + range_a_jp_chars, range_b_jp_chars = ( + unicode_range_a + in ( + "Hiragana", + "Katakana", + ), + unicode_range_b in ("Hiragana", "Katakana"), + ) + if (range_a_jp_chars or range_b_jp_chars) and ( + "CJK" in unicode_range_a or "CJK" in unicode_range_b + ): + return False + if range_a_jp_chars and range_b_jp_chars: + return False + + if "Hangul" in unicode_range_a or "Hangul" in unicode_range_b: + if "CJK" in unicode_range_a or "CJK" in unicode_range_b: + return False + if unicode_range_a == "Basic Latin" or unicode_range_b == "Basic Latin": + return False + + # Chinese/Japanese use dedicated range for punctuation and/or separators. + if ("CJK" in unicode_range_a or "CJK" in unicode_range_b) or ( + unicode_range_a in ["Katakana", "Hiragana"] + and unicode_range_b in ["Katakana", "Hiragana"] + ): + if "Punctuation" in unicode_range_a or "Punctuation" in unicode_range_b: + return False + if "Forms" in unicode_range_a or "Forms" in unicode_range_b: + return False + if unicode_range_a == "Basic Latin" or unicode_range_b == "Basic Latin": + return False + + return True + + +@lru_cache(maxsize=2048) +def mess_ratio( + decoded_sequence: str, maximum_threshold: float = 0.2, debug: bool = False +) -> float: + """ + Compute a mess ratio given a decoded bytes sequence. The maximum threshold does stop the computation earlier. + """ + + detectors: List[MessDetectorPlugin] = [ + md_class() for md_class in MessDetectorPlugin.__subclasses__() + ] + + length: int = len(decoded_sequence) + 1 + + mean_mess_ratio: float = 0.0 + + if length < 512: + intermediary_mean_mess_ratio_calc: int = 32 + elif length <= 1024: + intermediary_mean_mess_ratio_calc = 64 + else: + intermediary_mean_mess_ratio_calc = 128 + + for character, index in zip(decoded_sequence + "\n", range(length)): + for detector in detectors: + if detector.eligible(character): + detector.feed(character) + + if ( + index > 0 and index % intermediary_mean_mess_ratio_calc == 0 + ) or index == length - 1: + mean_mess_ratio = sum(dt.ratio for dt in detectors) + + if mean_mess_ratio >= maximum_threshold: + break + + if debug: + logger = getLogger("charset_normalizer") + + logger.log( + TRACE, + "Mess-detector extended-analysis start. " + f"intermediary_mean_mess_ratio_calc={intermediary_mean_mess_ratio_calc} mean_mess_ratio={mean_mess_ratio} " + f"maximum_threshold={maximum_threshold}", + ) + + if len(decoded_sequence) > 16: + logger.log(TRACE, f"Starting with: {decoded_sequence[:16]}") + logger.log(TRACE, f"Ending with: {decoded_sequence[-16::]}") + + for dt in detectors: # pragma: nocover + logger.log(TRACE, f"{dt.__class__}: {dt.ratio}") + + return round(mean_mess_ratio, 3) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/md__mypyc.cpython-311-x86_64-linux-gnu.so b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/md__mypyc.cpython-311-x86_64-linux-gnu.so new file mode 100755 index 000000000..47e80b8af Binary files /dev/null and b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/md__mypyc.cpython-311-x86_64-linux-gnu.so differ diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/models.py b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/models.py new file mode 100644 index 000000000..a760b9c55 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/models.py @@ -0,0 +1,340 @@ +from encodings.aliases import aliases +from hashlib import sha256 +from json import dumps +from typing import Any, Dict, Iterator, List, Optional, Tuple, Union + +from .constant import TOO_BIG_SEQUENCE +from .utils import iana_name, is_multi_byte_encoding, unicode_range + + +class CharsetMatch: + def __init__( + self, + payload: bytes, + guessed_encoding: str, + mean_mess_ratio: float, + has_sig_or_bom: bool, + languages: "CoherenceMatches", + decoded_payload: Optional[str] = None, + ): + self._payload: bytes = payload + + self._encoding: str = guessed_encoding + self._mean_mess_ratio: float = mean_mess_ratio + self._languages: CoherenceMatches = languages + self._has_sig_or_bom: bool = has_sig_or_bom + self._unicode_ranges: Optional[List[str]] = None + + self._leaves: List[CharsetMatch] = [] + self._mean_coherence_ratio: float = 0.0 + + self._output_payload: Optional[bytes] = None + self._output_encoding: Optional[str] = None + + self._string: Optional[str] = decoded_payload + + def __eq__(self, other: object) -> bool: + if not isinstance(other, CharsetMatch): + raise TypeError( + "__eq__ cannot be invoked on {} and {}.".format( + str(other.__class__), str(self.__class__) + ) + ) + return self.encoding == other.encoding and self.fingerprint == other.fingerprint + + def __lt__(self, other: object) -> bool: + """ + Implemented to make sorted available upon CharsetMatches items. + """ + if not isinstance(other, CharsetMatch): + raise ValueError + + chaos_difference: float = abs(self.chaos - other.chaos) + coherence_difference: float = abs(self.coherence - other.coherence) + + # Below 1% difference --> Use Coherence + if chaos_difference < 0.01 and coherence_difference > 0.02: + return self.coherence > other.coherence + elif chaos_difference < 0.01 and coherence_difference <= 0.02: + # When having a difficult decision, use the result that decoded as many multi-byte as possible. + # preserve RAM usage! + if len(self._payload) >= TOO_BIG_SEQUENCE: + return self.chaos < other.chaos + return self.multi_byte_usage > other.multi_byte_usage + + return self.chaos < other.chaos + + @property + def multi_byte_usage(self) -> float: + return 1.0 - (len(str(self)) / len(self.raw)) + + def __str__(self) -> str: + # Lazy Str Loading + if self._string is None: + self._string = str(self._payload, self._encoding, "strict") + return self._string + + def __repr__(self) -> str: + return "".format(self.encoding, self.fingerprint) + + def add_submatch(self, other: "CharsetMatch") -> None: + if not isinstance(other, CharsetMatch) or other == self: + raise ValueError( + "Unable to add instance <{}> as a submatch of a CharsetMatch".format( + other.__class__ + ) + ) + + other._string = None # Unload RAM usage; dirty trick. + self._leaves.append(other) + + @property + def encoding(self) -> str: + return self._encoding + + @property + def encoding_aliases(self) -> List[str]: + """ + Encoding name are known by many name, using this could help when searching for IBM855 when it's listed as CP855. + """ + also_known_as: List[str] = [] + for u, p in aliases.items(): + if self.encoding == u: + also_known_as.append(p) + elif self.encoding == p: + also_known_as.append(u) + return also_known_as + + @property + def bom(self) -> bool: + return self._has_sig_or_bom + + @property + def byte_order_mark(self) -> bool: + return self._has_sig_or_bom + + @property + def languages(self) -> List[str]: + """ + Return the complete list of possible languages found in decoded sequence. + Usually not really useful. Returned list may be empty even if 'language' property return something != 'Unknown'. + """ + return [e[0] for e in self._languages] + + @property + def language(self) -> str: + """ + Most probable language found in decoded sequence. If none were detected or inferred, the property will return + "Unknown". + """ + if not self._languages: + # Trying to infer the language based on the given encoding + # Its either English or we should not pronounce ourselves in certain cases. + if "ascii" in self.could_be_from_charset: + return "English" + + # doing it there to avoid circular import + from charset_normalizer.cd import encoding_languages, mb_encoding_languages + + languages = ( + mb_encoding_languages(self.encoding) + if is_multi_byte_encoding(self.encoding) + else encoding_languages(self.encoding) + ) + + if len(languages) == 0 or "Latin Based" in languages: + return "Unknown" + + return languages[0] + + return self._languages[0][0] + + @property + def chaos(self) -> float: + return self._mean_mess_ratio + + @property + def coherence(self) -> float: + if not self._languages: + return 0.0 + return self._languages[0][1] + + @property + def percent_chaos(self) -> float: + return round(self.chaos * 100, ndigits=3) + + @property + def percent_coherence(self) -> float: + return round(self.coherence * 100, ndigits=3) + + @property + def raw(self) -> bytes: + """ + Original untouched bytes. + """ + return self._payload + + @property + def submatch(self) -> List["CharsetMatch"]: + return self._leaves + + @property + def has_submatch(self) -> bool: + return len(self._leaves) > 0 + + @property + def alphabets(self) -> List[str]: + if self._unicode_ranges is not None: + return self._unicode_ranges + # list detected ranges + detected_ranges: List[Optional[str]] = [ + unicode_range(char) for char in str(self) + ] + # filter and sort + self._unicode_ranges = sorted(list({r for r in detected_ranges if r})) + return self._unicode_ranges + + @property + def could_be_from_charset(self) -> List[str]: + """ + The complete list of encoding that output the exact SAME str result and therefore could be the originating + encoding. + This list does include the encoding available in property 'encoding'. + """ + return [self._encoding] + [m.encoding for m in self._leaves] + + def output(self, encoding: str = "utf_8") -> bytes: + """ + Method to get re-encoded bytes payload using given target encoding. Default to UTF-8. + Any errors will be simply ignored by the encoder NOT replaced. + """ + if self._output_encoding is None or self._output_encoding != encoding: + self._output_encoding = encoding + self._output_payload = str(self).encode(encoding, "replace") + + return self._output_payload # type: ignore + + @property + def fingerprint(self) -> str: + """ + Retrieve the unique SHA256 computed using the transformed (re-encoded) payload. Not the original one. + """ + return sha256(self.output()).hexdigest() + + +class CharsetMatches: + """ + Container with every CharsetMatch items ordered by default from most probable to the less one. + Act like a list(iterable) but does not implements all related methods. + """ + + def __init__(self, results: Optional[List[CharsetMatch]] = None): + self._results: List[CharsetMatch] = sorted(results) if results else [] + + def __iter__(self) -> Iterator[CharsetMatch]: + yield from self._results + + def __getitem__(self, item: Union[int, str]) -> CharsetMatch: + """ + Retrieve a single item either by its position or encoding name (alias may be used here). + Raise KeyError upon invalid index or encoding not present in results. + """ + if isinstance(item, int): + return self._results[item] + if isinstance(item, str): + item = iana_name(item, False) + for result in self._results: + if item in result.could_be_from_charset: + return result + raise KeyError + + def __len__(self) -> int: + return len(self._results) + + def __bool__(self) -> bool: + return len(self._results) > 0 + + def append(self, item: CharsetMatch) -> None: + """ + Insert a single match. Will be inserted accordingly to preserve sort. + Can be inserted as a submatch. + """ + if not isinstance(item, CharsetMatch): + raise ValueError( + "Cannot append instance '{}' to CharsetMatches".format( + str(item.__class__) + ) + ) + # We should disable the submatch factoring when the input file is too heavy (conserve RAM usage) + if len(item.raw) <= TOO_BIG_SEQUENCE: + for match in self._results: + if match.fingerprint == item.fingerprint and match.chaos == item.chaos: + match.add_submatch(item) + return + self._results.append(item) + self._results = sorted(self._results) + + def best(self) -> Optional["CharsetMatch"]: + """ + Simply return the first match. Strict equivalent to matches[0]. + """ + if not self._results: + return None + return self._results[0] + + def first(self) -> Optional["CharsetMatch"]: + """ + Redundant method, call the method best(). Kept for BC reasons. + """ + return self.best() + + +CoherenceMatch = Tuple[str, float] +CoherenceMatches = List[CoherenceMatch] + + +class CliDetectionResult: + def __init__( + self, + path: str, + encoding: Optional[str], + encoding_aliases: List[str], + alternative_encodings: List[str], + language: str, + alphabets: List[str], + has_sig_or_bom: bool, + chaos: float, + coherence: float, + unicode_path: Optional[str], + is_preferred: bool, + ): + self.path: str = path + self.unicode_path: Optional[str] = unicode_path + self.encoding: Optional[str] = encoding + self.encoding_aliases: List[str] = encoding_aliases + self.alternative_encodings: List[str] = alternative_encodings + self.language: str = language + self.alphabets: List[str] = alphabets + self.has_sig_or_bom: bool = has_sig_or_bom + self.chaos: float = chaos + self.coherence: float = coherence + self.is_preferred: bool = is_preferred + + @property + def __dict__(self) -> Dict[str, Any]: # type: ignore + return { + "path": self.path, + "encoding": self.encoding, + "encoding_aliases": self.encoding_aliases, + "alternative_encodings": self.alternative_encodings, + "language": self.language, + "alphabets": self.alphabets, + "has_sig_or_bom": self.has_sig_or_bom, + "chaos": self.chaos, + "coherence": self.coherence, + "unicode_path": self.unicode_path, + "is_preferred": self.is_preferred, + } + + def to_json(self) -> str: + return dumps(self.__dict__, ensure_ascii=True, indent=4) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/py.typed b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/utils.py b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/utils.py new file mode 100644 index 000000000..e5cbbf4c0 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/utils.py @@ -0,0 +1,421 @@ +import importlib +import logging +import unicodedata +from codecs import IncrementalDecoder +from encodings.aliases import aliases +from functools import lru_cache +from re import findall +from typing import Generator, List, Optional, Set, Tuple, Union + +from _multibytecodec import MultibyteIncrementalDecoder + +from .constant import ( + ENCODING_MARKS, + IANA_SUPPORTED_SIMILAR, + RE_POSSIBLE_ENCODING_INDICATION, + UNICODE_RANGES_COMBINED, + UNICODE_SECONDARY_RANGE_KEYWORD, + UTF8_MAXIMAL_ALLOCATION, +) + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_accentuated(character: str) -> bool: + try: + description: str = unicodedata.name(character) + except ValueError: + return False + return ( + "WITH GRAVE" in description + or "WITH ACUTE" in description + or "WITH CEDILLA" in description + or "WITH DIAERESIS" in description + or "WITH CIRCUMFLEX" in description + or "WITH TILDE" in description + or "WITH MACRON" in description + or "WITH RING ABOVE" in description + ) + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def remove_accent(character: str) -> str: + decomposed: str = unicodedata.decomposition(character) + if not decomposed: + return character + + codes: List[str] = decomposed.split(" ") + + return chr(int(codes[0], 16)) + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def unicode_range(character: str) -> Optional[str]: + """ + Retrieve the Unicode range official name from a single character. + """ + character_ord: int = ord(character) + + for range_name, ord_range in UNICODE_RANGES_COMBINED.items(): + if character_ord in ord_range: + return range_name + + return None + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_latin(character: str) -> bool: + try: + description: str = unicodedata.name(character) + except ValueError: + return False + return "LATIN" in description + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_punctuation(character: str) -> bool: + character_category: str = unicodedata.category(character) + + if "P" in character_category: + return True + + character_range: Optional[str] = unicode_range(character) + + if character_range is None: + return False + + return "Punctuation" in character_range + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_symbol(character: str) -> bool: + character_category: str = unicodedata.category(character) + + if "S" in character_category or "N" in character_category: + return True + + character_range: Optional[str] = unicode_range(character) + + if character_range is None: + return False + + return "Forms" in character_range and character_category != "Lo" + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_emoticon(character: str) -> bool: + character_range: Optional[str] = unicode_range(character) + + if character_range is None: + return False + + return "Emoticons" in character_range or "Pictographs" in character_range + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_separator(character: str) -> bool: + if character.isspace() or character in {"|", "+", "<", ">"}: + return True + + character_category: str = unicodedata.category(character) + + return "Z" in character_category or character_category in {"Po", "Pd", "Pc"} + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_case_variable(character: str) -> bool: + return character.islower() != character.isupper() + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_cjk(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: + return False + + return "CJK" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_hiragana(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: + return False + + return "HIRAGANA" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_katakana(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: + return False + + return "KATAKANA" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_hangul(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: + return False + + return "HANGUL" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_thai(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: + return False + + return "THAI" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_arabic(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: + return False + + return "ARABIC" in character_name + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_arabic_isolated_form(character: str) -> bool: + try: + character_name = unicodedata.name(character) + except ValueError: + return False + + return "ARABIC" in character_name and "ISOLATED FORM" in character_name + + +@lru_cache(maxsize=len(UNICODE_RANGES_COMBINED)) +def is_unicode_range_secondary(range_name: str) -> bool: + return any(keyword in range_name for keyword in UNICODE_SECONDARY_RANGE_KEYWORD) + + +@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION) +def is_unprintable(character: str) -> bool: + return ( + character.isspace() is False # includes \n \t \r \v + and character.isprintable() is False + and character != "\x1A" # Why? Its the ASCII substitute character. + and character != "\ufeff" # bug discovered in Python, + # Zero Width No-Break Space located in Arabic Presentation Forms-B, Unicode 1.1 not acknowledged as space. + ) + + +def any_specified_encoding(sequence: bytes, search_zone: int = 8192) -> Optional[str]: + """ + Extract using ASCII-only decoder any specified encoding in the first n-bytes. + """ + if not isinstance(sequence, bytes): + raise TypeError + + seq_len: int = len(sequence) + + results: List[str] = findall( + RE_POSSIBLE_ENCODING_INDICATION, + sequence[: min(seq_len, search_zone)].decode("ascii", errors="ignore"), + ) + + if len(results) == 0: + return None + + for specified_encoding in results: + specified_encoding = specified_encoding.lower().replace("-", "_") + + encoding_alias: str + encoding_iana: str + + for encoding_alias, encoding_iana in aliases.items(): + if encoding_alias == specified_encoding: + return encoding_iana + if encoding_iana == specified_encoding: + return encoding_iana + + return None + + +@lru_cache(maxsize=128) +def is_multi_byte_encoding(name: str) -> bool: + """ + Verify is a specific encoding is a multi byte one based on it IANA name + """ + return name in { + "utf_8", + "utf_8_sig", + "utf_16", + "utf_16_be", + "utf_16_le", + "utf_32", + "utf_32_le", + "utf_32_be", + "utf_7", + } or issubclass( + importlib.import_module("encodings.{}".format(name)).IncrementalDecoder, + MultibyteIncrementalDecoder, + ) + + +def identify_sig_or_bom(sequence: bytes) -> Tuple[Optional[str], bytes]: + """ + Identify and extract SIG/BOM in given sequence. + """ + + for iana_encoding in ENCODING_MARKS: + marks: Union[bytes, List[bytes]] = ENCODING_MARKS[iana_encoding] + + if isinstance(marks, bytes): + marks = [marks] + + for mark in marks: + if sequence.startswith(mark): + return iana_encoding, mark + + return None, b"" + + +def should_strip_sig_or_bom(iana_encoding: str) -> bool: + return iana_encoding not in {"utf_16", "utf_32"} + + +def iana_name(cp_name: str, strict: bool = True) -> str: + cp_name = cp_name.lower().replace("-", "_") + + encoding_alias: str + encoding_iana: str + + for encoding_alias, encoding_iana in aliases.items(): + if cp_name in [encoding_alias, encoding_iana]: + return encoding_iana + + if strict: + raise ValueError("Unable to retrieve IANA for '{}'".format(cp_name)) + + return cp_name + + +def range_scan(decoded_sequence: str) -> List[str]: + ranges: Set[str] = set() + + for character in decoded_sequence: + character_range: Optional[str] = unicode_range(character) + + if character_range is None: + continue + + ranges.add(character_range) + + return list(ranges) + + +def cp_similarity(iana_name_a: str, iana_name_b: str) -> float: + if is_multi_byte_encoding(iana_name_a) or is_multi_byte_encoding(iana_name_b): + return 0.0 + + decoder_a = importlib.import_module( + "encodings.{}".format(iana_name_a) + ).IncrementalDecoder + decoder_b = importlib.import_module( + "encodings.{}".format(iana_name_b) + ).IncrementalDecoder + + id_a: IncrementalDecoder = decoder_a(errors="ignore") + id_b: IncrementalDecoder = decoder_b(errors="ignore") + + character_match_count: int = 0 + + for i in range(255): + to_be_decoded: bytes = bytes([i]) + if id_a.decode(to_be_decoded) == id_b.decode(to_be_decoded): + character_match_count += 1 + + return character_match_count / 254 + + +def is_cp_similar(iana_name_a: str, iana_name_b: str) -> bool: + """ + Determine if two code page are at least 80% similar. IANA_SUPPORTED_SIMILAR dict was generated using + the function cp_similarity. + """ + return ( + iana_name_a in IANA_SUPPORTED_SIMILAR + and iana_name_b in IANA_SUPPORTED_SIMILAR[iana_name_a] + ) + + +def set_logging_handler( + name: str = "charset_normalizer", + level: int = logging.INFO, + format_string: str = "%(asctime)s | %(levelname)s | %(message)s", +) -> None: + logger = logging.getLogger(name) + logger.setLevel(level) + + handler = logging.StreamHandler() + handler.setFormatter(logging.Formatter(format_string)) + logger.addHandler(handler) + + +def cut_sequence_chunks( + sequences: bytes, + encoding_iana: str, + offsets: range, + chunk_size: int, + bom_or_sig_available: bool, + strip_sig_or_bom: bool, + sig_payload: bytes, + is_multi_byte_decoder: bool, + decoded_payload: Optional[str] = None, +) -> Generator[str, None, None]: + if decoded_payload and is_multi_byte_decoder is False: + for i in offsets: + chunk = decoded_payload[i : i + chunk_size] + if not chunk: + break + yield chunk + else: + for i in offsets: + chunk_end = i + chunk_size + if chunk_end > len(sequences) + 8: + continue + + cut_sequence = sequences[i : i + chunk_size] + + if bom_or_sig_available and strip_sig_or_bom is False: + cut_sequence = sig_payload + cut_sequence + + chunk = cut_sequence.decode( + encoding_iana, + errors="ignore" if is_multi_byte_decoder else "strict", + ) + + # multi-byte bad cutting detector and adjustment + # not the cleanest way to perform that fix but clever enough for now. + if is_multi_byte_decoder and i > 0: + chunk_partial_size_chk: int = min(chunk_size, 16) + + if ( + decoded_payload + and chunk[:chunk_partial_size_chk] not in decoded_payload + ): + for j in range(i, i - 4, -1): + cut_sequence = sequences[j:chunk_end] + + if bom_or_sig_available and strip_sig_or_bom is False: + cut_sequence = sig_payload + cut_sequence + + chunk = cut_sequence.decode(encoding_iana, errors="ignore") + + if chunk[:chunk_partial_size_chk] in decoded_payload: + break + + yield chunk diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/version.py b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/version.py new file mode 100644 index 000000000..5a4da4ff4 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/charset_normalizer/version.py @@ -0,0 +1,6 @@ +""" +Expose version +""" + +__version__ = "3.3.2" +VERSION = __version__.split(".") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr-0.5.1.dist-info/INSTALLER b/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr-0.5.1.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr-0.5.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr-0.5.1.dist-info/LICENSE.txt b/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr-0.5.1.dist-info/LICENSE.txt new file mode 100644 index 000000000..3d5c53fa1 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr-0.5.1.dist-info/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2021 Alex Hall + +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/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr-0.5.1.dist-info/METADATA b/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr-0.5.1.dist-info/METADATA new file mode 100644 index 000000000..456552d4a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr-0.5.1.dist-info/METADATA @@ -0,0 +1,197 @@ +Metadata-Version: 2.1 +Name: cheap-repr +Version: 0.5.1 +Summary: Better version of repr/reprlib for short, cheap string representations. +Home-page: https://github.com/alexmojaki/cheap_repr +Author: Alex Hall +Author-email: alex.mojaki@gmail.com +License: MIT +Platform: UNKNOWN +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.4 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Description-Content-Type: text/markdown +License-File: LICENSE.txt +Requires-Dist: qualname ; python_version == "2.7" +Provides-Extra: tests +Requires-Dist: pytest ; extra == 'tests' +Requires-Dist: Django ; extra == 'tests' +Requires-Dist: pandas (>=0.24.2) ; (platform_python_implementation != "PyPy") and extra == 'tests' +Requires-Dist: numpy (>=1.16.3) ; (platform_python_implementation != "PyPy") and extra == 'tests' +Requires-Dist: chainmap ; (python_version == "2.7") and extra == 'tests' +Requires-Dist: Django (<2) ; (python_version == "2.7") and extra == 'tests' +Requires-Dist: pandas (<0.25,>=0.24.2) ; (python_version == "2.7" and platform_python_implementation != "PyPy") and extra == 'tests' +Requires-Dist: numpy (<1.17,>=1.16.3) ; (python_version == "2.7" and platform_python_implementation != "PyPy") and extra == 'tests' +Requires-Dist: Django (<3) ; (python_version == "3.5") and extra == 'tests' +Requires-Dist: pandas (<0.26,>=0.24.2) ; (python_version == "3.5" and platform_python_implementation != "PyPy") and extra == 'tests' +Requires-Dist: numpy (<1.19,>=1.16.3) ; (python_version == "3.5" and platform_python_implementation != "PyPy") and extra == 'tests' + +cheap_repr +========== + +[![Build Status](https://github.com/alexmojaki/cheap_repr/workflows/Tests/badge.svg?branch=master)](https://github.com/alexmojaki/cheap_repr/actions) [![Coverage Status](https://coveralls.io/repos/github/alexmojaki/cheap_repr/badge.svg?branch=master)](https://coveralls.io/github/alexmojaki/cheap_repr?branch=master) [![Supports Python versions 2.7 and 3.4+, including PyPy](https://img.shields.io/pypi/pyversions/cheap_repr.svg)](https://pypi.python.org/pypi/cheap_repr) [![Join the chat at https://gitter.im/cheap_repr/Lobby](https://badges.gitter.im/cheap_repr/Lobby.svg)](https://gitter.im/cheap_repr/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +This library provides short, fast, configurable string representations, and an easy API for registering your own. It's an improvement of the standard library module `reprlib` (`repr` in Python 2). + +Just use the `cheap_repr` function instead of `repr`: + +```python +>>> from cheap_repr import cheap_repr +>>> cheap_repr(list(range(100))) +'[0, 1, 2, ..., 97, 98, 99]' +``` + +`cheap_repr` knows how to handle many different types out of the box. You can register a function for any type, and pull requests to make these part of the library are welcome. If it doesn't know how to handle a particular type, the default `repr()` is used, possibly truncated: + +```python +>>> class MyClass(object): +... def __init__(self, items): +... self.items = items +... +... def __repr__(self): +... return 'MyClass(%r)' % self.items +... +>>> c = MyClass(list(range(20))) +>>> c +MyClass([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]) +>>> cheap_repr(c) +'MyClass([0, 1, 2, 3, 4, 5, 6... 13, 14, 15, 16, 17, 18, 19])' +``` + +## Suppression of long reprs + +`cheap_repr` is meant to prevent slow, expensive computations of string representations. So if it finds that a particular class can potentially produce very long representations, the class will be *suppressed*, meaning that in future the `__repr__` won't be calculated at all: + +```python +>>> cheap_repr(MyClass(list(range(1000)))) +'MyClass([0, 1, 2, 3, 4, 5, 6...94, 995, 996, 997, 998, 999])' +.../cheap_repr/__init__.py:80: ReprSuppressedWarning: MyClass.__repr__ is too long and has been suppressed. Register a repr for the class to avoid this warning and see an informative repr again, or increase cheap_repr.suppression_threshold +>>> cheap_repr(MyClass(list(range(1000)))) +'' +``` + +`cheap_repr.suppression_threshold` refers to the attribute on the function itself, not the module. By default it's 300, meaning that a `repr` longer than 300 characters will trigger the suppression. + +## Registering your own repr function + +For example: + +```python +>>> from cheap_repr import register_repr +>>> @register_repr(MyClass) +... def repr_my_class(x, helper): +... return helper.repr_iterable(x.items, 'MyClass([', '])') +... +>>> cheap_repr(MyClass(list(range(1000)))) +'MyClass([0, 1, 2, 3, 4, 5, ...])' +``` + +In general, write a function that takes two arguments `(x, helper)` and decorate it with `register_repr(cls)`. Then `cheap_repr(x)` where `isinstance(x, cls)` will dispatch to that function, unless there is also a registered function for a subclass which `x` is also an instance of. More precisely, the function corresponding to the first class in the MRO will be used. This is in contrast to the standard library module `reprlib`, which cannot handle subclasses that aren't explicitly 'registered', or classes with the same name. + +The `helper` argument is an object with a couple of useful attributes and methods: + +- `repr_iterable(iterable, left, right, end=False, length=None)` produces a comma-separated representation of `iterable`, automatically handling nesting and iterables that are too long, surrounded by `left` and `right`. The number of items is limited to `func.maxparts` (see the configuration section below). + + Set `end=True` to include items from both the beginning and end, possibly leaving out items + in the middle. Only do this if `iterable` supports efficient slicing at the end, e.g. `iterable[-3:]`. + + Provide the `length` parameter if `len(iterable)` doesn't work. Usually this is not needed. +- `truncate(string)` returns a version of `string` at most `func.maxparts` characters long, with the middle replaced by `...` if necessary. +- `level` indicates how much nesting is still allowed in the result. If it's 0, return something minimal such as `[...]` to indicate that the original object is too deep to show all its contents. Otherwise, if you use `cheap_repr` on several items inside `x`, pass `helper.level - 1` as the second argument, e.g. `', '.join(cheap_repr(item, helper.level - 1) for item in x)`. + +## Exceptions in repr functions + +If an exception occurs in `cheap_repr`, whether from a registered repr function or the usual `__repr__`, the exception will be caught and the cheap repr of the class will be suppressed: + +```python +>>> @register_repr(MyClass) +... def repr_my_class(x, helper): +... return 'MyClass([%r, ...])' % x.items[0] +... +>>> cheap_repr(MyClass([])) +'' +.../cheap_repr/__init__.py:123: ReprSuppressedWarning: Exception 'IndexError: list index out of range' in repr_my_class for object of type MyClass. The repr has been suppressed for this type. +... +>>> cheap_repr(MyClass([1, 2, 3])) +'' +``` + +If you would prefer exceptions to bubble up normally, you can: + +1. Set `cheap_repr.raise_exceptions = True` to globally make all exceptions bubble up. +2. To bubble exceptions from the `__repr__` of a class, call `raise_exceptions_from_default_repr()`. +3. Set `repr_my_class.raise_exceptions = True` (substituting your own registered repr function) to make exceptions bubble from that function. The way to find the relevant function is in the next section. + +## Configuration: + +### Configuration for specific functions + +To configure a specific function, you set attributes on that function. To find the function corresponding to a class, use `find_repr_function`: + +```python +>>> from cheap_repr import find_repr_function +>>> find_repr_function(MyClass) + +``` + +For most functions, there are two attributes available to configure, but contributors and library writers are encouraged to add arbitrary attributes for their own functions. The first attribute is `raise_exceptions`, described in the previous section. + +### maxparts + +The other configurable attribute is `maxparts`. All registered repr functions have this attribute. It determines the maximum number of 'parts' (e.g. list elements or string characters, the meaning depends on the function) from the input that the output can display without truncation. The default value is 6. The decorator `@maxparts(n)` conveniently sets the attribute to make writing your own registered functions nicer. For example: + +```python +>>> from cheap_repr import maxparts +>>> @register_repr(MyClass) +... @maxparts(2) +... def repr_my_class(x, helper): +... return helper.repr_iterable(x.items, 'MyClass([', '])') +... +>>> cheap_repr(MyClass([1, 2, 3, 4])) +'MyClass([1, 2, ...])' +>>> find_repr_function(MyClass).maxparts = 3 +>>> cheap_repr(MyClass([1, 2, 3, 4])) +'MyClass([1, 2, 3, ...])' +``` + +### pandas + +The functions for `DataFrame`s and `Series` from the `pandas` library don't use `maxparts`. +For the `DataFrame` function there's `max_rows` and `max_cols`. For the `Series` function there's just `max_rows`. + +### level and max_level + +`cheap_repr` takes an optional argument `level` which controls the display of nested objects. Typically this decreases through recursive calls, and when it's 0, the contents of the object aren't shown. See 'Registering your own repr function' for more details. This means you can change the amount of nested data in the output of `cheap_repr` by changing the `level` argument. The default value is `cheap_repr.max_level`, which is initially 3. This means that changing `cheap_repr.max_level` will effectively change the `level` argument whenever it isn't explicitly specified. + +### Global configuration + +These things that can be configured globally: + +1. `cheap_repr.suppression_threshold`, discussed in the 'Suppression of long reprs' section. +2. The handling of exceptions, discussed in the 'Exceptions in repr functions' section, which can be changed by setting `cheap_repr.raise_exceptions = True` or calling `raise_exceptions_from_default_repr()`. +3. `cheap_repr.max_level`, discussed above. + +## Other miscellaneous functions + +`basic_repr(x)` returns a string that looks like the default `object.__repr__`. This is handy if you don't want to write your own repr function to register. Simply register this function instead, e.g. + +```python +>>> from cheap_repr import basic_repr +>>> register_repr(MyClass)(basic_repr) +>>> cheap_repr(MyClass([1, 2, 3, 4])) +'' +``` + +`normal_repr(x)` returns `repr(x)` - register it with a class to indicate that its own `__repr__` method is already fine. This prevents it from being supressed when its output is a bit long. + +`try_register_repr` is handy when you want to register a repr function for a class that may not exist, e.g. if the class is in a third party package that may not be installed. See the docstring for more details. + + diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr-0.5.1.dist-info/RECORD b/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr-0.5.1.dist-info/RECORD new file mode 100644 index 000000000..30520a120 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr-0.5.1.dist-info/RECORD @@ -0,0 +1,12 @@ +cheap_repr-0.5.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +cheap_repr-0.5.1.dist-info/LICENSE.txt,sha256=_BeYpYlsme20LrTBb0-aruQ43N8XHFB7I7qEyd0SEjM,1066 +cheap_repr-0.5.1.dist-info/METADATA,sha256=UXorqSYuRb2MMZs-uatL5RRSzZN8jiOrhz2NoFNctS4,11393 +cheap_repr-0.5.1.dist-info/RECORD,, +cheap_repr-0.5.1.dist-info/WHEEL,sha256=WzZ8cwjh8l0jtULNjYq1Hpr-WCqCRgPr--TX4P5I1Wo,110 +cheap_repr-0.5.1.dist-info/top_level.txt,sha256=zQqsNupbhApbcDH4WF5-XZYn2W6GDAgvgwFfr050fgA,11 +cheap_repr/__init__.py,sha256=tBinL5WThIXTUkP3cPCTmBnwRrPcIDsVEpTaxBKcZmI,19621 +cheap_repr/__pycache__/__init__.cpython-311.pyc,, +cheap_repr/__pycache__/utils.cpython-311.pyc,, +cheap_repr/__pycache__/version.cpython-311.pyc,, +cheap_repr/utils.py,sha256=XuslueJDeAfYiD82Q3z41y-xprGDrlvUrDkJYD8xuws,903 +cheap_repr/version.py,sha256=ot38MXI2Gybe8uk3SHIeU9fHN_Tj1M_NBr9vSEDzz0o,21 diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr-0.5.1.dist-info/WHEEL b/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr-0.5.1.dist-info/WHEEL new file mode 100644 index 000000000..b733a60d3 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr-0.5.1.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.0) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr-0.5.1.dist-info/top_level.txt b/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr-0.5.1.dist-info/top_level.txt new file mode 100644 index 000000000..fcf3d6947 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr-0.5.1.dist-info/top_level.txt @@ -0,0 +1 @@ +cheap_repr diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr/__init__.py new file mode 100644 index 000000000..ebed5f421 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr/__init__.py @@ -0,0 +1,655 @@ +""" +MIT License + +Copyright (c) 2021 Alex Hall + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +""" + +import inspect +import warnings +from array import array +from collections import defaultdict, deque +from importlib import import_module +from itertools import islice, repeat + +from cheap_repr.utils import type_name, exception_string, safe_qualname, viewitems, PY2, PY3 + +if PY2: + from itertools import izip as zip, izip_longest as zip_longest + from collections import Mapping, Set +else: + from itertools import zip_longest + from collections.abc import Mapping, Set + + +try: + from .version import __version__ +except ImportError: # pragma: no cover + # version.py is auto-generated with the git tag when building + __version__ = "???" + + +class ReprSuppressedWarning(Warning): + """ + This warning is raised when a class is supressed from having a + repr calculated for it by cheap_repr in the future. + Instead the output will be of the form: + + This can happen when either: + 1. An exception is raised by either repr(x) or f(x) where + f is a registered repr function for that class. See + 'Exceptions in repr functions' in the README for more. + 2. The output of repr(x) is longer than + cheap_repr.suppression_threshold characters. + """ + + +repr_registry = {} + + +def try_register_repr(module_name, class_name): + """ + This tries to register a repr function for a class that may not exist, + e.g. if the class is in a third party package that may not be installed. + module_name and class_name are strings. If the class can be imported, + then: + + @try_register_repr(module_name, class_name) + def repr_function(...) + ... + + is equivalent to: + + from import + @register_repr() + def repr_function(...) + ... + + If the class cannot be imported, nothing happens. + """ + try: + cls = getattr(import_module(module_name), class_name) + return register_repr(cls) + except Exception: + return lambda x: x + + +def register_repr(cls): + """ + Register a repr function for cls. The function must accept two arguments: + the object to be represented as a string, and an instance of ReprHelper. + The registered function will be used by cheap_repr when appropriate, + and can be retrieved by find_repr_function(cls). + """ + + assert inspect.isclass(cls), 'register_repr must be called with a class. ' \ + 'The type of %s is %s' % (cheap_repr(cls), type_name(cls)) + + def decorator(func): + repr_registry[cls] = func + func.__dict__.setdefault('maxparts', 6) + return func + + return decorator + + +def maxparts(num): + """ + See the maxparts section in the README. + """ + + def decorator(func): + func.maxparts = num + return func + + return decorator + + +@try_register_repr('pandas.core.internals', 'BlockManager') +def basic_repr(x, *_): + return '<%s instance at %#x>' % (type_name(x), id(x)) + + +@try_register_repr('importlib.machinery', 'ModuleSpec') +@register_repr(type(register_repr)) +@register_repr(type(_ for _ in [])) +@register_repr(type(inspect)) +def normal_repr(x, *_): + """ + Register this with a class to indicate that its own + __repr__ method is already fine. This prevents it from + being supressed when its output is a bit long. + """ + return repr(x) + + +suppressed_classes = set() + + +@register_repr(object) +@maxparts(60) +def repr_object(x, helper): + s = repr(x) + if type(x).__repr__ is object.__repr__: + return s + + if len(s) > cheap_repr.suppression_threshold: + cls = x.__class__ + suppressed_classes.add(cls) + warnings.warn(ReprSuppressedWarning( + '%s.__repr__ is too long and has been suppressed. ' + 'Register a repr for the class to avoid this warning ' + 'and see an informative repr again, ' + 'or increase cheap_repr.suppression_threshold' % safe_qualname(cls))) + return helper.truncate(s) + + +def find_repr_function(cls): + for cls in inspect.getmro(cls): + func = repr_registry.get(cls) + if func: + return func + + +__raise_exceptions_from_default_repr = False + + +def raise_exceptions_from_default_repr(): + global __raise_exceptions_from_default_repr + __raise_exceptions_from_default_repr = True + repr_object.raise_exceptions = True + + +def cheap_repr(x, level=None, target_length=None): + """ + Return a short, computationally inexpensive string + representation of x, with approximately up to `level` + levels of nesting. + """ + if level is None: + level = cheap_repr.max_level + x_cls = getattr(x, '__class__', type(x)) + for cls in inspect.getmro(x_cls): + if cls in suppressed_classes: + return _basic_but('repr suppressed', x) + func = repr_registry.get(cls) + if func: + helper = ReprHelper(level, func, target_length) + return _try_repr(func, x, helper) + + # Old-style classes in Python 2. + return _try_repr(repr, x) + + +cheap_repr.suppression_threshold = 300 +cheap_repr.raise_exceptions = False +cheap_repr.max_level = 3 + + +def _try_repr(func, x, *args): + try: + return func(x, *args) + except BaseException as e: + should_raise = (cheap_repr.raise_exceptions or + getattr(func, 'raise_exceptions', False) or + func is repr and __raise_exceptions_from_default_repr) + if should_raise: + raise + cls = x.__class__ + if cls not in suppressed_classes: + suppressed_classes.add(cls) + warnings.warn(ReprSuppressedWarning( + "Exception '%s' in %s for object of type %s. " + "The repr has been suppressed for this type." % + (exception_string(e), func.__name__, safe_qualname(cls)))) + return _basic_but('exception in repr', x) + + +def _basic_but(message, x): + return '%s (%s)>' % (basic_repr(x)[:-1], message) + + +class ReprHelper(object): + __slots__ = ('level', 'func', 'target_length') + + def __init__(self, level, func, target_length): + self.level = level + self.func = func + self.target_length = target_length + + def repr_iterable(self, iterable, left, right, end=False, length=None): + """ + Produces a comma-separated representation of `iterable`, automatically handling nesting and iterables + that are too long, surrounded by `left` and `right`. + The number of items is at most `maxparts` (see the configuration section in the README). + + Set `end=True` to include items from both the beginning and end, possibly leaving out items + in the middle. Only do this if `iterable` supports efficient slicing at the end, e.g. `iterable[-3:]`. + + Provide the `length` parameter if `len(iterable)` doesn't work. Usually this is not needed. + """ + + if length is None: + length = len(iterable) + if self.level <= 0 and length: + s = '...' + else: + newlevel = self.level - 1 + max_parts = original_maxparts = self.func.maxparts + truncate = length > max_parts + target_length = self.target_length + + if target_length is None or not truncate: + if end and truncate: + # Round up from half, e.g. 7 -> 4 + max_parts -= max_parts // 2 + + pieces = [cheap_repr(elem, newlevel) for elem in islice(iterable, max_parts)] + + if truncate: + pieces.append('...') + + if end: + max_parts = original_maxparts - max_parts + + pieces += [cheap_repr(elem, newlevel) for elem in iterable[-max_parts:]] + + else: + pieces = [] + right_pieces = [] + total_length = 3 + len(left) + len(right) + + if end: + sentinel = object() + + def parts_gen(): + for left_part, right_part in zip_longest( + iterable[:length - length // 2], + islice(reversed(iterable), length // 2), + fillvalue=sentinel, + ): + yield left_part, pieces + if right_part is not sentinel: + yield right_part, right_pieces + + parts = parts_gen() + else: + parts = zip(iterable, repeat(pieces)) + + for i, (part, pieces_list) in enumerate(parts): + r = cheap_repr(part, newlevel) + pieces_list.append(r) + total_length += len(r) + 2 + if max_parts <= i + 1 < length and total_length >= target_length: + pieces_list.append('...') + break + + if end: + pieces += right_pieces[::-1] + + s = ', '.join(pieces) + return left + s + right + + def truncate(self, string, middle='...'): + """ + Returns a version of `string` at most `maxparts` characters long, + with the middle replaced by `...` if necessary. + """ + max_parts = self.func.maxparts + if len(string) > max_parts: + i = max(0, (max_parts - 3) // 2) + j = max(0, max_parts - 3 - i) + string = string[:i] + middle + string[len(string) - j:] + return string + + +@register_repr(type(ReprHelper(0, None, None).truncate)) +def repr_bound_method(meth, _helper): + obj = meth.__self__ + return '' % ( + type_name(obj), meth.__name__, cheap_repr(obj)) + + +@register_repr(tuple) +def repr_tuple(x, helper): + if len(x) == 1: + return '(%s,)' % cheap_repr(x[0], helper.level) + else: + return helper.repr_iterable(x, '(', ')', end=True) + + +@register_repr(list) +@try_register_repr('UserList', 'UserList') +@try_register_repr('collections', 'UserList') +def repr_list(x, helper): + return helper.repr_iterable(x, '[', ']', end=True) + + +@register_repr(array) +@maxparts(5) +def repr_array(x, helper): + if not x: + return repr(x) + return helper.repr_iterable(x, "array('%s', [" % x.typecode, '])', end=True) + + +@register_repr(set) +def repr_set(x, helper): + if not x: + return repr(x) + elif PY2: + return helper.repr_iterable(x, 'set([', '])') + else: + return helper.repr_iterable(x, '{', '}') + + +@register_repr(frozenset) +def repr_frozenset(x, helper): + if not x: + return repr(x) + elif PY2: + return helper.repr_iterable(x, 'frozenset([', '])') + else: + return helper.repr_iterable(x, 'frozenset({', '})') + + +@register_repr(Set) +def repr_Set(x, helper): + if not x: + return '%s()' % type_name(x) + else: + return helper.repr_iterable(x, '%s({' % type_name(x), '})') + + +@register_repr(deque) +def repr_deque(x, helper): + return helper.repr_iterable(x, 'deque([', '])') + + +class _DirectRepr(str): + def __repr__(self): + return self + + +register_repr(_DirectRepr)(normal_repr) + + +@register_repr(dict) +@maxparts(4) +def repr_dict(x, helper): + newlevel = helper.level - 1 + + return helper.repr_iterable( + ( + _DirectRepr('%s: %s' % ( + cheap_repr(key, newlevel), + cheap_repr(x[key], newlevel), + )) + for key in x + ), + '{', '}', length=len(x), + ) + + +@try_register_repr('__builtin__', 'unicode') +@register_repr(str) +@maxparts(60) +def repr_str(x, helper): + return repr(helper.truncate(x)) + + +if PY3: + @register_repr(bytes) + @maxparts(60) + def repr_bytes(x, helper): + return repr(helper.truncate(x, middle=b'...')) + + +@register_repr(int) +@try_register_repr('__builtin__', 'long') +@maxparts(40) +def repr_int(x, helper): + return helper.truncate(repr(x)) + + +@try_register_repr('numpy', 'ndarray') +def repr_ndarray(x, _helper): + # noinspection PyPackageRequirements + import numpy as np + + dims = len(x.shape) + if ( + # Too many dimensions to be concise + dims > 6 or + # There's a bug with array_repr and matrices + isinstance(x, np.matrix) and np.lib.NumpyVersion(np.__version__) < '1.14.0' or + # and with masked arrays... + isinstance(x, np.ma.MaskedArray) + + ): + name = type_name(x) + if name == 'ndarray': + name = 'array' + return '%s(%r, shape=%r)' % (name, x.dtype, x.shape) + + edgeitems = repr_ndarray.maxparts // 2 + if dims == 3: + edgeitems = min(edgeitems, 2) + elif dims > 3: + edgeitems = 1 + + opts = np.get_printoptions() + try: + np.set_printoptions(threshold=repr_ndarray.maxparts, edgeitems=edgeitems) + return np.array_repr(x) + finally: + np.set_printoptions(**opts) + + +@try_register_repr('pandas', 'DataFrame') +def repr_DataFrame(df, _): + """ + This function can be configured by setting `max_rows` or `max_cols` attributes. + """ + from pandas import get_option + + return df.to_string( + max_rows=repr_DataFrame.max_rows, + max_cols=repr_DataFrame.max_cols, + show_dimensions=get_option("display.show_dimensions"), + ) + + +repr_DataFrame.max_rows = 8 +repr_DataFrame.max_cols = 8 + + +@try_register_repr('pandas', 'Series') +def repr_pandas_Series(series, _): + """ + This function can be configured by setting the `max_rows` attributes. + """ + from pandas import get_option + + return series.to_string( + max_rows=repr_pandas_Series.max_rows, + name=series.name, + dtype=series.dtype, + length=get_option("display.show_dimensions"), + ) + + +repr_pandas_Series.max_rows = 8 + + +def _repr_pandas_index_generic(index, helper, attrs, long_space=False): + klass = index.__class__.__name__ + if long_space: + space = '\n%s' % (' ' * (len(klass) + 1)) + else: + space = ' ' + + prepr = (",%s" % space).join( + "%s=%s" % (k, cheap_repr(v, helper.level - 1)) + for k, v in attrs) + return "%s(%s)" % (klass, prepr) + + +@try_register_repr('pandas', 'Index') +def repr_pandas_Index(index, helper): + attrs = [['dtype', index.dtype]] + if index.name is not None: + attrs.append(['name', index.name]) + attrs.append(['length', len(index)]) + return _repr_pandas_index_generic(index, helper, attrs) + + +@try_register_repr('pandas', 'IntervalIndex') +def repr_pandas_IntervalIndex(index, helper): + attrs = [['closed', index.closed]] + if index.name is not None: + attrs.append(['name', index.name]) + attrs.append(['dtype', index.dtype]) + return _repr_pandas_index_generic(index, helper, attrs, long_space=True) + + +@try_register_repr('pandas', 'RangeIndex') +def repr_pandas_RangeIndex(index, helper): + attrs = index._format_attrs() + return _repr_pandas_index_generic(index, helper, attrs) + + +@try_register_repr('pandas', 'MultiIndex') +def repr_pandas_MultiIndex(index, helper): + attrs = [('levels', index._levels)] + + try: + attrs.append(('labels', index._labels)) + except AttributeError: + attrs.append(('codes', index.codes)) + + attrs.append(('names', index.names)) + + if index.sortorder is not None: + attrs.append(('sortorder', index.sortorder)) + return _repr_pandas_index_generic(index, helper, attrs, long_space=True) + + +@try_register_repr('pandas', 'CategoricalIndex') +def repr_pandas_CategoricalIndex(index, helper): + attrs = [('categories', index.categories), + ('ordered', index.ordered)] + if index.name is not None: + attrs.append(['name', index.name]) + attrs.append(['dtype', index.dtype.name]) + attrs.append(['length', len(index)]) + return _repr_pandas_index_generic(index, helper, attrs) + + +@try_register_repr('django.db.models', 'QuerySet') +def repr_QuerySet(x, _): + try: + model_name = x.model._meta.object_name + except AttributeError: + model_name = type_name(x.model) + return '<%s instance of %s at %#x>' % (type_name(x), model_name, id(x)) + + +@try_register_repr('collections', 'ChainMap') +@try_register_repr('chainmap', 'ChainMap') +@maxparts(4) +def repr_ChainMap(x, helper): + return helper.repr_iterable(x.maps, type_name(x) + '(', ')', end=True) + + +@try_register_repr('collections', 'OrderedDict') +@try_register_repr('ordereddict', 'OrderedDict') +@try_register_repr('backport_collections', 'OrderedDict') +@maxparts(4) +def repr_OrderedDict(x, helper): + if not x: + return repr(x) + helper.level += 1 + return helper.repr_iterable(viewitems(x), type_name(x) + '([', '])', length=len(x)) + + +@try_register_repr('collections', 'UserDict') +@try_register_repr('UserDict', 'UserDict') +@register_repr(Mapping) +@maxparts(5) +def repr_Mapping(x, helper): + if not x: + return type_name(x) + '()' + return '{0}({1})'.format(type_name(x), repr_dict(x, helper)) + + +@try_register_repr('collections', 'Counter') +@try_register_repr('counter', 'Counter') +@try_register_repr('backport_collections', 'Counter') +@maxparts(5) +def repr_Counter(x, helper): + length = len(x) + if length <= repr_Counter.maxparts: + return repr_Mapping(x, helper) + else: + # The default repr of Counter gives the items in decreasing order + # of frequency. We don't do that because it would be expensive + # to compute. We also don't show a sample of random keys + # because someone familiar with the default repr might be misled + # into thinking that they are the most common. + return '{0}({1} keys)'.format(type_name(x), length) + + +@register_repr(defaultdict) +@maxparts(4) +def repr_defaultdict(x, helper): + return '{0}({1}, {2})'.format(type_name(x), + x.default_factory, + repr_dict(x, helper)) + + +def repr_Printer(x, _helper): + contents = repr(x) + return '{0}({1})'.format(type_name(x), + cheap_repr(contents)) + + +try: + register_repr(type(copyright)) +except NameError: + pass + + +if PY3: + @register_repr(type({}.keys())) + def repr_dict_keys(x, helper): + return helper.repr_iterable(x, 'dict_keys([', '])') + + + @register_repr(type({}.values())) + def repr_dict_values(x, helper): + return helper.repr_iterable(x, 'dict_values([', '])') + + + @register_repr(type({}.items())) + @maxparts(4) + def repr_dict_items(x, helper): + helper.level += 1 + return helper.repr_iterable(x, 'dict_items([', '])') diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr/utils.py b/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr/utils.py new file mode 100644 index 000000000..99056961a --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr/utils.py @@ -0,0 +1,44 @@ +import traceback + +from sys import version_info + +try: + from qualname import qualname +except ImportError: + def qualname(cls): + return cls.__qualname__ + +PY2 = version_info[0] == 2 +PY3 = not PY2 + +if PY2: + def viewitems(d): + return d.viewitems() +else: + def viewitems(d): + return d.items() + + +def safe_qualname(cls): + # type: (type) -> str + result = _safe_qualname_cache.get(cls) + if not result: + try: + result = qualname(cls) + except (AttributeError, IOError, SyntaxError): + result = cls.__name__ + if '' not in result: + _safe_qualname_cache[cls] = result + return result + + +_safe_qualname_cache = {} + + +def type_name(x): + return safe_qualname(x.__class__) + + +def exception_string(exc): + assert isinstance(exc, BaseException) + return ''.join(traceback.format_exception_only(type(exc), exc)).strip() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr/version.py b/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr/version.py new file mode 100644 index 000000000..08d79c0e9 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/cheap_repr/version.py @@ -0,0 +1 @@ +__version__ = '0.5.1' \ No newline at end of file diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/INSTALLER b/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/INSTALLER new file mode 100644 index 000000000..a1b589e38 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/LICENSE.txt b/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/LICENSE.txt new file mode 100644 index 000000000..f433b1a53 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/LICENSE.txt @@ -0,0 +1,177 @@ + + 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 diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/METADATA b/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/METADATA new file mode 100644 index 000000000..e08da4483 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/METADATA @@ -0,0 +1,188 @@ +Metadata-Version: 2.1 +Name: coverage +Version: 5.5 +Summary: Code coverage measurement for Python +Home-page: https://github.com/nedbat/coveragepy +Author: Ned Batchelder and 142 others +Author-email: ned@nedbatchelder.com +License: Apache 2.0 +Project-URL: Documentation, https://coverage.readthedocs.io +Project-URL: Funding, https://tidelift.com/subscription/pkg/pypi-coverage?utm_source=pypi-coverage&utm_medium=referral&utm_campaign=pypi +Project-URL: Issues, https://github.com/nedbat/coveragepy/issues +Keywords: code coverage testing +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: Apache Software License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Software Development :: Quality Assurance +Classifier: Topic :: Software Development :: Testing +Classifier: Development Status :: 5 - Production/Stable +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4 +Description-Content-Type: text/x-rst +License-File: LICENSE.txt +Provides-Extra: toml +Requires-Dist: toml ; extra == 'toml' + +.. Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +.. For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +=========== +Coverage.py +=========== + +Code coverage testing for Python. + +| |license| |versions| |status| +| |test-status| |quality-status| |docs| |codecov| +| |kit| |format| |repos| |downloads| +| |stars| |forks| |contributors| +| |tidelift| |twitter-coveragepy| |twitter-nedbat| + +Coverage.py measures code coverage, typically during test execution. It uses +the code analysis tools and tracing hooks provided in the Python standard +library to determine which lines are executable, and which have been executed. + +Coverage.py runs on many versions of Python: + +* CPython 2.7. +* CPython 3.5 through 3.10 alpha. +* PyPy2 7.3.3 and PyPy3 7.3.3. + +Documentation is on `Read the Docs`_. Code repository and issue tracker are on +`GitHub`_. + +.. _Read the Docs: https://coverage.readthedocs.io/ +.. _GitHub: https://github.com/nedbat/coveragepy + + +**New in 5.x:** SQLite data storage, JSON report, contexts, relative filenames, +dropped support for Python 2.6, 3.3 and 3.4. + + +For Enterprise +-------------- + +.. |tideliftlogo| image:: https://nedbatchelder.com/pix/Tidelift_Logo_small.png + :alt: Tidelift + :target: https://tidelift.com/subscription/pkg/pypi-coverage?utm_source=pypi-coverage&utm_medium=referral&utm_campaign=readme + +.. list-table:: + :widths: 10 100 + + * - |tideliftlogo| + - `Available as part of the Tidelift Subscription. `_ + Coverage and thousands of other packages are working with + Tidelift to deliver one enterprise subscription that covers all of the open + source you use. If you want the flexibility of open source and the confidence + of commercial-grade software, this is for you. + `Learn more. `_ + + +Getting Started +--------------- + +See the `Quick Start section`_ of the docs. + +.. _Quick Start section: https://coverage.readthedocs.io/#quick-start + + +Change history +-------------- + +The complete history of changes is on the `change history page`_. + +.. _change history page: https://coverage.readthedocs.io/en/latest/changes.html + + +Contributing +------------ + +See the `Contributing section`_ of the docs. + +.. _Contributing section: https://coverage.readthedocs.io/en/latest/contributing.html + + +Security +-------- + +To report a security vulnerability, please use the `Tidelift security +contact`_. Tidelift will coordinate the fix and disclosure. + +.. _Tidelift security contact: https://tidelift.com/security + + +License +------- + +Licensed under the `Apache 2.0 License`_. For details, see `NOTICE.txt`_. + +.. _Apache 2.0 License: http://www.apache.org/licenses/LICENSE-2.0 +.. _NOTICE.txt: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + + +.. |test-status| image:: https://github.com/nedbat/coveragepy/actions/workflows/testsuite.yml/badge.svg?branch=master&event=push + :target: https://github.com/nedbat/coveragepy/actions/workflows/testsuite.yml + :alt: Test suite status +.. |quality-status| image:: https://github.com/nedbat/coveragepy/actions/workflows/quality.yml/badge.svg?branch=master&event=push + :target: https://github.com/nedbat/coveragepy/actions/workflows/quality.yml + :alt: Quality check status +.. |docs| image:: https://readthedocs.org/projects/coverage/badge/?version=latest&style=flat + :target: https://coverage.readthedocs.io/ + :alt: Documentation +.. |reqs| image:: https://requires.io/github/nedbat/coveragepy/requirements.svg?branch=master + :target: https://requires.io/github/nedbat/coveragepy/requirements/?branch=master + :alt: Requirements status +.. |kit| image:: https://badge.fury.io/py/coverage.svg + :target: https://pypi.org/project/coverage/ + :alt: PyPI status +.. |format| image:: https://img.shields.io/pypi/format/coverage.svg + :target: https://pypi.org/project/coverage/ + :alt: Kit format +.. |downloads| image:: https://img.shields.io/pypi/dw/coverage.svg + :target: https://pypi.org/project/coverage/ + :alt: Weekly PyPI downloads +.. |versions| image:: https://img.shields.io/pypi/pyversions/coverage.svg?logo=python&logoColor=FBE072 + :target: https://pypi.org/project/coverage/ + :alt: Python versions supported +.. |status| image:: https://img.shields.io/pypi/status/coverage.svg + :target: https://pypi.org/project/coverage/ + :alt: Package stability +.. |license| image:: https://img.shields.io/pypi/l/coverage.svg + :target: https://pypi.org/project/coverage/ + :alt: License +.. |codecov| image:: https://codecov.io/github/nedbat/coveragepy/coverage.svg?branch=master&precision=2 + :target: https://codecov.io/github/nedbat/coveragepy?branch=master + :alt: Coverage! +.. |repos| image:: https://repology.org/badge/tiny-repos/python:coverage.svg + :target: https://repology.org/metapackage/python:coverage/versions + :alt: Packaging status +.. |tidelift| image:: https://tidelift.com/badges/package/pypi/coverage + :target: https://tidelift.com/subscription/pkg/pypi-coverage?utm_source=pypi-coverage&utm_medium=referral&utm_campaign=readme + :alt: Tidelift +.. |stars| image:: https://img.shields.io/github/stars/nedbat/coveragepy.svg?logo=github + :target: https://github.com/nedbat/coveragepy/stargazers + :alt: Github stars +.. |forks| image:: https://img.shields.io/github/forks/nedbat/coveragepy.svg?logo=github + :target: https://github.com/nedbat/coveragepy/network/members + :alt: Github forks +.. |contributors| image:: https://img.shields.io/github/contributors/nedbat/coveragepy.svg?logo=github + :target: https://github.com/nedbat/coveragepy/graphs/contributors + :alt: Contributors +.. |twitter-coveragepy| image:: https://img.shields.io/twitter/follow/coveragepy.svg?label=coveragepy&style=flat&logo=twitter&logoColor=4FADFF + :target: https://twitter.com/coveragepy + :alt: coverage.py on Twitter +.. |twitter-nedbat| image:: https://img.shields.io/twitter/follow/nedbat.svg?label=nedbat&style=flat&logo=twitter&logoColor=4FADFF + :target: https://twitter.com/nedbat + :alt: nedbat on Twitter diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/RECORD b/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/RECORD new file mode 100644 index 000000000..4ed1ccda6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/RECORD @@ -0,0 +1,98 @@ +../../../bin/coverage,sha256=YsBP0cf5VowBnZ-LtwpGj8IJvk2jLjGtViN7dpI5qvU,272 +../../../bin/coverage-3.11,sha256=YsBP0cf5VowBnZ-LtwpGj8IJvk2jLjGtViN7dpI5qvU,272 +../../../bin/coverage3,sha256=YsBP0cf5VowBnZ-LtwpGj8IJvk2jLjGtViN7dpI5qvU,272 +coverage-5.5.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +coverage-5.5.dist-info/LICENSE.txt,sha256=DVQuDIgE45qn836wDaWnYhSdxoLXgpRRKH4RuTjpRZQ,10174 +coverage-5.5.dist-info/METADATA,sha256=IMVpzvCSxiDBlF5vvsMDZL_ReAFrkhuBgoncZmCbMTk,7986 +coverage-5.5.dist-info/RECORD,, +coverage-5.5.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +coverage-5.5.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92 +coverage-5.5.dist-info/entry_points.txt,sha256=1YZ9VNHzvplT76fAhqRNQLG8wmPI5AtUKig-3sjqQJo,123 +coverage-5.5.dist-info/top_level.txt,sha256=BjhyiIvusb5OJkqCXjRncTF3soKF-mDOby-hxkWwwv0,9 +coverage/__init__.py,sha256=8KDKMbvJG6vWupvHNzzHUIV906S6IPu6-vRdWnZg3fI,1283 +coverage/__main__.py,sha256=IOd5fAsdpJd1t8ZyrkGcFk-eqMd3Sdc2qbhNb8YQBW0,257 +coverage/__pycache__/__init__.cpython-311.pyc,, +coverage/__pycache__/__main__.cpython-311.pyc,, +coverage/__pycache__/annotate.cpython-311.pyc,, +coverage/__pycache__/backward.cpython-311.pyc,, +coverage/__pycache__/bytecode.cpython-311.pyc,, +coverage/__pycache__/cmdline.cpython-311.pyc,, +coverage/__pycache__/collector.cpython-311.pyc,, +coverage/__pycache__/config.cpython-311.pyc,, +coverage/__pycache__/context.cpython-311.pyc,, +coverage/__pycache__/control.cpython-311.pyc,, +coverage/__pycache__/data.cpython-311.pyc,, +coverage/__pycache__/debug.cpython-311.pyc,, +coverage/__pycache__/disposition.cpython-311.pyc,, +coverage/__pycache__/env.cpython-311.pyc,, +coverage/__pycache__/execfile.cpython-311.pyc,, +coverage/__pycache__/files.cpython-311.pyc,, +coverage/__pycache__/html.cpython-311.pyc,, +coverage/__pycache__/inorout.cpython-311.pyc,, +coverage/__pycache__/jsonreport.cpython-311.pyc,, +coverage/__pycache__/misc.cpython-311.pyc,, +coverage/__pycache__/multiproc.cpython-311.pyc,, +coverage/__pycache__/numbits.cpython-311.pyc,, +coverage/__pycache__/parser.cpython-311.pyc,, +coverage/__pycache__/phystokens.cpython-311.pyc,, +coverage/__pycache__/plugin.cpython-311.pyc,, +coverage/__pycache__/plugin_support.cpython-311.pyc,, +coverage/__pycache__/python.cpython-311.pyc,, +coverage/__pycache__/pytracer.cpython-311.pyc,, +coverage/__pycache__/report.cpython-311.pyc,, +coverage/__pycache__/results.cpython-311.pyc,, +coverage/__pycache__/sqldata.cpython-311.pyc,, +coverage/__pycache__/summary.cpython-311.pyc,, +coverage/__pycache__/templite.cpython-311.pyc,, +coverage/__pycache__/tomlconfig.cpython-311.pyc,, +coverage/__pycache__/version.cpython-311.pyc,, +coverage/__pycache__/xmlreport.cpython-311.pyc,, +coverage/annotate.py,sha256=FCS90-FKxNZ1wUBNmGZvFp0f0fsxL3r9jjgA5CDG8VY,3557 +coverage/backward.py,sha256=yehFvzNoQ5-7FZqgPVYS-Dn9UIYm3sHuiTjjO5FPnrs,7545 +coverage/bytecode.py,sha256=RgL-pG1AicUD8ksZ6P_swwfzlTJldCrBvr4oZ-G2Qyc,609 +coverage/cmdline.py,sha256=ebxHbxEyucIcGCgaV1lm_OsgX9h6RUDrCLfyGjSAmME,30741 +coverage/collector.py,sha256=ypqm0HfmDjjWqdO9SzRjgdgR7oMUmrjQmLV-KTIX27s,17852 +coverage/config.py,sha256=_fDI5Ch-n6p9LOPIMkOZIP7lethVJEiPD26SZzRNsOg,19766 +coverage/context.py,sha256=aG4mZVyQROCGqlLhCeKYtNErn6Ai2mG3_byN6ZjjBTo,3091 +coverage/control.py,sha256=gKoj_dM94zQL16QPcCQZVAUUfySyfi9gc3hMmTMdqfM,42379 +coverage/data.py,sha256=o3IDu0lvd1MZowxOQqyHopQQZWrZAHZfx5m31SKI3ok,4550 +coverage/debug.py,sha256=5J6qm0OA2RYCofBk-V-88X1RaPr3gniiFdwgew1Vu28,13872 +coverage/disposition.py,sha256=HF2eJULSz9NEMOgN22daJJvgBzJtvEKtsj2gw8ZK26E,1255 +coverage/env.py,sha256=xa7bUFbCU9oT6MNAdZO3bC_gAIA5T6sKwKOxqr79AII,4693 +coverage/execfile.py,sha256=sewNsJ4z9GNJVxscKCTz0e_BQsh6npoj1sHNZWlIf04,13444 +coverage/files.py,sha256=1ZKYpCNdnjdnj1x_yEjJXQE36dnLMDSrUhDgnyduBvw,14326 +coverage/fullcoverage/__pycache__/encodings.cpython-311.pyc,, +coverage/fullcoverage/encodings.py,sha256=DW3X3yoqrI-Waq3l3lgGdIxLFia4gsrjLR03cr_EWX8,2548 +coverage/html.py,sha256=bCf5LNwzlw0lejtZLN5j2HpfEQAQ8Lm2qAPB0S9tRaI,17873 +coverage/htmlfiles/coverage_html.js,sha256=0RGp8VupFTT1fgNo4vL5ReNnq7JJLpUw2PZkm5vTXto,19445 +coverage/htmlfiles/favicon_32.png,sha256=vIEA-odDwRvSQ-syWfSwEnWGUWEv2b-Tv4tzTRfwJWE,1732 +coverage/htmlfiles/index.html,sha256=h-P_bm8PsAdVIbWd4JxZvapsVShntxV7b6VLwqrQfbM,4254 +coverage/htmlfiles/jquery.ba-throttle-debounce.min.js,sha256=wXepUsOX1VYr5AyWGbIoAqlrvjQz9unPbtEyM7wFBnw,731 +coverage/htmlfiles/jquery.hotkeys.js,sha256=VVqbRGJlCvARPGMJXcSiRRIJwkpged3wG5fQ47gi42U,3065 +coverage/htmlfiles/jquery.isonscreen.js,sha256=WEyXE6yTYNzAYfzViwksNu7AJAY5zZBI9q6-J9pF1Zw,1502 +coverage/htmlfiles/jquery.min.js,sha256=JCYrqv7xcJKSfD2v52SqpSoqNxuD7SJJzKfkFN-Z-sE,95785 +coverage/htmlfiles/jquery.tablesorter.min.js,sha256=t4ifnz2eByQEUafncoSdJUwD2jUt68VY8CzNjAywo08,12795 +coverage/htmlfiles/keybd_closed.png,sha256=FNDmw-Lx9aptnMr-XiZ4gh2EGPs17nft-QKmXgilIe0,112 +coverage/htmlfiles/keybd_open.png,sha256=FNDmw-Lx9aptnMr-XiZ4gh2EGPs17nft-QKmXgilIe0,112 +coverage/htmlfiles/pyfile.html,sha256=kEAzajng44FAbiltAh13XoKAihtJXvlpIBtn71btdQw,4621 +coverage/htmlfiles/style.css,sha256=jkvVPWTFwAB4Nkqr3jR8P0jpg81i_Hr2364wDYlGqxM,11692 +coverage/htmlfiles/style.scss,sha256=SE96hwXj-62zfyAodXbhJrWAPuiMk1nJ8diesKEY2Jg,16281 +coverage/inorout.py,sha256=I2VG99xtlde8jVvVeerNiPIX-GCraUsJJ6cpWq_I36o,19752 +coverage/jsonreport.py,sha256=PZVkril1YUHeQSc7ASNjWxfEKdnMWZeo22Vy6TNrgw0,3686 +coverage/misc.py,sha256=0sFG3MjjvZ213fJhMNx9MQ_QUj8CLKXZtyl1T5p--CA,11004 +coverage/multiproc.py,sha256=eOYolk_Bp1pGpF7Cgc5NcX3QEsuM23ZkKq1fTw1WkFk,3841 +coverage/numbits.py,sha256=kPD3WHU9orL6cl5FB56eF5Dz5QQgYUR0tMadI4RDHd8,5529 +coverage/parser.py,sha256=zPVmVqsJ2qM0vyuLP7QM2ITpz9jW_jK4TZa9TZQRncM,49599 +coverage/phystokens.py,sha256=oqJ3UoLIjBhvC_-moJvXRvIqZfukAgurEjoTOs6Ftcw,10045 +coverage/plugin.py,sha256=-RMXO-rY06qwW9FWZBO92q1b1ABGNmyNqeKbIALvnOE,18549 +coverage/plugin_support.py,sha256=-MQ_4TSZug4u6ReNqNdb1CnAlBHkJH5h5HO03o4HgdI,9101 +coverage/python.py,sha256=LsqDDXMc1qeVxeez058NGTnlSG3xQiSoSa6De04OgrM,7633 +coverage/pytracer.py,sha256=mUq-_vZoQa3epjtw0RYMI_rX7oBygw4GrLnCpKOfsG8,10991 +coverage/report.py,sha256=AvFOS1l_kr0qMBpaQTOzV-tgkrt4N2CvMJAtBc0ZpSQ,3222 +coverage/results.py,sha256=RrUx7AfIdb0nt7pnd6bI3ecYsoQdSHHoqwjIfeH97Ow,12225 +coverage/sqldata.py,sha256=aK_ku63OM9ZgJD_lUWlT4Xtwbu-9AoZmo5MVrmnW6wI,43865 +coverage/summary.py,sha256=So2Yn2s-k0QlsG1keX-H67Vp5-GS4u4T4F19w-WW1R4,5883 +coverage/templite.py,sha256=ZrsnMuc0rlMVYb54KGA8Whp1CMh5XsGeu3_7aW-OkBE,10504 +coverage/tomlconfig.py,sha256=gW0kJfOLY-aOZjcmXlJ7E74L3urRYyr4IKHXtuqwJDY,5560 +coverage/version.py,sha256=vyDttATHaXSb-mcEkuwQ_0LJAARQAiajZTG0RIFgxIo,1260 +coverage/xmlreport.py,sha256=ogkVOk8rLmFmPh5EaKWxSgQQabxjvUhcTLmTjrV-y1A,8700 diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/REQUESTED b/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/REQUESTED new file mode 100644 index 000000000..e69de29bb diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/WHEEL b/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/WHEEL new file mode 100644 index 000000000..98c0d20b7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.42.0) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/entry_points.txt b/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/entry_points.txt new file mode 100644 index 000000000..55e5f6b7c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/entry_points.txt @@ -0,0 +1,4 @@ +[console_scripts] +coverage = coverage.cmdline:main +coverage-3.11 = coverage.cmdline:main +coverage3 = coverage.cmdline:main diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/top_level.txt b/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/top_level.txt new file mode 100644 index 000000000..4ebc8aea5 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage-5.5.dist-info/top_level.txt @@ -0,0 +1 @@ +coverage diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/__init__.py b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/__init__.py new file mode 100644 index 000000000..331b304b6 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/__init__.py @@ -0,0 +1,36 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +"""Code coverage measurement for Python. + +Ned Batchelder +https://nedbatchelder.com/code/coverage + +""" + +import sys + +from coverage.version import __version__, __url__, version_info + +from coverage.control import Coverage, process_startup +from coverage.data import CoverageData +from coverage.misc import CoverageException +from coverage.plugin import CoveragePlugin, FileTracer, FileReporter +from coverage.pytracer import PyTracer + +# Backward compatibility. +coverage = Coverage + +# On Windows, we encode and decode deep enough that something goes wrong and +# the encodings.utf_8 module is loaded and then unloaded, I don't know why. +# Adding a reference here prevents it from being unloaded. Yuk. +import encodings.utf_8 # pylint: disable=wrong-import-position, wrong-import-order + +# Because of the "from coverage.control import fooey" lines at the top of the +# file, there's an entry for coverage.coverage in sys.modules, mapped to None. +# This makes some inspection tools (like pydoc) unable to find the class +# coverage.coverage. So remove that entry. +try: + del sys.modules['coverage.coverage'] +except KeyError: + pass diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/__main__.py b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/__main__.py new file mode 100644 index 000000000..79aa4e2b3 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/__main__.py @@ -0,0 +1,8 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +"""Coverage.py's main entry point.""" + +import sys +from coverage.cmdline import main +sys.exit(main()) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/annotate.py b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/annotate.py new file mode 100644 index 000000000..999ab6e55 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/annotate.py @@ -0,0 +1,108 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +"""Source file annotation for coverage.py.""" + +import io +import os +import re + +from coverage.files import flat_rootname +from coverage.misc import ensure_dir, isolate_module +from coverage.report import get_analysis_to_report + +os = isolate_module(os) + + +class AnnotateReporter(object): + """Generate annotated source files showing line coverage. + + This reporter creates annotated copies of the measured source files. Each + .py file is copied as a .py,cover file, with a left-hand margin annotating + each line:: + + > def h(x): + - if 0: #pragma: no cover + - pass + > if x == 1: + ! a = 1 + > else: + > a = 2 + + > h(2) + + Executed lines use '>', lines not executed use '!', lines excluded from + consideration use '-'. + + """ + + def __init__(self, coverage): + self.coverage = coverage + self.config = self.coverage.config + self.directory = None + + blank_re = re.compile(r"\s*(#|$)") + else_re = re.compile(r"\s*else\s*:\s*(#|$)") + + def report(self, morfs, directory=None): + """Run the report. + + See `coverage.report()` for arguments. + + """ + self.directory = directory + self.coverage.get_data() + for fr, analysis in get_analysis_to_report(self.coverage, morfs): + self.annotate_file(fr, analysis) + + def annotate_file(self, fr, analysis): + """Annotate a single file. + + `fr` is the FileReporter for the file to annotate. + + """ + statements = sorted(analysis.statements) + missing = sorted(analysis.missing) + excluded = sorted(analysis.excluded) + + if self.directory: + ensure_dir(self.directory) + dest_file = os.path.join(self.directory, flat_rootname(fr.relative_filename())) + if dest_file.endswith("_py"): + dest_file = dest_file[:-3] + ".py" + dest_file += ",cover" + else: + dest_file = fr.filename + ",cover" + + with io.open(dest_file, 'w', encoding='utf8') as dest: + i = 0 + j = 0 + covered = True + source = fr.source() + for lineno, line in enumerate(source.splitlines(True), start=1): + while i < len(statements) and statements[i] < lineno: + i += 1 + while j < len(missing) and missing[j] < lineno: + j += 1 + if i < len(statements) and statements[i] == lineno: + covered = j >= len(missing) or missing[j] > lineno + if self.blank_re.match(line): + dest.write(u' ') + elif self.else_re.match(line): + # Special logic for lines containing only 'else:'. + if i >= len(statements) and j >= len(missing): + dest.write(u'! ') + elif i >= len(statements) or j >= len(missing): + dest.write(u'> ') + elif statements[i] == missing[j]: + dest.write(u'! ') + else: + dest.write(u'> ') + elif lineno in excluded: + dest.write(u'- ') + elif covered: + dest.write(u'> ') + else: + dest.write(u'! ') + + dest.write(line) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/backward.py b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/backward.py new file mode 100644 index 000000000..ac781ab96 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/backward.py @@ -0,0 +1,267 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +"""Add things to old Pythons so I can pretend they are newer.""" + +# This file's purpose is to provide modules to be imported from here. +# pylint: disable=unused-import + +import os +import sys + +from datetime import datetime + +from coverage import env + + +# Pythons 2 and 3 differ on where to get StringIO. +try: + from cStringIO import StringIO +except ImportError: + from io import StringIO + +# In py3, ConfigParser was renamed to the more-standard configparser. +# But there's a py3 backport that installs "configparser" in py2, and I don't +# want it because it has annoying deprecation warnings. So try the real py2 +# import first. +try: + import ConfigParser as configparser +except ImportError: + import configparser + +# What's a string called? +try: + string_class = basestring +except NameError: + string_class = str + +# What's a Unicode string called? +try: + unicode_class = unicode +except NameError: + unicode_class = str + +# range or xrange? +try: + range = xrange # pylint: disable=redefined-builtin +except NameError: + range = range + +try: + from itertools import zip_longest +except ImportError: + from itertools import izip_longest as zip_longest + +# Where do we get the thread id from? +try: + from thread import get_ident as get_thread_id +except ImportError: + from threading import get_ident as get_thread_id + +try: + os.PathLike +except AttributeError: + # This is Python 2 and 3 + path_types = (bytes, string_class, unicode_class) +else: + # 3.6+ + path_types = (bytes, str, os.PathLike) + +# shlex.quote is new, but there's an undocumented implementation in "pipes", +# who knew!? +try: + from shlex import quote as shlex_quote +except ImportError: + # Useful function, available under a different (undocumented) name + # in Python versions earlier than 3.3. + from pipes import quote as shlex_quote + +try: + import reprlib +except ImportError: # pragma: not covered + # We need this on Python 2, but in testing environments, a backport is + # installed, so this import isn't used. + import repr as reprlib + +# A function to iterate listlessly over a dict's items, and one to get the +# items as a list. +try: + {}.iteritems +except AttributeError: + # Python 3 + def iitems(d): + """Produce the items from dict `d`.""" + return d.items() + + def litems(d): + """Return a list of items from dict `d`.""" + return list(d.items()) +else: + # Python 2 + def iitems(d): + """Produce the items from dict `d`.""" + return d.iteritems() + + def litems(d): + """Return a list of items from dict `d`.""" + return d.items() + +# Getting the `next` function from an iterator is different in 2 and 3. +try: + iter([]).next +except AttributeError: + def iternext(seq): + """Get the `next` function for iterating over `seq`.""" + return iter(seq).__next__ +else: + def iternext(seq): + """Get the `next` function for iterating over `seq`.""" + return iter(seq).next + +# Python 3.x is picky about bytes and strings, so provide methods to +# get them right, and make them no-ops in 2.x +if env.PY3: + def to_bytes(s): + """Convert string `s` to bytes.""" + return s.encode('utf8') + + def to_string(b): + """Convert bytes `b` to string.""" + return b.decode('utf8') + + def binary_bytes(byte_values): + """Produce a byte string with the ints from `byte_values`.""" + return bytes(byte_values) + + def byte_to_int(byte): + """Turn a byte indexed from a bytes object into an int.""" + return byte + + def bytes_to_ints(bytes_value): + """Turn a bytes object into a sequence of ints.""" + # In Python 3, iterating bytes gives ints. + return bytes_value + +else: + def to_bytes(s): + """Convert string `s` to bytes (no-op in 2.x).""" + return s + + def to_string(b): + """Convert bytes `b` to string.""" + return b + + def binary_bytes(byte_values): + """Produce a byte string with the ints from `byte_values`.""" + return "".join(chr(b) for b in byte_values) + + def byte_to_int(byte): + """Turn a byte indexed from a bytes object into an int.""" + return ord(byte) + + def bytes_to_ints(bytes_value): + """Turn a bytes object into a sequence of ints.""" + for byte in bytes_value: + yield ord(byte) + + +try: + # In Python 2.x, the builtins were in __builtin__ + BUILTINS = sys.modules['__builtin__'] +except KeyError: + # In Python 3.x, they're in builtins + BUILTINS = sys.modules['builtins'] + + +# imp was deprecated in Python 3.3 +try: + import importlib + import importlib.util + imp = None +except ImportError: + importlib = None + +# We only want to use importlib if it has everything we need. +try: + importlib_util_find_spec = importlib.util.find_spec +except Exception: + import imp + importlib_util_find_spec = None + +# What is the .pyc magic number for this version of Python? +try: + PYC_MAGIC_NUMBER = importlib.util.MAGIC_NUMBER +except AttributeError: + PYC_MAGIC_NUMBER = imp.get_magic() + + +def code_object(fn): + """Get the code object from a function.""" + try: + return fn.func_code + except AttributeError: + return fn.__code__ + + +try: + from types import SimpleNamespace +except ImportError: + # The code from https://docs.python.org/3/library/types.html#types.SimpleNamespace + class SimpleNamespace: + """Python implementation of SimpleNamespace, for Python 2.""" + def __init__(self, **kwargs): + self.__dict__.update(kwargs) + + def __repr__(self): + keys = sorted(self.__dict__) + items = ("{}={!r}".format(k, self.__dict__[k]) for k in keys) + return "{}({})".format(type(self).__name__, ", ".join(items)) + + +def format_local_datetime(dt): + """Return a string with local timezone representing the date. + If python version is lower than 3.6, the time zone is not included. + """ + try: + return dt.astimezone().strftime('%Y-%m-%d %H:%M %z') + except (TypeError, ValueError): + # Datetime.astimezone in Python 3.5 can not handle naive datetime + return dt.strftime('%Y-%m-%d %H:%M') + + +def invalidate_import_caches(): + """Invalidate any import caches that may or may not exist.""" + if importlib and hasattr(importlib, "invalidate_caches"): + importlib.invalidate_caches() + + +def import_local_file(modname, modfile=None): + """Import a local file as a module. + + Opens a file in the current directory named `modname`.py, imports it + as `modname`, and returns the module object. `modfile` is the file to + import if it isn't in the current directory. + + """ + try: + import importlib.util as importlib_util + except ImportError: + importlib_util = None + + if modfile is None: + modfile = modname + '.py' + if importlib_util: + spec = importlib_util.spec_from_file_location(modname, modfile) + mod = importlib_util.module_from_spec(spec) + sys.modules[modname] = mod + spec.loader.exec_module(mod) + else: + for suff in imp.get_suffixes(): # pragma: part covered + if suff[0] == '.py': + break + + with open(modfile, 'r') as f: + # pylint: disable=undefined-loop-variable + mod = imp.load_module(modname, f, modfile, suff) + + return mod diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/bytecode.py b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/bytecode.py new file mode 100644 index 000000000..ceb18cf37 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/bytecode.py @@ -0,0 +1,19 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +"""Bytecode manipulation for coverage.py""" + +import types + + +def code_objects(code): + """Iterate over all the code objects in `code`.""" + stack = [code] + while stack: + # We're going to return the code object on the stack, but first + # push its children for later returning. + code = stack.pop() + for c in code.co_consts: + if isinstance(c, types.CodeType): + stack.append(c) + yield code diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/cmdline.py b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/cmdline.py new file mode 100644 index 000000000..0be0cca19 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/cmdline.py @@ -0,0 +1,910 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +"""Command-line support for coverage.py.""" + +from __future__ import print_function + +import glob +import optparse +import os.path +import shlex +import sys +import textwrap +import traceback + +import coverage +from coverage import Coverage +from coverage import env +from coverage.collector import CTracer +from coverage.data import line_counts +from coverage.debug import info_formatter, info_header, short_stack +from coverage.execfile import PyRunner +from coverage.misc import BaseCoverageException, ExceptionDuringRun, NoSource, output_encoding +from coverage.results import should_fail_under + + +class Opts(object): + """A namespace class for individual options we'll build parsers from.""" + + append = optparse.make_option( + '-a', '--append', action='store_true', + help="Append coverage data to .coverage, otherwise it starts clean each time.", + ) + keep = optparse.make_option( + '', '--keep', action='store_true', + help="Keep original coverage files, otherwise they are deleted.", + ) + branch = optparse.make_option( + '', '--branch', action='store_true', + help="Measure branch coverage in addition to statement coverage.", + ) + CONCURRENCY_CHOICES = [ + "thread", "gevent", "greenlet", "eventlet", "multiprocessing", + ] + concurrency = optparse.make_option( + '', '--concurrency', action='store', metavar="LIB", + choices=CONCURRENCY_CHOICES, + help=( + "Properly measure code using a concurrency library. " + "Valid values are: %s." + ) % ", ".join(CONCURRENCY_CHOICES), + ) + context = optparse.make_option( + '', '--context', action='store', metavar="LABEL", + help="The context label to record for this coverage run.", + ) + debug = optparse.make_option( + '', '--debug', action='store', metavar="OPTS", + help="Debug options, separated by commas. [env: COVERAGE_DEBUG]", + ) + directory = optparse.make_option( + '-d', '--directory', action='store', metavar="DIR", + help="Write the output files to DIR.", + ) + fail_under = optparse.make_option( + '', '--fail-under', action='store', metavar="MIN", type="float", + help="Exit with a status of 2 if the total coverage is less than MIN.", + ) + help = optparse.make_option( + '-h', '--help', action='store_true', + help="Get help on this command.", + ) + ignore_errors = optparse.make_option( + '-i', '--ignore-errors', action='store_true', + help="Ignore errors while reading source files.", + ) + include = optparse.make_option( + '', '--include', action='store', + metavar="PAT1,PAT2,...", + help=( + "Include only files whose paths match one of these patterns. " + "Accepts shell-style wildcards, which must be quoted." + ), + ) + pylib = optparse.make_option( + '-L', '--pylib', action='store_true', + help=( + "Measure coverage even inside the Python installed library, " + "which isn't done by default." + ), + ) + sort = optparse.make_option( + '--sort', action='store', metavar='COLUMN', + help="Sort the report by the named column: name, stmts, miss, branch, brpart, or cover. " + "Default is name." + ) + show_missing = optparse.make_option( + '-m', '--show-missing', action='store_true', + help="Show line numbers of statements in each module that weren't executed.", + ) + skip_covered = optparse.make_option( + '--skip-covered', action='store_true', + help="Skip files with 100% coverage.", + ) + no_skip_covered = optparse.make_option( + '--no-skip-covered', action='store_false', dest='skip_covered', + help="Disable --skip-covered.", + ) + skip_empty = optparse.make_option( + '--skip-empty', action='store_true', + help="Skip files with no code.", + ) + show_contexts = optparse.make_option( + '--show-contexts', action='store_true', + help="Show contexts for covered lines.", + ) + omit = optparse.make_option( + '', '--omit', action='store', + metavar="PAT1,PAT2,...", + help=( + "Omit files whose paths match one of these patterns. " + "Accepts shell-style wildcards, which must be quoted." + ), + ) + contexts = optparse.make_option( + '', '--contexts', action='store', + metavar="REGEX1,REGEX2,...", + help=( + "Only display data from lines covered in the given contexts. " + "Accepts Python regexes, which must be quoted." + ), + ) + output_xml = optparse.make_option( + '-o', '', action='store', dest="outfile", + metavar="OUTFILE", + help="Write the XML report to this file. Defaults to 'coverage.xml'", + ) + output_json = optparse.make_option( + '-o', '', action='store', dest="outfile", + metavar="OUTFILE", + help="Write the JSON report to this file. Defaults to 'coverage.json'", + ) + json_pretty_print = optparse.make_option( + '', '--pretty-print', action='store_true', + help="Format the JSON for human readers.", + ) + parallel_mode = optparse.make_option( + '-p', '--parallel-mode', action='store_true', + help=( + "Append the machine name, process id and random number to the " + ".coverage data file name to simplify collecting data from " + "many processes." + ), + ) + module = optparse.make_option( + '-m', '--module', action='store_true', + help=( + " is an importable Python module, not a script path, " + "to be run as 'python -m' would run it." + ), + ) + precision = optparse.make_option( + '', '--precision', action='store', metavar='N', type=int, + help=( + "Number of digits after the decimal point to display for " + "reported coverage percentages." + ), + ) + rcfile = optparse.make_option( + '', '--rcfile', action='store', + help=( + "Specify configuration file. " + "By default '.coveragerc', 'setup.cfg', 'tox.ini', and " + "'pyproject.toml' are tried. [env: COVERAGE_RCFILE]" + ), + ) + source = optparse.make_option( + '', '--source', action='store', metavar="SRC1,SRC2,...", + help="A list of packages or directories of code to be measured.", + ) + timid = optparse.make_option( + '', '--timid', action='store_true', + help=( + "Use a simpler but slower trace method. Try this if you get " + "seemingly impossible results!" + ), + ) + title = optparse.make_option( + '', '--title', action='store', metavar="TITLE", + help="A text string to use as the title on the HTML.", + ) + version = optparse.make_option( + '', '--version', action='store_true', + help="Display version information and exit.", + ) + + +class CoverageOptionParser(optparse.OptionParser, object): + """Base OptionParser for coverage.py. + + Problems don't exit the program. + Defaults are initialized for all options. + + """ + + def __init__(self, *args, **kwargs): + super(CoverageOptionParser, self).__init__( + add_help_option=False, *args, **kwargs + ) + self.set_defaults( + action=None, + append=None, + branch=None, + concurrency=None, + context=None, + debug=None, + directory=None, + fail_under=None, + help=None, + ignore_errors=None, + include=None, + keep=None, + module=None, + omit=None, + contexts=None, + parallel_mode=None, + precision=None, + pylib=None, + rcfile=True, + show_missing=None, + skip_covered=None, + skip_empty=None, + show_contexts=None, + sort=None, + source=None, + timid=None, + title=None, + version=None, + ) + + self.disable_interspersed_args() + + class OptionParserError(Exception): + """Used to stop the optparse error handler ending the process.""" + pass + + def parse_args_ok(self, args=None, options=None): + """Call optparse.parse_args, but return a triple: + + (ok, options, args) + + """ + try: + options, args = super(CoverageOptionParser, self).parse_args(args, options) + except self.OptionParserError: + return False, None, None + return True, options, args + + def error(self, msg): + """Override optparse.error so sys.exit doesn't get called.""" + show_help(msg) + raise self.OptionParserError + + +class GlobalOptionParser(CoverageOptionParser): + """Command-line parser for coverage.py global option arguments.""" + + def __init__(self): + super(GlobalOptionParser, self).__init__() + + self.add_options([ + Opts.help, + Opts.version, + ]) + + +class CmdOptionParser(CoverageOptionParser): + """Parse one of the new-style commands for coverage.py.""" + + def __init__(self, action, options, defaults=None, usage=None, description=None): + """Create an OptionParser for a coverage.py command. + + `action` is the slug to put into `options.action`. + `options` is a list of Option's for the command. + `defaults` is a dict of default value for options. + `usage` is the usage string to display in help. + `description` is the description of the command, for the help text. + + """ + if usage: + usage = "%prog " + usage + super(CmdOptionParser, self).__init__( + usage=usage, + description=description, + ) + self.set_defaults(action=action, **(defaults or {})) + self.add_options(options) + self.cmd = action + + def __eq__(self, other): + # A convenience equality, so that I can put strings in unit test + # results, and they will compare equal to objects. + return (other == "" % self.cmd) + + __hash__ = None # This object doesn't need to be hashed. + + def get_prog_name(self): + """Override of an undocumented function in optparse.OptionParser.""" + program_name = super(CmdOptionParser, self).get_prog_name() + + # Include the sub-command for this parser as part of the command. + return "{command} {subcommand}".format(command=program_name, subcommand=self.cmd) + + +GLOBAL_ARGS = [ + Opts.debug, + Opts.help, + Opts.rcfile, + ] + +CMDS = { + 'annotate': CmdOptionParser( + "annotate", + [ + Opts.directory, + Opts.ignore_errors, + Opts.include, + Opts.omit, + ] + GLOBAL_ARGS, + usage="[options] [modules]", + description=( + "Make annotated copies of the given files, marking statements that are executed " + "with > and statements that are missed with !." + ), + ), + + 'combine': CmdOptionParser( + "combine", + [ + Opts.append, + Opts.keep, + ] + GLOBAL_ARGS, + usage="[options] ... ", + description=( + "Combine data from multiple coverage files collected " + "with 'run -p'. The combined results are written to a single " + "file representing the union of the data. The positional " + "arguments are data files or directories containing data files. " + "If no paths are provided, data files in the default data file's " + "directory are combined." + ), + ), + + 'debug': CmdOptionParser( + "debug", GLOBAL_ARGS, + usage="", + description=( + "Display information about the internals of coverage.py, " + "for diagnosing problems. " + "Topics are: " + "'data' to show a summary of the collected data; " + "'sys' to show installation information; " + "'config' to show the configuration; " + "'premain' to show what is calling coverage." + ), + ), + + 'erase': CmdOptionParser( + "erase", GLOBAL_ARGS, + description="Erase previously collected coverage data.", + ), + + 'help': CmdOptionParser( + "help", GLOBAL_ARGS, + usage="[command]", + description="Describe how to use coverage.py", + ), + + 'html': CmdOptionParser( + "html", + [ + Opts.contexts, + Opts.directory, + Opts.fail_under, + Opts.ignore_errors, + Opts.include, + Opts.omit, + Opts.precision, + Opts.show_contexts, + Opts.skip_covered, + Opts.no_skip_covered, + Opts.skip_empty, + Opts.title, + ] + GLOBAL_ARGS, + usage="[options] [modules]", + description=( + "Create an HTML report of the coverage of the files. " + "Each file gets its own page, with the source decorated to show " + "executed, excluded, and missed lines." + ), + ), + + 'json': CmdOptionParser( + "json", + [ + Opts.contexts, + Opts.fail_under, + Opts.ignore_errors, + Opts.include, + Opts.omit, + Opts.output_json, + Opts.json_pretty_print, + Opts.show_contexts, + ] + GLOBAL_ARGS, + usage="[options] [modules]", + description="Generate a JSON report of coverage results." + ), + + 'report': CmdOptionParser( + "report", + [ + Opts.contexts, + Opts.fail_under, + Opts.ignore_errors, + Opts.include, + Opts.omit, + Opts.precision, + Opts.sort, + Opts.show_missing, + Opts.skip_covered, + Opts.no_skip_covered, + Opts.skip_empty, + ] + GLOBAL_ARGS, + usage="[options] [modules]", + description="Report coverage statistics on modules." + ), + + 'run': CmdOptionParser( + "run", + [ + Opts.append, + Opts.branch, + Opts.concurrency, + Opts.context, + Opts.include, + Opts.module, + Opts.omit, + Opts.pylib, + Opts.parallel_mode, + Opts.source, + Opts.timid, + ] + GLOBAL_ARGS, + usage="[options] [program options]", + description="Run a Python program, measuring code execution." + ), + + 'xml': CmdOptionParser( + "xml", + [ + Opts.fail_under, + Opts.ignore_errors, + Opts.include, + Opts.omit, + Opts.output_xml, + Opts.skip_empty, + ] + GLOBAL_ARGS, + usage="[options] [modules]", + description="Generate an XML report of coverage results." + ), +} + + +def show_help(error=None, topic=None, parser=None): + """Display an error message, or the named topic.""" + assert error or topic or parser + + program_path = sys.argv[0] + if program_path.endswith(os.path.sep + '__main__.py'): + # The path is the main module of a package; get that path instead. + program_path = os.path.dirname(program_path) + program_name = os.path.basename(program_path) + if env.WINDOWS: + # entry_points={'console_scripts':...} on Windows makes files + # called coverage.exe, coverage3.exe, and coverage-3.5.exe. These + # invoke coverage-script.py, coverage3-script.py, and + # coverage-3.5-script.py. argv[0] is the .py file, but we want to + # get back to the original form. + auto_suffix = "-script.py" + if program_name.endswith(auto_suffix): + program_name = program_name[:-len(auto_suffix)] + + help_params = dict(coverage.__dict__) + help_params['program_name'] = program_name + if CTracer is not None: + help_params['extension_modifier'] = 'with C extension' + else: + help_params['extension_modifier'] = 'without C extension' + + if error: + print(error, file=sys.stderr) + print("Use '%s help' for help." % (program_name,), file=sys.stderr) + elif parser: + print(parser.format_help().strip()) + print() + else: + help_msg = textwrap.dedent(HELP_TOPICS.get(topic, '')).strip() + if help_msg: + print(help_msg.format(**help_params)) + else: + print("Don't know topic %r" % topic) + print("Full documentation is at {__url__}".format(**help_params)) + + +OK, ERR, FAIL_UNDER = 0, 1, 2 + + +class CoverageScript(object): + """The command-line interface to coverage.py.""" + + def __init__(self): + self.global_option = False + self.coverage = None + + def command_line(self, argv): + """The bulk of the command line interface to coverage.py. + + `argv` is the argument list to process. + + Returns 0 if all is well, 1 if something went wrong. + + """ + # Collect the command-line options. + if not argv: + show_help(topic='minimum_help') + return OK + + # The command syntax we parse depends on the first argument. Global + # switch syntax always starts with an option. + self.global_option = argv[0].startswith('-') + if self.global_option: + parser = GlobalOptionParser() + else: + parser = CMDS.get(argv[0]) + if not parser: + show_help("Unknown command: '%s'" % argv[0]) + return ERR + argv = argv[1:] + + ok, options, args = parser.parse_args_ok(argv) + if not ok: + return ERR + + # Handle help and version. + if self.do_help(options, args, parser): + return OK + + # Listify the list options. + source = unshell_list(options.source) + omit = unshell_list(options.omit) + include = unshell_list(options.include) + debug = unshell_list(options.debug) + contexts = unshell_list(options.contexts) + + # Do something. + self.coverage = Coverage( + data_suffix=options.parallel_mode, + cover_pylib=options.pylib, + timid=options.timid, + branch=options.branch, + config_file=options.rcfile, + source=source, + omit=omit, + include=include, + debug=debug, + concurrency=options.concurrency, + check_preimported=True, + context=options.context, + ) + + if options.action == "debug": + return self.do_debug(args) + + elif options.action == "erase": + self.coverage.erase() + return OK + + elif options.action == "run": + return self.do_run(options, args) + + elif options.action == "combine": + if options.append: + self.coverage.load() + data_dirs = args or None + self.coverage.combine(data_dirs, strict=True, keep=bool(options.keep)) + self.coverage.save() + return OK + + # Remaining actions are reporting, with some common options. + report_args = dict( + morfs=unglob_args(args), + ignore_errors=options.ignore_errors, + omit=omit, + include=include, + contexts=contexts, + ) + + # We need to be able to import from the current directory, because + # plugins may try to, for example, to read Django settings. + sys.path.insert(0, '') + + self.coverage.load() + + total = None + if options.action == "report": + total = self.coverage.report( + show_missing=options.show_missing, + skip_covered=options.skip_covered, + skip_empty=options.skip_empty, + precision=options.precision, + sort=options.sort, + **report_args + ) + elif options.action == "annotate": + self.coverage.annotate(directory=options.directory, **report_args) + elif options.action == "html": + total = self.coverage.html_report( + directory=options.directory, + title=options.title, + skip_covered=options.skip_covered, + skip_empty=options.skip_empty, + show_contexts=options.show_contexts, + precision=options.precision, + **report_args + ) + elif options.action == "xml": + outfile = options.outfile + total = self.coverage.xml_report( + outfile=outfile, skip_empty=options.skip_empty, + **report_args + ) + elif options.action == "json": + outfile = options.outfile + total = self.coverage.json_report( + outfile=outfile, + pretty_print=options.pretty_print, + show_contexts=options.show_contexts, + **report_args + ) + + if total is not None: + # Apply the command line fail-under options, and then use the config + # value, so we can get fail_under from the config file. + if options.fail_under is not None: + self.coverage.set_option("report:fail_under", options.fail_under) + + fail_under = self.coverage.get_option("report:fail_under") + precision = self.coverage.get_option("report:precision") + if should_fail_under(total, fail_under, precision): + msg = "total of {total:.{p}f} is less than fail-under={fail_under:.{p}f}".format( + total=total, fail_under=fail_under, p=precision, + ) + print("Coverage failure:", msg) + return FAIL_UNDER + + return OK + + def do_help(self, options, args, parser): + """Deal with help requests. + + Return True if it handled the request, False if not. + + """ + # Handle help. + if options.help: + if self.global_option: + show_help(topic='help') + else: + show_help(parser=parser) + return True + + if options.action == "help": + if args: + for a in args: + parser = CMDS.get(a) + if parser: + show_help(parser=parser) + else: + show_help(topic=a) + else: + show_help(topic='help') + return True + + # Handle version. + if options.version: + show_help(topic='version') + return True + + return False + + def do_run(self, options, args): + """Implementation of 'coverage run'.""" + + if not args: + if options.module: + # Specified -m with nothing else. + show_help("No module specified for -m") + return ERR + command_line = self.coverage.get_option("run:command_line") + if command_line is not None: + args = shlex.split(command_line) + if args and args[0] == "-m": + options.module = True + args = args[1:] + if not args: + show_help("Nothing to do.") + return ERR + + if options.append and self.coverage.get_option("run:parallel"): + show_help("Can't append to data files in parallel mode.") + return ERR + + if options.concurrency == "multiprocessing": + # Can't set other run-affecting command line options with + # multiprocessing. + for opt_name in ['branch', 'include', 'omit', 'pylib', 'source', 'timid']: + # As it happens, all of these options have no default, meaning + # they will be None if they have not been specified. + if getattr(options, opt_name) is not None: + show_help( + "Options affecting multiprocessing must only be specified " + "in a configuration file.\n" + "Remove --{} from the command line.".format(opt_name) + ) + return ERR + + runner = PyRunner(args, as_module=bool(options.module)) + runner.prepare() + + if options.append: + self.coverage.load() + + # Run the script. + self.coverage.start() + code_ran = True + try: + runner.run() + except NoSource: + code_ran = False + raise + finally: + self.coverage.stop() + if code_ran: + self.coverage.save() + + return OK + + def do_debug(self, args): + """Implementation of 'coverage debug'.""" + + if not args: + show_help("What information would you like: config, data, sys, premain?") + return ERR + + for info in args: + if info == 'sys': + sys_info = self.coverage.sys_info() + print(info_header("sys")) + for line in info_formatter(sys_info): + print(" %s" % line) + elif info == 'data': + self.coverage.load() + data = self.coverage.get_data() + print(info_header("data")) + print("path: %s" % data.data_filename()) + if data: + print("has_arcs: %r" % data.has_arcs()) + summary = line_counts(data, fullpath=True) + filenames = sorted(summary.keys()) + print("\n%d files:" % len(filenames)) + for f in filenames: + line = "%s: %d lines" % (f, summary[f]) + plugin = data.file_tracer(f) + if plugin: + line += " [%s]" % plugin + print(line) + else: + print("No data collected") + elif info == 'config': + print(info_header("config")) + config_info = self.coverage.config.__dict__.items() + for line in info_formatter(config_info): + print(" %s" % line) + elif info == "premain": + print(info_header("premain")) + print(short_stack()) + else: + show_help("Don't know what you mean by %r" % info) + return ERR + + return OK + + +def unshell_list(s): + """Turn a command-line argument into a list.""" + if not s: + return None + if env.WINDOWS: + # When running coverage.py as coverage.exe, some of the behavior + # of the shell is emulated: wildcards are expanded into a list of + # file names. So you have to single-quote patterns on the command + # line, but (not) helpfully, the single quotes are included in the + # argument, so we have to strip them off here. + s = s.strip("'") + return s.split(',') + + +def unglob_args(args): + """Interpret shell wildcards for platforms that need it.""" + if env.WINDOWS: + globbed = [] + for arg in args: + if '?' in arg or '*' in arg: + globbed.extend(glob.glob(arg)) + else: + globbed.append(arg) + args = globbed + return args + + +HELP_TOPICS = { + 'help': """\ + Coverage.py, version {__version__} {extension_modifier} + Measure, collect, and report on code coverage in Python programs. + + usage: {program_name} [options] [args] + + Commands: + annotate Annotate source files with execution information. + combine Combine a number of data files. + debug Display information about the internals of coverage.py + erase Erase previously collected coverage data. + help Get help on using coverage.py. + html Create an HTML report. + json Create a JSON report of coverage results. + report Report coverage stats on modules. + run Run a Python program and measure code execution. + xml Create an XML report of coverage results. + + Use "{program_name} help " for detailed help on any command. + """, + + 'minimum_help': """\ + Code coverage for Python, version {__version__} {extension_modifier}. Use '{program_name} help' for help. + """, + + 'version': """\ + Coverage.py, version {__version__} {extension_modifier} + """, +} + + +def main(argv=None): + """The main entry point to coverage.py. + + This is installed as the script entry point. + + """ + if argv is None: + argv = sys.argv[1:] + try: + status = CoverageScript().command_line(argv) + except ExceptionDuringRun as err: + # An exception was caught while running the product code. The + # sys.exc_info() return tuple is packed into an ExceptionDuringRun + # exception. + traceback.print_exception(*err.args) # pylint: disable=no-value-for-parameter + status = ERR + except BaseCoverageException as err: + # A controlled error inside coverage.py: print the message to the user. + msg = err.args[0] + if env.PY2: + msg = msg.encode(output_encoding()) + print(msg) + status = ERR + except SystemExit as err: + # The user called `sys.exit()`. Exit with their argument, if any. + if err.args: + status = err.args[0] + else: + status = None + return status + +# Profiling using ox_profile. Install it from GitHub: +# pip install git+https://github.com/emin63/ox_profile.git +# +# $set_env.py: COVERAGE_PROFILE - Set to use ox_profile. +_profile = os.environ.get("COVERAGE_PROFILE", "") +if _profile: # pragma: debugging + from ox_profile.core.launchers import SimpleLauncher # pylint: disable=import-error + original_main = main + + def main(argv=None): # pylint: disable=function-redefined + """A wrapper around main that profiles.""" + profiler = SimpleLauncher.launch() + try: + return original_main(argv) + finally: + data, _ = profiler.query(re_filter='coverage', max_records=100) + print(profiler.show(query=data, limit=100, sep='', col='')) + profiler.cancel() diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/collector.py b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/collector.py new file mode 100644 index 000000000..a4f1790dd --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/collector.py @@ -0,0 +1,451 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +"""Raw data collector for coverage.py.""" + +import os +import sys + +from coverage import env +from coverage.backward import litems, range # pylint: disable=redefined-builtin +from coverage.debug import short_stack +from coverage.disposition import FileDisposition +from coverage.misc import CoverageException, isolate_module +from coverage.pytracer import PyTracer + +os = isolate_module(os) + + +try: + # Use the C extension code when we can, for speed. + from coverage.tracer import CTracer, CFileDisposition +except ImportError: + # Couldn't import the C extension, maybe it isn't built. + if os.getenv('COVERAGE_TEST_TRACER') == 'c': + # During testing, we use the COVERAGE_TEST_TRACER environment variable + # to indicate that we've fiddled with the environment to test this + # fallback code. If we thought we had a C tracer, but couldn't import + # it, then exit quickly and clearly instead of dribbling confusing + # errors. I'm using sys.exit here instead of an exception because an + # exception here causes all sorts of other noise in unittest. + sys.stderr.write("*** COVERAGE_TEST_TRACER is 'c' but can't import CTracer!\n") + sys.exit(1) + CTracer = None + + +class Collector(object): + """Collects trace data. + + Creates a Tracer object for each thread, since they track stack + information. Each Tracer points to the same shared data, contributing + traced data points. + + When the Collector is started, it creates a Tracer for the current thread, + and installs a function to create Tracers for each new thread started. + When the Collector is stopped, all active Tracers are stopped. + + Threads started while the Collector is stopped will never have Tracers + associated with them. + + """ + + # The stack of active Collectors. Collectors are added here when started, + # and popped when stopped. Collectors on the stack are paused when not + # the top, and resumed when they become the top again. + _collectors = [] + + # The concurrency settings we support here. + SUPPORTED_CONCURRENCIES = {"greenlet", "eventlet", "gevent", "thread"} + + def __init__( + self, should_trace, check_include, should_start_context, file_mapper, + timid, branch, warn, concurrency, + ): + """Create a collector. + + `should_trace` is a function, taking a file name and a frame, and + returning a `coverage.FileDisposition object`. + + `check_include` is a function taking a file name and a frame. It returns + a boolean: True if the file should be traced, False if not. + + `should_start_context` is a function taking a frame, and returning a + string. If the frame should be the start of a new context, the string + is the new context. If the frame should not be the start of a new + context, return None. + + `file_mapper` is a function taking a filename, and returning a Unicode + filename. The result is the name that will be recorded in the data + file. + + If `timid` is true, then a slower simpler trace function will be + used. This is important for some environments where manipulation of + tracing functions make the faster more sophisticated trace function not + operate properly. + + If `branch` is true, then branches will be measured. This involves + collecting data on which statements followed each other (arcs). Use + `get_arc_data` to get the arc data. + + `warn` is a warning function, taking a single string message argument + and an optional slug argument which will be a string or None, to be + used if a warning needs to be issued. + + `concurrency` is a list of strings indicating the concurrency libraries + in use. Valid values are "greenlet", "eventlet", "gevent", or "thread" + (the default). Of these four values, only one can be supplied. Other + values are ignored. + + """ + self.should_trace = should_trace + self.check_include = check_include + self.should_start_context = should_start_context + self.file_mapper = file_mapper + self.warn = warn + self.branch = branch + self.threading = None + self.covdata = None + + self.static_context = None + + self.origin = short_stack() + + self.concur_id_func = None + self.mapped_file_cache = {} + + # We can handle a few concurrency options here, but only one at a time. + these_concurrencies = self.SUPPORTED_CONCURRENCIES.intersection(concurrency) + if len(these_concurrencies) > 1: + raise CoverageException("Conflicting concurrency settings: %s" % concurrency) + self.concurrency = these_concurrencies.pop() if these_concurrencies else '' + + try: + if self.concurrency == "greenlet": + import greenlet + self.concur_id_func = greenlet.getcurrent + elif self.concurrency == "eventlet": + import eventlet.greenthread # pylint: disable=import-error,useless-suppression + self.concur_id_func = eventlet.greenthread.getcurrent + elif self.concurrency == "gevent": + import gevent # pylint: disable=import-error,useless-suppression + self.concur_id_func = gevent.getcurrent + elif self.concurrency == "thread" or not self.concurrency: + # It's important to import threading only if we need it. If + # it's imported early, and the program being measured uses + # gevent, then gevent's monkey-patching won't work properly. + import threading + self.threading = threading + else: + raise CoverageException("Don't understand concurrency=%s" % concurrency) + except ImportError: + raise CoverageException( + "Couldn't trace with concurrency=%s, the module isn't installed." % ( + self.concurrency, + ) + ) + + self.reset() + + if timid: + # Being timid: use the simple Python trace function. + self._trace_class = PyTracer + else: + # Being fast: use the C Tracer if it is available, else the Python + # trace function. + self._trace_class = CTracer or PyTracer + + if self._trace_class is CTracer: + self.file_disposition_class = CFileDisposition + self.supports_plugins = True + else: + self.file_disposition_class = FileDisposition + self.supports_plugins = False + + def __repr__(self): + return "" % (id(self), self.tracer_name()) + + def use_data(self, covdata, context): + """Use `covdata` for recording data.""" + self.covdata = covdata + self.static_context = context + self.covdata.set_context(self.static_context) + + def tracer_name(self): + """Return the class name of the tracer we're using.""" + return self._trace_class.__name__ + + def _clear_data(self): + """Clear out existing data, but stay ready for more collection.""" + # We used to used self.data.clear(), but that would remove filename + # keys and data values that were still in use higher up the stack + # when we are called as part of switch_context. + for d in self.data.values(): + d.clear() + + for tracer in self.tracers: + tracer.reset_activity() + + def reset(self): + """Clear collected data, and prepare to collect more.""" + # A dictionary mapping file names to dicts with line number keys (if not + # branch coverage), or mapping file names to dicts with line number + # pairs as keys (if branch coverage). + self.data = {} + + # A dictionary mapping file names to file tracer plugin names that will + # handle them. + self.file_tracers = {} + + self.disabled_plugins = set() + + # The .should_trace_cache attribute is a cache from file names to + # coverage.FileDisposition objects, or None. When a file is first + # considered for tracing, a FileDisposition is obtained from + # Coverage.should_trace. Its .trace attribute indicates whether the + # file should be traced or not. If it should be, a plugin with dynamic + # file names can decide not to trace it based on the dynamic file name + # being excluded by the inclusion rules, in which case the + # FileDisposition will be replaced by None in the cache. + if env.PYPY: + import __pypy__ # pylint: disable=import-error + # Alex Gaynor said: + # should_trace_cache is a strictly growing key: once a key is in + # it, it never changes. Further, the keys used to access it are + # generally constant, given sufficient context. That is to say, at + # any given point _trace() is called, pypy is able to know the key. + # This is because the key is determined by the physical source code + # line, and that's invariant with the call site. + # + # This property of a dict with immutable keys, combined with + # call-site-constant keys is a match for PyPy's module dict, + # which is optimized for such workloads. + # + # This gives a 20% benefit on the workload described at + # https://bitbucket.org/pypy/pypy/issue/1871/10x-slower-than-cpython-under-coverage + self.should_trace_cache = __pypy__.newdict("module") + else: + self.should_trace_cache = {} + + # Our active Tracers. + self.tracers = [] + + self._clear_data() + + def _start_tracer(self): + """Start a new Tracer object, and store it in self.tracers.""" + tracer = self._trace_class() + tracer.data = self.data + tracer.trace_arcs = self.branch + tracer.should_trace = self.should_trace + tracer.should_trace_cache = self.should_trace_cache + tracer.warn = self.warn + + if hasattr(tracer, 'concur_id_func'): + tracer.concur_id_func = self.concur_id_func + elif self.concur_id_func: + raise CoverageException( + "Can't support concurrency=%s with %s, only threads are supported" % ( + self.concurrency, self.tracer_name(), + ) + ) + + if hasattr(tracer, 'file_tracers'): + tracer.file_tracers = self.file_tracers + if hasattr(tracer, 'threading'): + tracer.threading = self.threading + if hasattr(tracer, 'check_include'): + tracer.check_include = self.check_include + if hasattr(tracer, 'should_start_context'): + tracer.should_start_context = self.should_start_context + tracer.switch_context = self.switch_context + if hasattr(tracer, 'disable_plugin'): + tracer.disable_plugin = self.disable_plugin + + fn = tracer.start() + self.tracers.append(tracer) + + return fn + + # The trace function has to be set individually on each thread before + # execution begins. Ironically, the only support the threading module has + # for running code before the thread main is the tracing function. So we + # install this as a trace function, and the first time it's called, it does + # the real trace installation. + + def _installation_trace(self, frame, event, arg): + """Called on new threads, installs the real tracer.""" + # Remove ourselves as the trace function. + sys.settrace(None) + # Install the real tracer. + fn = self._start_tracer() + # Invoke the real trace function with the current event, to be sure + # not to lose an event. + if fn: + fn = fn(frame, event, arg) + # Return the new trace function to continue tracing in this scope. + return fn + + def start(self): + """Start collecting trace information.""" + if self._collectors: + self._collectors[-1].pause() + + self.tracers = [] + + # Check to see whether we had a fullcoverage tracer installed. If so, + # get the stack frames it stashed away for us. + traces0 = [] + fn0 = sys.gettrace() + if fn0: + tracer0 = getattr(fn0, '__self__', None) + if tracer0: + traces0 = getattr(tracer0, 'traces', []) + + try: + # Install the tracer on this thread. + fn = self._start_tracer() + except: + if self._collectors: + self._collectors[-1].resume() + raise + + # If _start_tracer succeeded, then we add ourselves to the global + # stack of collectors. + self._collectors.append(self) + + # Replay all the events from fullcoverage into the new trace function. + for args in traces0: + (frame, event, arg), lineno = args + try: + fn(frame, event, arg, lineno=lineno) + except TypeError: + raise Exception("fullcoverage must be run with the C trace function.") + + # Install our installation tracer in threading, to jump-start other + # threads. + if self.threading: + self.threading.settrace(self._installation_trace) + + def stop(self): + """Stop collecting trace information.""" + assert self._collectors + if self._collectors[-1] is not self: + print("self._collectors:") + for c in self._collectors: + print(" {!r}\n{}".format(c, c.origin)) + assert self._collectors[-1] is self, ( + "Expected current collector to be %r, but it's %r" % (self, self._collectors[-1]) + ) + + self.pause() + + # Remove this Collector from the stack, and resume the one underneath + # (if any). + self._collectors.pop() + if self._collectors: + self._collectors[-1].resume() + + def pause(self): + """Pause tracing, but be prepared to `resume`.""" + for tracer in self.tracers: + tracer.stop() + stats = tracer.get_stats() + if stats: + print("\nCoverage.py tracer stats:") + for k in sorted(stats.keys()): + print("%20s: %s" % (k, stats[k])) + if self.threading: + self.threading.settrace(None) + + def resume(self): + """Resume tracing after a `pause`.""" + for tracer in self.tracers: + tracer.start() + if self.threading: + self.threading.settrace(self._installation_trace) + else: + self._start_tracer() + + def _activity(self): + """Has any activity been traced? + + Returns a boolean, True if any trace function was invoked. + + """ + return any(tracer.activity() for tracer in self.tracers) + + def switch_context(self, new_context): + """Switch to a new dynamic context.""" + self.flush_data() + if self.static_context: + context = self.static_context + if new_context: + context += "|" + new_context + else: + context = new_context + self.covdata.set_context(context) + + def disable_plugin(self, disposition): + """Disable the plugin mentioned in `disposition`.""" + file_tracer = disposition.file_tracer + plugin = file_tracer._coverage_plugin + plugin_name = plugin._coverage_plugin_name + self.warn("Disabling plug-in {!r} due to previous exception".format(plugin_name)) + plugin._coverage_enabled = False + disposition.trace = False + + def cached_mapped_file(self, filename): + """A locally cached version of file names mapped through file_mapper.""" + key = (type(filename), filename) + try: + return self.mapped_file_cache[key] + except KeyError: + return self.mapped_file_cache.setdefault(key, self.file_mapper(filename)) + + def mapped_file_dict(self, d): + """Return a dict like d, but with keys modified by file_mapper.""" + # The call to litems() ensures that the GIL protects the dictionary + # iterator against concurrent modifications by tracers running + # in other threads. We try three times in case of concurrent + # access, hoping to get a clean copy. + runtime_err = None + for _ in range(3): + try: + items = litems(d) + except RuntimeError as ex: + runtime_err = ex + else: + break + else: + raise runtime_err + + return dict((self.cached_mapped_file(k), v) for k, v in items if v) + + def plugin_was_disabled(self, plugin): + """Record that `plugin` was disabled during the run.""" + self.disabled_plugins.add(plugin._coverage_plugin_name) + + def flush_data(self): + """Save the collected data to our associated `CoverageData`. + + Data may have also been saved along the way. This forces the + last of the data to be saved. + + Returns True if there was data to save, False if not. + """ + if not self._activity(): + return False + + if self.branch: + self.covdata.add_arcs(self.mapped_file_dict(self.data)) + else: + self.covdata.add_lines(self.mapped_file_dict(self.data)) + + file_tracers = { + k: v for k, v in self.file_tracers.items() + if v not in self.disabled_plugins + } + self.covdata.add_file_tracers(self.mapped_file_dict(file_tracers)) + + self._clear_data() + return True diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/config.py b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/config.py new file mode 100644 index 000000000..7ef7e7ae7 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/config.py @@ -0,0 +1,570 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +"""Config file for coverage.py""" + +import collections +import copy +import os +import os.path +import re + +from coverage import env +from coverage.backward import configparser, iitems, string_class +from coverage.misc import contract, CoverageException, isolate_module +from coverage.misc import substitute_variables + +from coverage.tomlconfig import TomlConfigParser, TomlDecodeError + +os = isolate_module(os) + + +class HandyConfigParser(configparser.RawConfigParser): + """Our specialization of ConfigParser.""" + + def __init__(self, our_file): + """Create the HandyConfigParser. + + `our_file` is True if this config file is specifically for coverage, + False if we are examining another config file (tox.ini, setup.cfg) + for possible settings. + """ + + configparser.RawConfigParser.__init__(self) + self.section_prefixes = ["coverage:"] + if our_file: + self.section_prefixes.append("") + + def read(self, filenames, encoding=None): + """Read a file name as UTF-8 configuration data.""" + kwargs = {} + if env.PYVERSION >= (3, 2): + kwargs['encoding'] = encoding or "utf-8" + return configparser.RawConfigParser.read(self, filenames, **kwargs) + + def has_option(self, section, option): + for section_prefix in self.section_prefixes: + real_section = section_prefix + section + has = configparser.RawConfigParser.has_option(self, real_section, option) + if has: + return has + return False + + def has_section(self, section): + for section_prefix in self.section_prefixes: + real_section = section_prefix + section + has = configparser.RawConfigParser.has_section(self, real_section) + if has: + return real_section + return False + + def options(self, section): + for section_prefix in self.section_prefixes: + real_section = section_prefix + section + if configparser.RawConfigParser.has_section(self, real_section): + return configparser.RawConfigParser.options(self, real_section) + raise configparser.NoSectionError(section) + + def get_section(self, section): + """Get the contents of a section, as a dictionary.""" + d = {} + for opt in self.options(section): + d[opt] = self.get(section, opt) + return d + + def get(self, section, option, *args, **kwargs): + """Get a value, replacing environment variables also. + + The arguments are the same as `RawConfigParser.get`, but in the found + value, ``$WORD`` or ``${WORD}`` are replaced by the value of the + environment variable ``WORD``. + + Returns the finished value. + + """ + for section_prefix in self.section_prefixes: + real_section = section_prefix + section + if configparser.RawConfigParser.has_option(self, real_section, option): + break + else: + raise configparser.NoOptionError(option, section) + + v = configparser.RawConfigParser.get(self, real_section, option, *args, **kwargs) + v = substitute_variables(v, os.environ) + return v + + def getlist(self, section, option): + """Read a list of strings. + + The value of `section` and `option` is treated as a comma- and newline- + separated list of strings. Each value is stripped of whitespace. + + Returns the list of strings. + + """ + value_list = self.get(section, option) + values = [] + for value_line in value_list.split('\n'): + for value in value_line.split(','): + value = value.strip() + if value: + values.append(value) + return values + + def getregexlist(self, section, option): + """Read a list of full-line regexes. + + The value of `section` and `option` is treated as a newline-separated + list of regexes. Each value is stripped of whitespace. + + Returns the list of strings. + + """ + line_list = self.get(section, option) + value_list = [] + for value in line_list.splitlines(): + value = value.strip() + try: + re.compile(value) + except re.error as e: + raise CoverageException( + "Invalid [%s].%s value %r: %s" % (section, option, value, e) + ) + if value: + value_list.append(value) + return value_list + + +# The default line exclusion regexes. +DEFAULT_EXCLUDE = [ + r'#\s*(pragma|PRAGMA)[:\s]?\s*(no|NO)\s*(cover|COVER)', +] + +# The default partial branch regexes, to be modified by the user. +DEFAULT_PARTIAL = [ + r'#\s*(pragma|PRAGMA)[:\s]?\s*(no|NO)\s*(branch|BRANCH)', +] + +# The default partial branch regexes, based on Python semantics. +# These are any Python branching constructs that can't actually execute all +# their branches. +DEFAULT_PARTIAL_ALWAYS = [ + 'while (True|1|False|0):', + 'if (True|1|False|0):', +] + + +class CoverageConfig(object): + """Coverage.py configuration. + + The attributes of this class are the various settings that control the + operation of coverage.py. + + """ + # pylint: disable=too-many-instance-attributes + + def __init__(self): + """Initialize the configuration attributes to their defaults.""" + # Metadata about the config. + # We tried to read these config files. + self.attempted_config_files = [] + # We did read these config files, but maybe didn't find any content for us. + self.config_files_read = [] + # The file that gave us our configuration. + self.config_file = None + self._config_contents = None + + # Defaults for [run] and [report] + self._include = None + self._omit = None + + # Defaults for [run] + self.branch = False + self.command_line = None + self.concurrency = None + self.context = None + self.cover_pylib = False + self.data_file = ".coverage" + self.debug = [] + self.disable_warnings = [] + self.dynamic_context = None + self.note = None + self.parallel = False + self.plugins = [] + self.relative_files = False + self.run_include = None + self.run_omit = None + self.source = None + self.source_pkgs = [] + self.timid = False + self._crash = None + + # Defaults for [report] + self.exclude_list = DEFAULT_EXCLUDE[:] + self.fail_under = 0.0 + self.ignore_errors = False + self.report_include = None + self.report_omit = None + self.partial_always_list = DEFAULT_PARTIAL_ALWAYS[:] + self.partial_list = DEFAULT_PARTIAL[:] + self.precision = 0 + self.report_contexts = None + self.show_missing = False + self.skip_covered = False + self.skip_empty = False + self.sort = None + + # Defaults for [html] + self.extra_css = None + self.html_dir = "htmlcov" + self.html_skip_covered = None + self.html_skip_empty = None + self.html_title = "Coverage report" + self.show_contexts = False + + # Defaults for [xml] + self.xml_output = "coverage.xml" + self.xml_package_depth = 99 + + # Defaults for [json] + self.json_output = "coverage.json" + self.json_pretty_print = False + self.json_show_contexts = False + + # Defaults for [paths] + self.paths = collections.OrderedDict() + + # Options for plugins + self.plugin_options = {} + + MUST_BE_LIST = [ + "debug", "concurrency", "plugins", + "report_omit", "report_include", + "run_omit", "run_include", + ] + + def from_args(self, **kwargs): + """Read config values from `kwargs`.""" + for k, v in iitems(kwargs): + if v is not None: + if k in self.MUST_BE_LIST and isinstance(v, string_class): + v = [v] + setattr(self, k, v) + + @contract(filename=str) + def from_file(self, filename, our_file): + """Read configuration from a .rc file. + + `filename` is a file name to read. + + `our_file` is True if this config file is specifically for coverage, + False if we are examining another config file (tox.ini, setup.cfg) + for possible settings. + + Returns True or False, whether the file could be read, and it had some + coverage.py settings in it. + + """ + _, ext = os.path.splitext(filename) + if ext == '.toml': + cp = TomlConfigParser(our_file) + else: + cp = HandyConfigParser(our_file) + + self.attempted_config_files.append(filename) + + try: + files_read = cp.read(filename) + except (configparser.Error, TomlDecodeError) as err: + raise CoverageException("Couldn't read config file %s: %s" % (filename, err)) + if not files_read: + return False + + self.config_files_read.extend(map(os.path.abspath, files_read)) + + any_set = False + try: + for option_spec in self.CONFIG_FILE_OPTIONS: + was_set = self._set_attr_from_config_option(cp, *option_spec) + if was_set: + any_set = True + except ValueError as err: + raise CoverageException("Couldn't read config file %s: %s" % (filename, err)) + + # Check that there are no unrecognized options. + all_options = collections.defaultdict(set) + for option_spec in self.CONFIG_FILE_OPTIONS: + section, option = option_spec[1].split(":") + all_options[section].add(option) + + for section, options in iitems(all_options): + real_section = cp.has_section(section) + if real_section: + for unknown in set(cp.options(section)) - options: + raise CoverageException( + "Unrecognized option '[%s] %s=' in config file %s" % ( + real_section, unknown, filename + ) + ) + + # [paths] is special + if cp.has_section('paths'): + for option in cp.options('paths'): + self.paths[option] = cp.getlist('paths', option) + any_set = True + + # plugins can have options + for plugin in self.plugins: + if cp.has_section(plugin): + self.plugin_options[plugin] = cp.get_section(plugin) + any_set = True + + # Was this file used as a config file? If it's specifically our file, + # then it was used. If we're piggybacking on someone else's file, + # then it was only used if we found some settings in it. + if our_file: + used = True + else: + used = any_set + + if used: + self.config_file = os.path.abspath(filename) + with open(filename, "rb") as f: + self._config_contents = f.read() + + return used + + def copy(self): + """Return a copy of the configuration.""" + return copy.deepcopy(self) + + CONFIG_FILE_OPTIONS = [ + # These are *args for _set_attr_from_config_option: + # (attr, where, type_="") + # + # attr is the attribute to set on the CoverageConfig object. + # where is the section:name to read from the configuration file. + # type_ is the optional type to apply, by using .getTYPE to read the + # configuration value from the file. + + # [run] + ('branch', 'run:branch', 'boolean'), + ('command_line', 'run:command_line'), + ('concurrency', 'run:concurrency', 'list'), + ('context', 'run:context'), + ('cover_pylib', 'run:cover_pylib', 'boolean'), + ('data_file', 'run:data_file'), + ('debug', 'run:debug', 'list'), + ('disable_warnings', 'run:disable_warnings', 'list'), + ('dynamic_context', 'run:dynamic_context'), + ('note', 'run:note'), + ('parallel', 'run:parallel', 'boolean'), + ('plugins', 'run:plugins', 'list'), + ('relative_files', 'run:relative_files', 'boolean'), + ('run_include', 'run:include', 'list'), + ('run_omit', 'run:omit', 'list'), + ('source', 'run:source', 'list'), + ('source_pkgs', 'run:source_pkgs', 'list'), + ('timid', 'run:timid', 'boolean'), + ('_crash', 'run:_crash'), + + # [report] + ('exclude_list', 'report:exclude_lines', 'regexlist'), + ('fail_under', 'report:fail_under', 'float'), + ('ignore_errors', 'report:ignore_errors', 'boolean'), + ('partial_always_list', 'report:partial_branches_always', 'regexlist'), + ('partial_list', 'report:partial_branches', 'regexlist'), + ('precision', 'report:precision', 'int'), + ('report_contexts', 'report:contexts', 'list'), + ('report_include', 'report:include', 'list'), + ('report_omit', 'report:omit', 'list'), + ('show_missing', 'report:show_missing', 'boolean'), + ('skip_covered', 'report:skip_covered', 'boolean'), + ('skip_empty', 'report:skip_empty', 'boolean'), + ('sort', 'report:sort'), + + # [html] + ('extra_css', 'html:extra_css'), + ('html_dir', 'html:directory'), + ('html_skip_covered', 'html:skip_covered', 'boolean'), + ('html_skip_empty', 'html:skip_empty', 'boolean'), + ('html_title', 'html:title'), + ('show_contexts', 'html:show_contexts', 'boolean'), + + # [xml] + ('xml_output', 'xml:output'), + ('xml_package_depth', 'xml:package_depth', 'int'), + + # [json] + ('json_output', 'json:output'), + ('json_pretty_print', 'json:pretty_print', 'boolean'), + ('json_show_contexts', 'json:show_contexts', 'boolean'), + ] + + def _set_attr_from_config_option(self, cp, attr, where, type_=''): + """Set an attribute on self if it exists in the ConfigParser. + + Returns True if the attribute was set. + + """ + section, option = where.split(":") + if cp.has_option(section, option): + method = getattr(cp, 'get' + type_) + setattr(self, attr, method(section, option)) + return True + return False + + def get_plugin_options(self, plugin): + """Get a dictionary of options for the plugin named `plugin`.""" + return self.plugin_options.get(plugin, {}) + + def set_option(self, option_name, value): + """Set an option in the configuration. + + `option_name` is a colon-separated string indicating the section and + option name. For example, the ``branch`` option in the ``[run]`` + section of the config file would be indicated with `"run:branch"`. + + `value` is the new value for the option. + + """ + # Special-cased options. + if option_name == "paths": + self.paths = value + return + + # Check all the hard-coded options. + for option_spec in self.CONFIG_FILE_OPTIONS: + attr, where = option_spec[:2] + if where == option_name: + setattr(self, attr, value) + return + + # See if it's a plugin option. + plugin_name, _, key = option_name.partition(":") + if key and plugin_name in self.plugins: + self.plugin_options.setdefault(plugin_name, {})[key] = value + return + + # If we get here, we didn't find the option. + raise CoverageException("No such option: %r" % option_name) + + def get_option(self, option_name): + """Get an option from the configuration. + + `option_name` is a colon-separated string indicating the section and + option name. For example, the ``branch`` option in the ``[run]`` + section of the config file would be indicated with `"run:branch"`. + + Returns the value of the option. + + """ + # Special-cased options. + if option_name == "paths": + return self.paths + + # Check all the hard-coded options. + for option_spec in self.CONFIG_FILE_OPTIONS: + attr, where = option_spec[:2] + if where == option_name: + return getattr(self, attr) + + # See if it's a plugin option. + plugin_name, _, key = option_name.partition(":") + if key and plugin_name in self.plugins: + return self.plugin_options.get(plugin_name, {}).get(key) + + # If we get here, we didn't find the option. + raise CoverageException("No such option: %r" % option_name) + + def post_process_file(self, path): + """Make final adjustments to a file path to make it usable.""" + return os.path.expanduser(path) + + def post_process(self): + """Make final adjustments to settings to make them usable.""" + self.data_file = self.post_process_file(self.data_file) + self.html_dir = self.post_process_file(self.html_dir) + self.xml_output = self.post_process_file(self.xml_output) + self.paths = collections.OrderedDict( + (k, [self.post_process_file(f) for f in v]) + for k, v in self.paths.items() + ) + + +def config_files_to_try(config_file): + """What config files should we try to read? + + Returns a list of tuples: + (filename, is_our_file, was_file_specified) + """ + + # Some API users were specifying ".coveragerc" to mean the same as + # True, so make it so. + if config_file == ".coveragerc": + config_file = True + specified_file = (config_file is not True) + if not specified_file: + # No file was specified. Check COVERAGE_RCFILE. + config_file = os.environ.get('COVERAGE_RCFILE') + if config_file: + specified_file = True + if not specified_file: + # Still no file specified. Default to .coveragerc + config_file = ".coveragerc" + files_to_try = [ + (config_file, True, specified_file), + ("setup.cfg", False, False), + ("tox.ini", False, False), + ("pyproject.toml", False, False), + ] + return files_to_try + + +def read_coverage_config(config_file, **kwargs): + """Read the coverage.py configuration. + + Arguments: + config_file: a boolean or string, see the `Coverage` class for the + tricky details. + all others: keyword arguments from the `Coverage` class, used for + setting values in the configuration. + + Returns: + config: + config is a CoverageConfig object read from the appropriate + configuration file. + + """ + # Build the configuration from a number of sources: + # 1) defaults: + config = CoverageConfig() + + # 2) from a file: + if config_file: + files_to_try = config_files_to_try(config_file) + + for fname, our_file, specified_file in files_to_try: + config_read = config.from_file(fname, our_file=our_file) + if config_read: + break + if specified_file: + raise CoverageException("Couldn't read '%s' as a config file" % fname) + + # $set_env.py: COVERAGE_DEBUG - Options for --debug. + # 3) from environment variables: + env_data_file = os.environ.get('COVERAGE_FILE') + if env_data_file: + config.data_file = env_data_file + debugs = os.environ.get('COVERAGE_DEBUG') + if debugs: + config.debug.extend(d.strip() for d in debugs.split(",")) + + # 4) from constructor arguments: + config.from_args(**kwargs) + + # Once all the config has been collected, there's a little post-processing + # to do. + config.post_process() + + return config diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/context.py b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/context.py new file mode 100644 index 000000000..ea13da21e --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/context.py @@ -0,0 +1,91 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +"""Determine contexts for coverage.py""" + + +def combine_context_switchers(context_switchers): + """Create a single context switcher from multiple switchers. + + `context_switchers` is a list of functions that take a frame as an + argument and return a string to use as the new context label. + + Returns a function that composites `context_switchers` functions, or None + if `context_switchers` is an empty list. + + When invoked, the combined switcher calls `context_switchers` one-by-one + until a string is returned. The combined switcher returns None if all + `context_switchers` return None. + """ + if not context_switchers: + return None + + if len(context_switchers) == 1: + return context_switchers[0] + + def should_start_context(frame): + """The combiner for multiple context switchers.""" + for switcher in context_switchers: + new_context = switcher(frame) + if new_context is not None: + return new_context + return None + + return should_start_context + + +def should_start_context_test_function(frame): + """Is this frame calling a test_* function?""" + co_name = frame.f_code.co_name + if co_name.startswith("test") or co_name == "runTest": + return qualname_from_frame(frame) + return None + + +def qualname_from_frame(frame): + """Get a qualified name for the code running in `frame`.""" + co = frame.f_code + fname = co.co_name + method = None + if co.co_argcount and co.co_varnames[0] == "self": + self = frame.f_locals["self"] + method = getattr(self, fname, None) + + if method is None: + func = frame.f_globals.get(fname) + if func is None: + return None + return func.__module__ + '.' + fname + + func = getattr(method, '__func__', None) + if func is None: + cls = self.__class__ + return cls.__module__ + '.' + cls.__name__ + "." + fname + + if hasattr(func, '__qualname__'): + qname = func.__module__ + '.' + func.__qualname__ + else: + for cls in getattr(self.__class__, '__mro__', ()): + f = cls.__dict__.get(fname, None) + if f is None: + continue + if f is func: + qname = cls.__module__ + '.' + cls.__name__ + "." + fname + break + else: + # Support for old-style classes. + def mro(bases): + for base in bases: + f = base.__dict__.get(fname, None) + if f is func: + return base.__module__ + '.' + base.__name__ + "." + fname + for base in bases: + qname = mro(base.__bases__) + if qname is not None: + return qname + return None + qname = mro([self.__class__]) + if qname is None: + qname = func.__module__ + '.' + fname + + return qname diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/control.py b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/control.py new file mode 100644 index 000000000..1623b0932 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/control.py @@ -0,0 +1,1145 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +"""Core control stuff for coverage.py.""" + +import atexit +import collections +import contextlib +import os +import os.path +import platform +import sys +import time + +from coverage import env +from coverage.annotate import AnnotateReporter +from coverage.backward import string_class, iitems +from coverage.collector import Collector, CTracer +from coverage.config import read_coverage_config +from coverage.context import should_start_context_test_function, combine_context_switchers +from coverage.data import CoverageData, combine_parallel_data +from coverage.debug import DebugControl, short_stack, write_formatted_info +from coverage.disposition import disposition_debug_msg +from coverage.files import PathAliases, abs_file, relative_filename, set_relative_directory +from coverage.html import HtmlReporter +from coverage.inorout import InOrOut +from coverage.jsonreport import JsonReporter +from coverage.misc import CoverageException, bool_or_none, join_regex +from coverage.misc import DefaultValue, ensure_dir_for_file, isolate_module +from coverage.plugin import FileReporter +from coverage.plugin_support import Plugins +from coverage.python import PythonFileReporter +from coverage.report import render_report +from coverage.results import Analysis, Numbers +from coverage.summary import SummaryReporter +from coverage.xmlreport import XmlReporter + +try: + from coverage.multiproc import patch_multiprocessing +except ImportError: # pragma: only jython + # Jython has no multiprocessing module. + patch_multiprocessing = None + +os = isolate_module(os) + +@contextlib.contextmanager +def override_config(cov, **kwargs): + """Temporarily tweak the configuration of `cov`. + + The arguments are applied to `cov.config` with the `from_args` method. + At the end of the with-statement, the old configuration is restored. + """ + original_config = cov.config + cov.config = cov.config.copy() + try: + cov.config.from_args(**kwargs) + yield + finally: + cov.config = original_config + + +_DEFAULT_DATAFILE = DefaultValue("MISSING") + +class Coverage(object): + """Programmatic access to coverage.py. + + To use:: + + from coverage import Coverage + + cov = Coverage() + cov.start() + #.. call your code .. + cov.stop() + cov.html_report(directory='covhtml') + + Note: in keeping with Python custom, names starting with underscore are + not part of the public API. They might stop working at any point. Please + limit yourself to documented methods to avoid problems. + + """ + + # The stack of started Coverage instances. + _instances = [] + + @classmethod + def current(cls): + """Get the latest started `Coverage` instance, if any. + + Returns: a `Coverage` instance, or None. + + .. versionadded:: 5.0 + + """ + if cls._instances: + return cls._instances[-1] + else: + return None + + def __init__( + self, data_file=_DEFAULT_DATAFILE, data_suffix=None, cover_pylib=None, + auto_data=False, timid=None, branch=None, config_file=True, + source=None, source_pkgs=None, omit=None, include=None, debug=None, + concurrency=None, check_preimported=False, context=None, + ): # pylint: disable=too-many-arguments + """ + Many of these arguments duplicate and override values that can be + provided in a configuration file. Parameters that are missing here + will use values from the config file. + + `data_file` is the base name of the data file to use. The config value + defaults to ".coverage". None can be provided to prevent writing a data + file. `data_suffix` is appended (with a dot) to `data_file` to create + the final file name. If `data_suffix` is simply True, then a suffix is + created with the machine and process identity included. + + `cover_pylib` is a boolean determining whether Python code installed + with the Python interpreter is measured. This includes the Python + standard library and any packages installed with the interpreter. + + If `auto_data` is true, then any existing data file will be read when + coverage measurement starts, and data will be saved automatically when + measurement stops. + + If `timid` is true, then a slower and simpler trace function will be + used. This is important for some environments where manipulation of + tracing functions breaks the faster trace function. + + If `branch` is true, then branch coverage will be measured in addition + to the usual statement coverage. + + `config_file` determines what configuration file to read: + + * If it is ".coveragerc", it is interpreted as if it were True, + for backward compatibility. + + * If it is a string, it is the name of the file to read. If the + file can't be read, it is an error. + + * If it is True, then a few standard files names are tried + (".coveragerc", "setup.cfg", "tox.ini"). It is not an error for + these files to not be found. + + * If it is False, then no configuration file is read. + + `source` is a list of file paths or package names. Only code located + in the trees indicated by the file paths or package names will be + measured. + + `source_pkgs` is a list of package names. It works the same as + `source`, but can be used to name packages where the name can also be + interpreted as a file path. + + `include` and `omit` are lists of file name patterns. Files that match + `include` will be measured, files that match `omit` will not. Each + will also accept a single string argument. + + `debug` is a list of strings indicating what debugging information is + desired. + + `concurrency` is a string indicating the concurrency library being used + in the measured code. Without this, coverage.py will get incorrect + results if these libraries are in use. Valid strings are "greenlet", + "eventlet", "gevent", "multiprocessing", or "thread" (the default). + This can also be a list of these strings. + + If `check_preimported` is true, then when coverage is started, the + already-imported files will be checked to see if they should be + measured by coverage. Importing measured files before coverage is + started can mean that code is missed. + + `context` is a string to use as the :ref:`static context + ` label for collected data. + + .. versionadded:: 4.0 + The `concurrency` parameter. + + .. versionadded:: 4.2 + The `concurrency` parameter can now be a list of strings. + + .. versionadded:: 5.0 + The `check_preimported` and `context` parameters. + + .. versionadded:: 5.3 + The `source_pkgs` parameter. + + """ + # data_file=None means no disk file at all. data_file missing means + # use the value from the config file. + self._no_disk = data_file is None + if data_file is _DEFAULT_DATAFILE: + data_file = None + + # Build our configuration from a number of sources. + self.config = read_coverage_config( + config_file=config_file, + data_file=data_file, cover_pylib=cover_pylib, timid=timid, + branch=branch, parallel=bool_or_none(data_suffix), + source=source, source_pkgs=source_pkgs, run_omit=omit, run_include=include, debug=debug, + report_omit=omit, report_include=include, + concurrency=concurrency, context=context, + ) + + # This is injectable by tests. + self._debug_file = None + + self._auto_load = self._auto_save = auto_data + self._data_suffix_specified = data_suffix + + # Is it ok for no data to be collected? + self._warn_no_data = True + self._warn_unimported_source = True + self._warn_preimported_source = check_preimported + self._no_warn_slugs = None + + # A record of all the warnings that have been issued. + self._warnings = [] + + # Other instance attributes, set later. + self._data = self._collector = None + self._plugins = None + self._inorout = None + self._data_suffix = self._run_suffix = None + self._exclude_re = None + self._debug = None + self._file_mapper = None + + # State machine variables: + # Have we initialized everything? + self._inited = False + self._inited_for_start = False + # Have we started collecting and not stopped it? + self._started = False + # Should we write the debug output? + self._should_write_debug = True + + # If we have sub-process measurement happening automatically, then we + # want any explicit creation of a Coverage object to mean, this process + # is already coverage-aware, so don't auto-measure it. By now, the + # auto-creation of a Coverage object has already happened. But we can + # find it and tell it not to save its data. + if not env.METACOV: + _prevent_sub_process_measurement() + + def _init(self): + """Set all the initial state. + + This is called by the public methods to initialize state. This lets us + construct a :class:`Coverage` object, then tweak its state before this + function is called. + + """ + if self._inited: + return + + self._inited = True + + # Create and configure the debugging controller. COVERAGE_DEBUG_FILE + # is an environment variable, the name of a file to append debug logs + # to. + self._debug = DebugControl(self.config.debug, self._debug_file) + + if "multiprocessing" in (self.config.concurrency or ()): + # Multi-processing uses parallel for the subprocesses, so also use + # it for the main process. + self.config.parallel = True + + # _exclude_re is a dict that maps exclusion list names to compiled regexes. + self._exclude_re = {} + + set_relative_directory() + self._file_mapper = relative_filename if self.config.relative_files else abs_file + + # Load plugins + self._plugins = Plugins.load_plugins(self.config.plugins, self.config, self._debug) + + # Run configuring plugins. + for plugin in self._plugins.configurers: + # We need an object with set_option and get_option. Either self or + # self.config will do. Choosing randomly stops people from doing + # other things with those objects, against the public API. Yes, + # this is a bit childish. :) + plugin.configure([self, self.config][int(time.time()) % 2]) + + def _post_init(self): + """Stuff to do after everything is initialized.""" + if self._should_write_debug: + self._should_write_debug = False + self._write_startup_debug() + + # '[run] _crash' will raise an exception if the value is close by in + # the call stack, for testing error handling. + if self.config._crash and self.config._crash in short_stack(limit=4): + raise Exception("Crashing because called by {}".format(self.config._crash)) + + def _write_startup_debug(self): + """Write out debug info at startup if needed.""" + wrote_any = False + with self._debug.without_callers(): + if self._debug.should('config'): + config_info = sorted(self.config.__dict__.items()) + config_info = [(k, v) for k, v in config_info if not k.startswith('_')] + write_formatted_info(self._debug, "config", config_info) + wrote_any = True + + if self._debug.should('sys'): + write_formatted_info(self._debug, "sys", self.sys_info()) + for plugin in self._plugins: + header = "sys: " + plugin._coverage_plugin_name + info = plugin.sys_info() + write_formatted_info(self._debug, header, info) + wrote_any = True + + if wrote_any: + write_formatted_info(self._debug, "end", ()) + + def _should_trace(self, filename, frame): + """Decide whether to trace execution in `filename`. + + Calls `_should_trace_internal`, and returns the FileDisposition. + + """ + disp = self._inorout.should_trace(filename, frame) + if self._debug.should('trace'): + self._debug.write(disposition_debug_msg(disp)) + return disp + + def _check_include_omit_etc(self, filename, frame): + """Check a file name against the include/omit/etc, rules, verbosely. + + Returns a boolean: True if the file should be traced, False if not. + + """ + reason = self._inorout.check_include_omit_etc(filename, frame) + if self._debug.should('trace'): + if not reason: + msg = "Including %r" % (filename,) + else: + msg = "Not including %r: %s" % (filename, reason) + self._debug.write(msg) + + return not reason + + def _warn(self, msg, slug=None, once=False): + """Use `msg` as a warning. + + For warning suppression, use `slug` as the shorthand. + + If `once` is true, only show this warning once (determined by the + slug.) + + """ + if self._no_warn_slugs is None: + self._no_warn_slugs = list(self.config.disable_warnings) + + if slug in self._no_warn_slugs: + # Don't issue the warning + return + + self._warnings.append(msg) + if slug: + msg = "%s (%s)" % (msg, slug) + if self._debug.should('pid'): + msg = "[%d] %s" % (os.getpid(), msg) + sys.stderr.write("Coverage.py warning: %s\n" % msg) + + if once: + self._no_warn_slugs.append(slug) + + def get_option(self, option_name): + """Get an option from the configuration. + + `option_name` is a colon-separated string indicating the section and + option name. For example, the ``branch`` option in the ``[run]`` + section of the config file would be indicated with `"run:branch"`. + + Returns the value of the option. The type depends on the option + selected. + + As a special case, an `option_name` of ``"paths"`` will return an + OrderedDict with the entire ``[paths]`` section value. + + .. versionadded:: 4.0 + + """ + return self.config.get_option(option_name) + + def set_option(self, option_name, value): + """Set an option in the configuration. + + `option_name` is a colon-separated string indicating the section and + option name. For example, the ``branch`` option in the ``[run]`` + section of the config file would be indicated with ``"run:branch"``. + + `value` is the new value for the option. This should be an + appropriate Python value. For example, use True for booleans, not the + string ``"True"``. + + As an example, calling:: + + cov.set_option("run:branch", True) + + has the same effect as this configuration file:: + + [run] + branch = True + + As a special case, an `option_name` of ``"paths"`` will replace the + entire ``[paths]`` section. The value should be an OrderedDict. + + .. versionadded:: 4.0 + + """ + self.config.set_option(option_name, value) + + def load(self): + """Load previously-collected coverage data from the data file.""" + self._init() + if self._collector: + self._collector.reset() + should_skip = self.config.parallel and not os.path.exists(self.config.data_file) + if not should_skip: + self._init_data(suffix=None) + self._post_init() + if not should_skip: + self._data.read() + + def _init_for_start(self): + """Initialization for start()""" + # Construct the collector. + concurrency = self.config.concurrency or () + if "multiprocessing" in concurrency: + if not patch_multiprocessing: + raise CoverageException( # pragma: only jython + "multiprocessing is not supported on this Python" + ) + patch_multiprocessing(rcfile=self.config.config_file) + + dycon = self.config.dynamic_context + if not dycon or dycon == "none": + context_switchers = [] + elif dycon == "test_function": + context_switchers = [should_start_context_test_function] + else: + raise CoverageException( + "Don't understand dynamic_context setting: {!r}".format(dycon) + ) + + context_switchers.extend( + plugin.dynamic_context for plugin in self._plugins.context_switchers + ) + + should_start_context = combine_context_switchers(context_switchers) + + self._collector = Collector( + should_trace=self._should_trace, + check_include=self._check_include_omit_etc, + should_start_context=should_start_context, + file_mapper=self._file_mapper, + timid=self.config.timid, + branch=self.config.branch, + warn=self._warn, + concurrency=concurrency, + ) + + suffix = self._data_suffix_specified + if suffix or self.config.parallel: + if not isinstance(suffix, string_class): + # if data_suffix=True, use .machinename.pid.random + suffix = True + else: + suffix = None + + self._init_data(suffix) + + self._collector.use_data(self._data, self.config.context) + + # Early warning if we aren't going to be able to support plugins. + if self._plugins.file_tracers and not self._collector.supports_plugins: + self._warn( + "Plugin file tracers (%s) aren't supported with %s" % ( + ", ".join( + plugin._coverage_plugin_name + for plugin in self._plugins.file_tracers + ), + self._collector.tracer_name(), + ) + ) + for plugin in self._plugins.file_tracers: + plugin._coverage_enabled = False + + # Create the file classifying substructure. + self._inorout = InOrOut( + warn=self._warn, + debug=(self._debug if self._debug.should('trace') else None), + ) + self._inorout.configure(self.config) + self._inorout.plugins = self._plugins + self._inorout.disp_class = self._collector.file_disposition_class + + # It's useful to write debug info after initing for start. + self._should_write_debug = True + + atexit.register(self._atexit) + + def _init_data(self, suffix): + """Create a data file if we don't have one yet.""" + if self._data is None: + # Create the data file. We do this at construction time so that the + # data file will be written into the directory where the process + # started rather than wherever the process eventually chdir'd to. + ensure_dir_for_file(self.config.data_file) + self._data = CoverageData( + basename=self.config.data_file, + suffix=suffix, + warn=self._warn, + debug=self._debug, + no_disk=self._no_disk, + ) + + def start(self): + """Start measuring code coverage. + + Coverage measurement only occurs in functions called after + :meth:`start` is invoked. Statements in the same scope as + :meth:`start` won't be measured. + + Once you invoke :meth:`start`, you must also call :meth:`stop` + eventually, or your process might not shut down cleanly. + + """ + self._init() + if not self._inited_for_start: + self._inited_for_start = True + self._init_for_start() + self._post_init() + + # Issue warnings for possible problems. + self._inorout.warn_conflicting_settings() + + # See if we think some code that would eventually be measured has + # already been imported. + if self._warn_preimported_source: + self._inorout.warn_already_imported_files() + + if self._auto_load: + self.load() + + self._collector.start() + self._started = True + self._instances.append(self) + + def stop(self): + """Stop measuring code coverage.""" + if self._instances: + if self._instances[-1] is self: + self._instances.pop() + if self._started: + self._collector.stop() + self._started = False + + def _atexit(self): + """Clean up on process shutdown.""" + if self._debug.should("process"): + self._debug.write("atexit: pid: {}, instance: {!r}".format(os.getpid(), self)) + if self._started: + self.stop() + if self._auto_save: + self.save() + + def erase(self): + """Erase previously collected coverage data. + + This removes the in-memory data collected in this session as well as + discarding the data file. + + """ + self._init() + self._post_init() + if self._collector: + self._collector.reset() + self._init_data(suffix=None) + self._data.erase(parallel=self.config.parallel) + self._data = None + self._inited_for_start = False + + def switch_context(self, new_context): + """Switch to a new dynamic context. + + `new_context` is a string to use as the :ref:`dynamic context + ` label for collected data. If a :ref:`static + context ` is in use, the static and dynamic context + labels will be joined together with a pipe character. + + Coverage collection must be started already. + + .. versionadded:: 5.0 + + """ + if not self._started: # pragma: part started + raise CoverageException( + "Cannot switch context, coverage is not started" + ) + + if self._collector.should_start_context: + self._warn("Conflicting dynamic contexts", slug="dynamic-conflict", once=True) + + self._collector.switch_context(new_context) + + def clear_exclude(self, which='exclude'): + """Clear the exclude list.""" + self._init() + setattr(self.config, which + "_list", []) + self._exclude_regex_stale() + + def exclude(self, regex, which='exclude'): + """Exclude source lines from execution consideration. + + A number of lists of regular expressions are maintained. Each list + selects lines that are treated differently during reporting. + + `which` determines which list is modified. The "exclude" list selects + lines that are not considered executable at all. The "partial" list + indicates lines with branches that are not taken. + + `regex` is a regular expression. The regex is added to the specified + list. If any of the regexes in the list is found in a line, the line + is marked for special treatment during reporting. + + """ + self._init() + excl_list = getattr(self.config, which + "_list") + excl_list.append(regex) + self._exclude_regex_stale() + + def _exclude_regex_stale(self): + """Drop all the compiled exclusion regexes, a list was modified.""" + self._exclude_re.clear() + + def _exclude_regex(self, which): + """Return a compiled regex for the given exclusion list.""" + if which not in self._exclude_re: + excl_list = getattr(self.config, which + "_list") + self._exclude_re[which] = join_regex(excl_list) + return self._exclude_re[which] + + def get_exclude_list(self, which='exclude'): + """Return a list of excluded regex patterns. + + `which` indicates which list is desired. See :meth:`exclude` for the + lists that are available, and their meaning. + + """ + self._init() + return getattr(self.config, which + "_list") + + def save(self): + """Save the collected coverage data to the data file.""" + data = self.get_data() + data.write() + + def combine(self, data_paths=None, strict=False, keep=False): + """Combine together a number of similarly-named coverage data files. + + All coverage data files whose name starts with `data_file` (from the + coverage() constructor) will be read, and combined together into the + current measurements. + + `data_paths` is a list of files or directories from which data should + be combined. If no list is passed, then the data files from the + directory indicated by the current data file (probably the current + directory) will be combined. + + If `strict` is true, then it is an error to attempt to combine when + there are no data files to combine. + + If `keep` is true, then original input data files won't be deleted. + + .. versionadded:: 4.0 + The `data_paths` parameter. + + .. versionadded:: 4.3 + The `strict` parameter. + + .. versionadded: 5.5 + The `keep` parameter. + """ + self._init() + self._init_data(suffix=None) + self._post_init() + self.get_data() + + aliases = None + if self.config.paths: + aliases = PathAliases() + for paths in self.config.paths.values(): + result = paths[0] + for pattern in paths[1:]: + aliases.add(pattern, result) + + combine_parallel_data( + self._data, + aliases=aliases, + data_paths=data_paths, + strict=strict, + keep=keep, + ) + + def get_data(self): + """Get the collected data. + + Also warn about various problems collecting data. + + Returns a :class:`coverage.CoverageData`, the collected coverage data. + + .. versionadded:: 4.0 + + """ + self._init() + self._init_data(suffix=None) + self._post_init() + + for plugin in self._plugins: + if not plugin._coverage_enabled: + self._collector.plugin_was_disabled(plugin) + + if self._collector and self._collector.flush_data(): + self._post_save_work() + + return self._data + + def _post_save_work(self): + """After saving data, look for warnings, post-work, etc. + + Warn about things that should have happened but didn't. + Look for unexecuted files. + + """ + # If there are still entries in the source_pkgs_unmatched list, + # then we never encountered those packages. + if self._warn_unimported_source: + self._inorout.warn_unimported_source() + + # Find out if we got any data. + if not self._data and self._warn_no_data: + self._warn("No data was collected.", slug="no-data-collected") + + # Touch all the files that could have executed, so that we can + # mark completely unexecuted files as 0% covered. + if self._data is not None: + file_paths = collections.defaultdict(list) + for file_path, plugin_name in self._inorout.find_possibly_unexecuted_files(): + file_path = self._file_mapper(file_path) + file_paths[plugin_name].append(file_path) + for plugin_name, paths in file_paths.items(): + self._data.touch_files(paths, plugin_name) + + if self.config.note: + self._warn("The '[run] note' setting is no longer supported.") + + # Backward compatibility with version 1. + def analysis(self, morf): + """Like `analysis2` but doesn't return excluded line numbers.""" + f, s, _, m, mf = self.analysis2(morf) + return f, s, m, mf + + def analysis2(self, morf): + """Analyze a module. + + `morf` is a module or a file name. It will be analyzed to determine + its coverage statistics. The return value is a 5-tuple: + + * The file name for the module. + * A list of line numbers of executable statements. + * A list of line numbers of excluded statements. + * A list of line numbers of statements not run (missing from + execution). + * A readable formatted string of the missing line numbers. + + The analysis uses the source file itself and the current measured + coverage data. + + """ + analysis = self._analyze(morf) + return ( + analysis.filename, + sorted(analysis.statements), + sorted(analysis.excluded), + sorted(analysis.missing), + analysis.missing_formatted(), + ) + + def _analyze(self, it): + """Analyze a single morf or code unit. + + Returns an `Analysis` object. + + """ + # All reporting comes through here, so do reporting initialization. + self._init() + Numbers.set_precision(self.config.precision) + self._post_init() + + data = self.get_data() + if not isinstance(it, FileReporter): + it = self._get_file_reporter(it) + + return Analysis(data, it, self._file_mapper) + + def _get_file_reporter(self, morf): + """Get a FileReporter for a module or file name.""" + plugin = None + file_reporter = "python" + + if isinstance(morf, string_class): + mapped_morf = self._file_mapper(morf) + plugin_name = self._data.file_tracer(mapped_morf) + if plugin_name: + plugin = self._plugins.get(plugin_name) + + if plugin: + file_reporter = plugin.file_reporter(mapped_morf) + if file_reporter is None: + raise CoverageException( + "Plugin %r did not provide a file reporter for %r." % ( + plugin._coverage_plugin_name, morf + ) + ) + + if file_reporter == "python": + file_reporter = PythonFileReporter(morf, self) + + return file_reporter + + def _get_file_reporters(self, morfs=None): + """Get a list of FileReporters for a list of modules or file names. + + For each module or file name in `morfs`, find a FileReporter. Return + the list of FileReporters. + + If `morfs` is a single module or file name, this returns a list of one + FileReporter. If `morfs` is empty or None, then the list of all files + measured is used to find the FileReporters. + + """ + if not morfs: + morfs = self._data.measured_files() + + # Be sure we have a collection. + if not isinstance(morfs, (list, tuple, set)): + morfs = [morfs] + + file_reporters = [self._get_file_reporter(morf) for morf in morfs] + return file_reporters + + def report( + self, morfs=None, show_missing=None, ignore_errors=None, + file=None, omit=None, include=None, skip_covered=None, + contexts=None, skip_empty=None, precision=None, sort=None + ): + """Write a textual summary report to `file`. + + Each module in `morfs` is listed, with counts of statements, executed + statements, missing statements, and a list of lines missed. + + If `show_missing` is true, then details of which lines or branches are + missing will be included in the report. If `ignore_errors` is true, + then a failure while reporting a single file will not stop the entire + report. + + `file` is a file-like object, suitable for writing. + + `include` is a list of file name patterns. Files that match will be + included in the report. Files matching `omit` will not be included in + the report. + + If `skip_covered` is true, don't report on files with 100% coverage. + + If `skip_empty` is true, don't report on empty files (those that have + no statements). + + `contexts` is a list of regular expressions. Only data from + :ref:`dynamic contexts ` that match one of those + expressions (using :func:`re.search `) will be + included in the report. + + `precision` is the number of digits to display after the decimal + point for percentages. + + All of the arguments default to the settings read from the + :ref:`configuration file `. + + Returns a float, the total percentage covered. + + .. versionadded:: 4.0 + The `skip_covered` parameter. + + .. versionadded:: 5.0 + The `contexts` and `skip_empty` parameters. + + .. versionadded:: 5.2 + The `precision` parameter. + + """ + with override_config( + self, + ignore_errors=ignore_errors, report_omit=omit, report_include=include, + show_missing=show_missing, skip_covered=skip_covered, + report_contexts=contexts, skip_empty=skip_empty, precision=precision, + sort=sort + ): + reporter = SummaryReporter(self) + return reporter.report(morfs, outfile=file) + + def annotate( + self, morfs=None, directory=None, ignore_errors=None, + omit=None, include=None, contexts=None, + ): + """Annotate a list of modules. + + Each module in `morfs` is annotated. The source is written to a new + file, named with a ",cover" suffix, with each line prefixed with a + marker to indicate the coverage of the line. Covered lines have ">", + excluded lines have "-", and missing lines have "!". + + See :meth:`report` for other arguments. + + """ + with override_config(self, + ignore_errors=ignore_errors, report_omit=omit, + report_include=include, report_contexts=contexts, + ): + reporter = AnnotateReporter(self) + reporter.report(morfs, directory=directory) + + def html_report( + self, morfs=None, directory=None, ignore_errors=None, + omit=None, include=None, extra_css=None, title=None, + skip_covered=None, show_contexts=None, contexts=None, + skip_empty=None, precision=None, + ): + """Generate an HTML report. + + The HTML is written to `directory`. The file "index.html" is the + overview starting point, with links to more detailed pages for + individual modules. + + `extra_css` is a path to a file of other CSS to apply on the page. + It will be copied into the HTML directory. + + `title` is a text string (not HTML) to use as the title of the HTML + report. + + See :meth:`report` for other arguments. + + Returns a float, the total percentage covered. + + .. note:: + The HTML report files are generated incrementally based on the + source files and coverage results. If you modify the report files, + the changes will not be considered. You should be careful about + changing the files in the report folder. + + """ + with override_config(self, + ignore_errors=ignore_errors, report_omit=omit, report_include=include, + html_dir=directory, extra_css=extra_css, html_title=title, + html_skip_covered=skip_covered, show_contexts=show_contexts, report_contexts=contexts, + html_skip_empty=skip_empty, precision=precision, + ): + reporter = HtmlReporter(self) + return reporter.report(morfs) + + def xml_report( + self, morfs=None, outfile=None, ignore_errors=None, + omit=None, include=None, contexts=None, skip_empty=None, + ): + """Generate an XML report of coverage results. + + The report is compatible with Cobertura reports. + + Each module in `morfs` is included in the report. `outfile` is the + path to write the file to, "-" will write to stdout. + + See :meth:`report` for other arguments. + + Returns a float, the total percentage covered. + + """ + with override_config(self, + ignore_errors=ignore_errors, report_omit=omit, report_include=include, + xml_output=outfile, report_contexts=contexts, skip_empty=skip_empty, + ): + return render_report(self.config.xml_output, XmlReporter(self), morfs) + + def json_report( + self, morfs=None, outfile=None, ignore_errors=None, + omit=None, include=None, contexts=None, pretty_print=None, + show_contexts=None + ): + """Generate a JSON report of coverage results. + + Each module in `morfs` is included in the report. `outfile` is the + path to write the file to, "-" will write to stdout. + + See :meth:`report` for other arguments. + + Returns a float, the total percentage covered. + + .. versionadded:: 5.0 + + """ + with override_config(self, + ignore_errors=ignore_errors, report_omit=omit, report_include=include, + json_output=outfile, report_contexts=contexts, json_pretty_print=pretty_print, + json_show_contexts=show_contexts + ): + return render_report(self.config.json_output, JsonReporter(self), morfs) + + def sys_info(self): + """Return a list of (key, value) pairs showing internal information.""" + + import coverage as covmod + + self._init() + self._post_init() + + def plugin_info(plugins): + """Make an entry for the sys_info from a list of plug-ins.""" + entries = [] + for plugin in plugins: + entry = plugin._coverage_plugin_name + if not plugin._coverage_enabled: + entry += " (disabled)" + entries.append(entry) + return entries + + info = [ + ('version', covmod.__version__), + ('coverage', covmod.__file__), + ('tracer', self._collector.tracer_name() if self._collector else "-none-"), + ('CTracer', 'available' if CTracer else "unavailable"), + ('plugins.file_tracers', plugin_info(self._plugins.file_tracers)), + ('plugins.configurers', plugin_info(self._plugins.configurers)), + ('plugins.context_switchers', plugin_info(self._plugins.context_switchers)), + ('configs_attempted', self.config.attempted_config_files), + ('configs_read', self.config.config_files_read), + ('config_file', self.config.config_file), + ('config_contents', + repr(self.config._config_contents) + if self.config._config_contents + else '-none-' + ), + ('data_file', self._data.data_filename() if self._data is not None else "-none-"), + ('python', sys.version.replace('\n', '')), + ('platform', platform.platform()), + ('implementation', platform.python_implementation()), + ('executable', sys.executable), + ('def_encoding', sys.getdefaultencoding()), + ('fs_encoding', sys.getfilesystemencoding()), + ('pid', os.getpid()), + ('cwd', os.getcwd()), + ('path', sys.path), + ('environment', sorted( + ("%s = %s" % (k, v)) + for k, v in iitems(os.environ) + if any(slug in k for slug in ("COV", "PY")) + )), + ('command_line', " ".join(getattr(sys, 'argv', ['-none-']))), + ] + + if self._inorout: + info.extend(self._inorout.sys_info()) + + info.extend(CoverageData.sys_info()) + + return info + + +# Mega debugging... +# $set_env.py: COVERAGE_DEBUG_CALLS - Lots and lots of output about calls to Coverage. +if int(os.environ.get("COVERAGE_DEBUG_CALLS", 0)): # pragma: debugging + from coverage.debug import decorate_methods, show_calls + + Coverage = decorate_methods(show_calls(show_args=True), butnot=['get_data'])(Coverage) + + +def process_startup(): + """Call this at Python start-up to perhaps measure coverage. + + If the environment variable COVERAGE_PROCESS_START is defined, coverage + measurement is started. The value of the variable is the config file + to use. + + There are two ways to configure your Python installation to invoke this + function when Python starts: + + #. Create or append to sitecustomize.py to add these lines:: + + import coverage + coverage.process_startup() + + #. Create a .pth file in your Python installation containing:: + + import coverage; coverage.process_startup() + + Returns the :class:`Coverage` instance that was started, or None if it was + not started by this call. + + """ + cps = os.environ.get("COVERAGE_PROCESS_START") + if not cps: + # No request for coverage, nothing to do. + return None + + # This function can be called more than once in a process. This happens + # because some virtualenv configurations make the same directory visible + # twice in sys.path. This means that the .pth file will be found twice, + # and executed twice, executing this function twice. We set a global + # flag (an attribute on this function) to indicate that coverage.py has + # already been started, so we can avoid doing it twice. + # + # https://github.com/nedbat/coveragepy/issues/340 has more details. + + if hasattr(process_startup, "coverage"): + # We've annotated this function before, so we must have already + # started coverage.py in this process. Nothing to do. + return None + + cov = Coverage(config_file=cps) + process_startup.coverage = cov + cov._warn_no_data = False + cov._warn_unimported_source = False + cov._warn_preimported_source = False + cov._auto_save = True + cov.start() + + return cov + + +def _prevent_sub_process_measurement(): + """Stop any subprocess auto-measurement from writing data.""" + auto_created_coverage = getattr(process_startup, "coverage", None) + if auto_created_coverage is not None: + auto_created_coverage._auto_save = False diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/data.py b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/data.py new file mode 100644 index 000000000..5dd1dfe3f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/data.py @@ -0,0 +1,125 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +"""Coverage data for coverage.py. + +This file had the 4.x JSON data support, which is now gone. This file still +has storage-agnostic helpers, and is kept to avoid changing too many imports. +CoverageData is now defined in sqldata.py, and imported here to keep the +imports working. + +""" + +import glob +import os.path + +from coverage.misc import CoverageException, file_be_gone +from coverage.sqldata import CoverageData + + +def line_counts(data, fullpath=False): + """Return a dict summarizing the line coverage data. + + Keys are based on the file names, and values are the number of executed + lines. If `fullpath` is true, then the keys are the full pathnames of + the files, otherwise they are the basenames of the files. + + Returns a dict mapping file names to counts of lines. + + """ + summ = {} + if fullpath: + filename_fn = lambda f: f + else: + filename_fn = os.path.basename + for filename in data.measured_files(): + summ[filename_fn(filename)] = len(data.lines(filename)) + return summ + + +def add_data_to_hash(data, filename, hasher): + """Contribute `filename`'s data to the `hasher`. + + `hasher` is a `coverage.misc.Hasher` instance to be updated with + the file's data. It should only get the results data, not the run + data. + + """ + if data.has_arcs(): + hasher.update(sorted(data.arcs(filename) or [])) + else: + hasher.update(sorted(data.lines(filename) or [])) + hasher.update(data.file_tracer(filename)) + + +def combine_parallel_data(data, aliases=None, data_paths=None, strict=False, keep=False): + """Combine a number of data files together. + + Treat `data.filename` as a file prefix, and combine the data from all + of the data files starting with that prefix plus a dot. + + If `aliases` is provided, it's a `PathAliases` object that is used to + re-map paths to match the local machine's. + + If `data_paths` is provided, it is a list of directories or files to + combine. Directories are searched for files that start with + `data.filename` plus dot as a prefix, and those files are combined. + + If `data_paths` is not provided, then the directory portion of + `data.filename` is used as the directory to search for data files. + + Unless `keep` is True every data file found and combined is then deleted from disk. If a file + cannot be read, a warning will be issued, and the file will not be + deleted. + + If `strict` is true, and no files are found to combine, an error is + raised. + + """ + # Because of the os.path.abspath in the constructor, data_dir will + # never be an empty string. + data_dir, local = os.path.split(data.base_filename()) + localdot = local + '.*' + + data_paths = data_paths or [data_dir] + files_to_combine = [] + for p in data_paths: + if os.path.isfile(p): + files_to_combine.append(os.path.abspath(p)) + elif os.path.isdir(p): + pattern = os.path.join(os.path.abspath(p), localdot) + files_to_combine.extend(glob.glob(pattern)) + else: + raise CoverageException("Couldn't combine from non-existent path '%s'" % (p,)) + + if strict and not files_to_combine: + raise CoverageException("No data to combine") + + files_combined = 0 + for f in files_to_combine: + if f == data.data_filename(): + # Sometimes we are combining into a file which is one of the + # parallel files. Skip that file. + if data._debug.should('dataio'): + data._debug.write("Skipping combining ourself: %r" % (f,)) + continue + if data._debug.should('dataio'): + data._debug.write("Combining data file %r" % (f,)) + try: + new_data = CoverageData(f, debug=data._debug) + new_data.read() + except CoverageException as exc: + if data._warn: + # The CoverageException has the file name in it, so just + # use the message as the warning. + data._warn(str(exc)) + else: + data.update(new_data, aliases=aliases) + files_combined += 1 + if not keep: + if data._debug.should('dataio'): + data._debug.write("Deleting combined data file %r" % (f,)) + file_be_gone(f) + + if strict and not files_combined: + raise CoverageException("No usable data files") diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/debug.py b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/debug.py new file mode 100644 index 000000000..194f16f50 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/debug.py @@ -0,0 +1,406 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +"""Control of and utilities for debugging.""" + +import contextlib +import functools +import inspect +import itertools +import os +import pprint +import sys +try: + import _thread +except ImportError: + import thread as _thread + +from coverage.backward import reprlib, StringIO +from coverage.misc import isolate_module + +os = isolate_module(os) + + +# When debugging, it can be helpful to force some options, especially when +# debugging the configuration mechanisms you usually use to control debugging! +# This is a list of forced debugging options. +FORCED_DEBUG = [] +FORCED_DEBUG_FILE = None + + +class DebugControl(object): + """Control and output for debugging.""" + + show_repr_attr = False # For SimpleReprMixin + + def __init__(self, options, output): + """Configure the options and output file for debugging.""" + self.options = list(options) + FORCED_DEBUG + self.suppress_callers = False + + filters = [] + if self.should('pid'): + filters.append(add_pid_and_tid) + self.output = DebugOutputFile.get_one( + output, + show_process=self.should('process'), + filters=filters, + ) + self.raw_output = self.output.outfile + + def __repr__(self): + return "" % (self.options, self.raw_output) + + def should(self, option): + """Decide whether to output debug information in category `option`.""" + if option == "callers" and self.suppress_callers: + return False + return (option in self.options) + + @contextlib.contextmanager + def without_callers(self): + """A context manager to prevent call stacks from being logged.""" + old = self.suppress_callers + self.suppress_callers = True + try: + yield + finally: + self.suppress_callers = old + + def write(self, msg): + """Write a line of debug output. + + `msg` is the line to write. A newline will be appended. + + """ + self.output.write(msg+"\n") + if self.should('self'): + caller_self = inspect.stack()[1][0].f_locals.get('self') + if caller_self is not None: + self.output.write("self: {!r}\n".format(caller_self)) + if self.should('callers'): + dump_stack_frames(out=self.output, skip=1) + self.output.flush() + + +class DebugControlString(DebugControl): + """A `DebugControl` that writes to a StringIO, for testing.""" + def __init__(self, options): + super(DebugControlString, self).__init__(options, StringIO()) + + def get_output(self): + """Get the output text from the `DebugControl`.""" + return self.raw_output.getvalue() + + +class NoDebugging(object): + """A replacement for DebugControl that will never try to do anything.""" + def should(self, option): # pylint: disable=unused-argument + """Should we write debug messages? Never.""" + return False + + +def info_header(label): + """Make a nice header string.""" + return "--{:-<60s}".format(" "+label+" ") + + +def info_formatter(info): + """Produce a sequence of formatted lines from info. + + `info` is a sequence of pairs (label, data). The produced lines are + nicely formatted, ready to print. + + """ + info = list(info) + if not info: + return + label_len = 30 + assert all(len(l) < label_len for l, _ in info) + for label, data in info: + if data == []: + data = "-none-" + if isinstance(data, (list, set, tuple)): + prefix = "%*s:" % (label_len, label) + for e in data: + yield "%*s %s" % (label_len+1, prefix, e) + prefix = "" + else: + yield "%*s: %s" % (label_len, label, data) + + +def write_formatted_info(writer, header, info): + """Write a sequence of (label,data) pairs nicely.""" + writer.write(info_header(header)) + for line in info_formatter(info): + writer.write(" %s" % line) + + +def short_stack(limit=None, skip=0): + """Return a string summarizing the call stack. + + The string is multi-line, with one line per stack frame. Each line shows + the function name, the file name, and the line number: + + ... + start_import_stop : /Users/ned/coverage/trunk/tests/coveragetest.py @95 + import_local_file : /Users/ned/coverage/trunk/tests/coveragetest.py @81 + import_local_file : /Users/ned/coverage/trunk/coverage/backward.py @159 + ... + + `limit` is the number of frames to include, defaulting to all of them. + + `skip` is the number of frames to skip, so that debugging functions can + call this and not be included in the result. + + """ + stack = inspect.stack()[limit:skip:-1] + return "\n".join("%30s : %s:%d" % (t[3], t[1], t[2]) for t in stack) + + +def dump_stack_frames(limit=None, out=None, skip=0): + """Print a summary of the stack to stdout, or someplace else.""" + out = out or sys.stdout + out.write(short_stack(limit=limit, skip=skip+1)) + out.write("\n") + + +def clipped_repr(text, numchars=50): + """`repr(text)`, but limited to `numchars`.""" + r = reprlib.Repr() + r.maxstring = numchars + return r.repr(text) + + +def short_id(id64): + """Given a 64-bit id, make a shorter 16-bit one.""" + id16 = 0 + for offset in range(0, 64, 16): + id16 ^= id64 >> offset + return id16 & 0xFFFF + + +def add_pid_and_tid(text): + """A filter to add pid and tid to debug messages.""" + # Thread ids are useful, but too long. Make a shorter one. + tid = "{:04x}".format(short_id(_thread.get_ident())) + text = "{:5d}.{}: {}".format(os.getpid(), tid, text) + return text + + +class SimpleReprMixin(object): + """A mixin implementing a simple __repr__.""" + simple_repr_ignore = ['simple_repr_ignore', '$coverage.object_id'] + + def __repr__(self): + show_attrs = ( + (k, v) for k, v in self.__dict__.items() + if getattr(v, "show_repr_attr", True) + and not callable(v) + and k not in self.simple_repr_ignore + ) + return "<{klass} @0x{id:x} {attrs}>".format( + klass=self.__class__.__name__, + id=id(self), + attrs=" ".join("{}={!r}".format(k, v) for k, v in show_attrs), + ) + + +def simplify(v): # pragma: debugging + """Turn things which are nearly dict/list/etc into dict/list/etc.""" + if isinstance(v, dict): + return {k:simplify(vv) for k, vv in v.items()} + elif isinstance(v, (list, tuple)): + return type(v)(simplify(vv) for vv in v) + elif hasattr(v, "__dict__"): + return simplify({'.'+k: v for k, v in v.__dict__.items()}) + else: + return v + + +def pp(v): # pragma: debugging + """Debug helper to pretty-print data, including SimpleNamespace objects.""" + # Might not be needed in 3.9+ + pprint.pprint(simplify(v)) + + +def filter_text(text, filters): + """Run `text` through a series of filters. + + `filters` is a list of functions. Each takes a string and returns a + string. Each is run in turn. + + Returns: the final string that results after all of the filters have + run. + + """ + clean_text = text.rstrip() + ending = text[len(clean_text):] + text = clean_text + for fn in filters: + lines = [] + for line in text.splitlines(): + lines.extend(fn(line).splitlines()) + text = "\n".join(lines) + return text + ending + + +class CwdTracker(object): # pragma: debugging + """A class to add cwd info to debug messages.""" + def __init__(self): + self.cwd = None + + def filter(self, text): + """Add a cwd message for each new cwd.""" + cwd = os.getcwd() + if cwd != self.cwd: + text = "cwd is now {!r}\n".format(cwd) + text + self.cwd = cwd + return text + + +class DebugOutputFile(object): # pragma: debugging + """A file-like object that includes pid and cwd information.""" + def __init__(self, outfile, show_process, filters): + self.outfile = outfile + self.show_process = show_process + self.filters = list(filters) + + if self.show_process: + self.filters.insert(0, CwdTracker().filter) + self.write("New process: executable: %r\n" % (sys.executable,)) + self.write("New process: cmd: %r\n" % (getattr(sys, 'argv', None),)) + if hasattr(os, 'getppid'): + self.write("New process: pid: %r, parent pid: %r\n" % (os.getpid(), os.getppid())) + + SYS_MOD_NAME = '$coverage.debug.DebugOutputFile.the_one' + + @classmethod + def get_one(cls, fileobj=None, show_process=True, filters=(), interim=False): + """Get a DebugOutputFile. + + If `fileobj` is provided, then a new DebugOutputFile is made with it. + + If `fileobj` isn't provided, then a file is chosen + (COVERAGE_DEBUG_FILE, or stderr), and a process-wide singleton + DebugOutputFile is made. + + `show_process` controls whether the debug file adds process-level + information, and filters is a list of other message filters to apply. + + `filters` are the text filters to apply to the stream to annotate with + pids, etc. + + If `interim` is true, then a future `get_one` can replace this one. + + """ + if fileobj is not None: + # Make DebugOutputFile around the fileobj passed. + return cls(fileobj, show_process, filters) + + # Because of the way igor.py deletes and re-imports modules, + # this class can be defined more than once. But we really want + # a process-wide singleton. So stash it in sys.modules instead of + # on a class attribute. Yes, this is aggressively gross. + the_one, is_interim = sys.modules.get(cls.SYS_MOD_NAME, (None, True)) + if the_one is None or is_interim: + if fileobj is None: + debug_file_name = os.environ.get("COVERAGE_DEBUG_FILE", FORCED_DEBUG_FILE) + if debug_file_name: + fileobj = open(debug_file_name, "a") + else: + fileobj = sys.stderr + the_one = cls(fileobj, show_process, filters) + sys.modules[cls.SYS_MOD_NAME] = (the_one, interim) + return the_one + + def write(self, text): + """Just like file.write, but filter through all our filters.""" + self.outfile.write(filter_text(text, self.filters)) + self.outfile.flush() + + def flush(self): + """Flush our file.""" + self.outfile.flush() + + +def log(msg, stack=False): # pragma: debugging + """Write a log message as forcefully as possible.""" + out = DebugOutputFile.get_one(interim=True) + out.write(msg+"\n") + if stack: + dump_stack_frames(out=out, skip=1) + + +def decorate_methods(decorator, butnot=(), private=False): # pragma: debugging + """A class decorator to apply a decorator to methods.""" + def _decorator(cls): + for name, meth in inspect.getmembers(cls, inspect.isroutine): + if name not in cls.__dict__: + continue + if name != "__init__": + if not private and name.startswith("_"): + continue + if name in butnot: + continue + setattr(cls, name, decorator(meth)) + return cls + return _decorator + + +def break_in_pudb(func): # pragma: debugging + """A function decorator to stop in the debugger for each call.""" + @functools.wraps(func) + def _wrapper(*args, **kwargs): + import pudb + sys.stdout = sys.__stdout__ + pudb.set_trace() + return func(*args, **kwargs) + return _wrapper + + +OBJ_IDS = itertools.count() +CALLS = itertools.count() +OBJ_ID_ATTR = "$coverage.object_id" + +def show_calls(show_args=True, show_stack=False, show_return=False): # pragma: debugging + """A method decorator to debug-log each call to the function.""" + def _decorator(func): + @functools.wraps(func) + def _wrapper(self, *args, **kwargs): + oid = getattr(self, OBJ_ID_ATTR, None) + if oid is None: + oid = "{:08d} {:04d}".format(os.getpid(), next(OBJ_IDS)) + setattr(self, OBJ_ID_ATTR, oid) + extra = "" + if show_args: + eargs = ", ".join(map(repr, args)) + ekwargs = ", ".join("{}={!r}".format(*item) for item in kwargs.items()) + extra += "(" + extra += eargs + if eargs and ekwargs: + extra += ", " + extra += ekwargs + extra += ")" + if show_stack: + extra += " @ " + extra += "; ".join(_clean_stack_line(l) for l in short_stack().splitlines()) + callid = next(CALLS) + msg = "{} {:04d} {}{}\n".format(oid, callid, func.__name__, extra) + DebugOutputFile.get_one(interim=True).write(msg) + ret = func(self, *args, **kwargs) + if show_return: + msg = "{} {:04d} {} return {!r}\n".format(oid, callid, func.__name__, ret) + DebugOutputFile.get_one(interim=True).write(msg) + return ret + return _wrapper + return _decorator + + +def _clean_stack_line(s): # pragma: debugging + """Simplify some paths in a stack trace, for compactness.""" + s = s.strip() + s = s.replace(os.path.dirname(__file__) + '/', '') + s = s.replace(os.path.dirname(os.__file__) + '/', '') + s = s.replace(sys.prefix + '/', '') + return s diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/disposition.py b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/disposition.py new file mode 100644 index 000000000..9b9a997d8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/disposition.py @@ -0,0 +1,37 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +"""Simple value objects for tracking what to do with files.""" + + +class FileDisposition(object): + """A simple value type for recording what to do with a file.""" + pass + + +# FileDisposition "methods": FileDisposition is a pure value object, so it can +# be implemented in either C or Python. Acting on them is done with these +# functions. + +def disposition_init(cls, original_filename): + """Construct and initialize a new FileDisposition object.""" + disp = cls() + disp.original_filename = original_filename + disp.canonical_filename = original_filename + disp.source_filename = None + disp.trace = False + disp.reason = "" + disp.file_tracer = None + disp.has_dynamic_filename = False + return disp + + +def disposition_debug_msg(disp): + """Make a nice debug message of what the FileDisposition is doing.""" + if disp.trace: + msg = "Tracing %r" % (disp.original_filename,) + if disp.file_tracer: + msg += ": will be traced by %r" % disp.file_tracer + else: + msg = "Not tracing %r: %s" % (disp.original_filename, disp.reason) + return msg diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/env.py b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/env.py new file mode 100644 index 000000000..ea78a5be8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/env.py @@ -0,0 +1,130 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +"""Determine facts about the environment.""" + +import os +import platform +import sys + +# Operating systems. +WINDOWS = sys.platform == "win32" +LINUX = sys.platform.startswith("linux") + +# Python implementations. +CPYTHON = (platform.python_implementation() == "CPython") +PYPY = (platform.python_implementation() == "PyPy") +JYTHON = (platform.python_implementation() == "Jython") +IRONPYTHON = (platform.python_implementation() == "IronPython") + +# Python versions. We amend version_info with one more value, a zero if an +# official version, or 1 if built from source beyond an official version. +PYVERSION = sys.version_info + (int(platform.python_version()[-1] == "+"),) +PY2 = PYVERSION < (3, 0) +PY3 = PYVERSION >= (3, 0) + +if PYPY: + PYPYVERSION = sys.pypy_version_info + +PYPY2 = PYPY and PY2 +PYPY3 = PYPY and PY3 + +# Python behavior. +class PYBEHAVIOR(object): + """Flags indicating this Python's behavior.""" + + pep626 = CPYTHON and (PYVERSION > (3, 10, 0, 'alpha', 4)) + + # Is "if __debug__" optimized away? + if PYPY3: + optimize_if_debug = True + elif PYPY2: + optimize_if_debug = False + else: + optimize_if_debug = not pep626 + + # Is "if not __debug__" optimized away? + optimize_if_not_debug = (not PYPY) and (PYVERSION >= (3, 7, 0, 'alpha', 4)) + if pep626: + optimize_if_not_debug = False + if PYPY3: + optimize_if_not_debug = True + + # Is "if not __debug__" optimized away even better? + optimize_if_not_debug2 = (not PYPY) and (PYVERSION >= (3, 8, 0, 'beta', 1)) + if pep626: + optimize_if_not_debug2 = False + + # Do we have yield-from? + yield_from = (PYVERSION >= (3, 3)) + + # Do we have PEP 420 namespace packages? + namespaces_pep420 = (PYVERSION >= (3, 3)) + + # Do .pyc files have the source file size recorded in them? + size_in_pyc = (PYVERSION >= (3, 3)) + + # Do we have async and await syntax? + async_syntax = (PYVERSION >= (3, 5)) + + # PEP 448 defined additional unpacking generalizations + unpackings_pep448 = (PYVERSION >= (3, 5)) + + # Can co_lnotab have negative deltas? + negative_lnotab = (PYVERSION >= (3, 6)) and not (PYPY and PYPYVERSION < (7, 2)) + + # Do .pyc files conform to PEP 552? Hash-based pyc's. + hashed_pyc_pep552 = (PYVERSION >= (3, 7, 0, 'alpha', 4)) + + # Python 3.7.0b3 changed the behavior of the sys.path[0] entry for -m. It + # used to be an empty string (meaning the current directory). It changed + # to be the actual path to the current directory, so that os.chdir wouldn't + # affect the outcome. + actual_syspath0_dash_m = CPYTHON and (PYVERSION >= (3, 7, 0, 'beta', 3)) + + # 3.7 changed how functions with only docstrings are numbered. + docstring_only_function = (not PYPY) and ((3, 7, 0, 'beta', 5) <= PYVERSION <= (3, 10)) + + # When a break/continue/return statement in a try block jumps to a finally + # block, does the finally block do the break/continue/return (pre-3.8), or + # does the finally jump back to the break/continue/return (3.8) to do the + # work? + finally_jumps_back = ((3, 8) <= PYVERSION < (3, 10)) + + # When a function is decorated, does the trace function get called for the + # @-line and also the def-line (new behavior in 3.8)? Or just the @-line + # (old behavior)? + trace_decorated_def = (PYVERSION >= (3, 8)) + + # Are while-true loops optimized into absolute jumps with no loop setup? + nix_while_true = (PYVERSION >= (3, 8)) + + # Python 3.9a1 made sys.argv[0] and other reported files absolute paths. + report_absolute_files = (PYVERSION >= (3, 9)) + + # Lines after break/continue/return/raise are no longer compiled into the + # bytecode. They used to be marked as missing, now they aren't executable. + omit_after_jump = pep626 + + # PyPy has always omitted statements after return. + omit_after_return = omit_after_jump or PYPY + + # Modules used to have firstlineno equal to the line number of the first + # real line of code. Now they always start at 1. + module_firstline_1 = pep626 + + # Are "if 0:" lines (and similar) kept in the compiled code? + keep_constant_test = pep626 + +# Coverage.py specifics. + +# Are we using the C-implemented trace function? +C_TRACER = os.getenv('COVERAGE_TEST_TRACER', 'c') == 'c' + +# Are we coverage-measuring ourselves? +METACOV = os.getenv('COVERAGE_COVERAGE', '') != '' + +# Are we running our test suite? +# Even when running tests, you can use COVERAGE_TESTING=0 to disable the +# test-specific behavior like contracts. +TESTING = os.getenv('COVERAGE_TESTING', '') == 'True' diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/execfile.py b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/execfile.py new file mode 100644 index 000000000..29409d517 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/execfile.py @@ -0,0 +1,362 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +"""Execute files of Python code.""" + +import inspect +import marshal +import os +import struct +import sys +import types + +from coverage import env +from coverage.backward import BUILTINS +from coverage.backward import PYC_MAGIC_NUMBER, imp, importlib_util_find_spec +from coverage.files import canonical_filename, python_reported_file +from coverage.misc import CoverageException, ExceptionDuringRun, NoCode, NoSource, isolate_module +from coverage.phystokens import compile_unicode +from coverage.python import get_python_source + +os = isolate_module(os) + + +class DummyLoader(object): + """A shim for the pep302 __loader__, emulating pkgutil.ImpLoader. + + Currently only implements the .fullname attribute + """ + def __init__(self, fullname, *_args): + self.fullname = fullname + + +if importlib_util_find_spec: + def find_module(modulename): + """Find the module named `modulename`. + + Returns the file path of the module, the name of the enclosing + package, and the spec. + """ + try: + spec = importlib_util_find_spec(modulename) + except ImportError as err: + raise NoSource(str(err)) + if not spec: + raise NoSource("No module named %r" % (modulename,)) + pathname = spec.origin + packagename = spec.name + if spec.submodule_search_locations: + mod_main = modulename + ".__main__" + spec = importlib_util_find_spec(mod_main) + if not spec: + raise NoSource( + "No module named %s; " + "%r is a package and cannot be directly executed" + % (mod_main, modulename) + ) + pathname = spec.origin + packagename = spec.name + packagename = packagename.rpartition(".")[0] + return pathname, packagename, spec +else: + def find_module(modulename): + """Find the module named `modulename`. + + Returns the file path of the module, the name of the enclosing + package, and None (where a spec would have been). + """ + openfile = None + glo, loc = globals(), locals() + try: + # Search for the module - inside its parent package, if any - using + # standard import mechanics. + if '.' in modulename: + packagename, name = modulename.rsplit('.', 1) + package = __import__(packagename, glo, loc, ['__path__']) + searchpath = package.__path__ + else: + packagename, name = None, modulename + searchpath = None # "top-level search" in imp.find_module() + openfile, pathname, _ = imp.find_module(name, searchpath) + + # Complain if this is a magic non-file module. + if openfile is None and pathname is None: + raise NoSource( + "module does not live in a file: %r" % modulename + ) + + # If `modulename` is actually a package, not a mere module, then we + # pretend to be Python 2.7 and try running its __main__.py script. + if openfile is None: + packagename = modulename + name = '__main__' + package = __import__(packagename, glo, loc, ['__path__']) + searchpath = package.__path__ + openfile, pathname, _ = imp.find_module(name, searchpath) + except ImportError as err: + raise NoSource(str(err)) + finally: + if openfile: + openfile.close() + + return pathname, packagename, None + + +class PyRunner(object): + """Multi-stage execution of Python code. + + This is meant to emulate real Python execution as closely as possible. + + """ + def __init__(self, args, as_module=False): + self.args = args + self.as_module = as_module + + self.arg0 = args[0] + self.package = self.modulename = self.pathname = self.loader = self.spec = None + + def prepare(self): + """Set sys.path properly. + + This needs to happen before any importing, and without importing anything. + """ + if self.as_module: + if env.PYBEHAVIOR.actual_syspath0_dash_m: + path0 = os.getcwd() + else: + path0 = "" + elif os.path.isdir(self.arg0): + # Running a directory means running the __main__.py file in that + # directory. + path0 = self.arg0 + else: + path0 = os.path.abspath(os.path.dirname(self.arg0)) + + if os.path.isdir(sys.path[0]): + # sys.path fakery. If we are being run as a command, then sys.path[0] + # is the directory of the "coverage" script. If this is so, replace + # sys.path[0] with the directory of the file we're running, or the + # current directory when running modules. If it isn't so, then we + # don't know what's going on, and just leave it alone. + top_file = inspect.stack()[-1][0].f_code.co_filename + sys_path_0_abs = os.path.abspath(sys.path[0]) + top_file_dir_abs = os.path.abspath(os.path.dirname(top_file)) + sys_path_0_abs = canonical_filename(sys_path_0_abs) + top_file_dir_abs = canonical_filename(top_file_dir_abs) + if sys_path_0_abs != top_file_dir_abs: + path0 = None + + else: + # sys.path[0] is a file. Is the next entry the directory containing + # that file? + if sys.path[1] == os.path.dirname(sys.path[0]): + # Can it be right to always remove that? + del sys.path[1] + + if path0 is not None: + sys.path[0] = python_reported_file(path0) + + def _prepare2(self): + """Do more preparation to run Python code. + + Includes finding the module to run and adjusting sys.argv[0]. + This method is allowed to import code. + + """ + if self.as_module: + self.modulename = self.arg0 + pathname, self.package, self.spec = find_module(self.modulename) + if self.spec is not None: + self.modulename = self.spec.name + self.loader = DummyLoader(self.modulename) + self.pathname = os.path.abspath(pathname) + self.args[0] = self.arg0 = self.pathname + elif os.path.isdir(self.arg0): + # Running a directory means running the __main__.py file in that + # directory. + for ext in [".py", ".pyc", ".pyo"]: + try_filename = os.path.join(self.arg0, "__main__" + ext) + if os.path.exists(try_filename): + self.arg0 = try_filename + break + else: + raise NoSource("Can't find '__main__' module in '%s'" % self.arg0) + + if env.PY2: + self.arg0 = os.path.abspath(self.arg0) + + # Make a spec. I don't know if this is the right way to do it. + try: + import importlib.machinery + except ImportError: + pass + else: + try_filename = python_reported_file(try_filename) + self.spec = importlib.machinery.ModuleSpec("__main__", None, origin=try_filename) + self.spec.has_location = True + self.package = "" + self.loader = DummyLoader("__main__") + else: + if env.PY3: + self.loader = DummyLoader("__main__") + + self.arg0 = python_reported_file(self.arg0) + + def run(self): + """Run the Python code!""" + + self._prepare2() + + # Create a module to serve as __main__ + main_mod = types.ModuleType('__main__') + + from_pyc = self.arg0.endswith((".pyc", ".pyo")) + main_mod.__file__ = self.arg0 + if from_pyc: + main_mod.__file__ = main_mod.__file__[:-1] + if self.package is not None: + main_mod.__package__ = self.package + main_mod.__loader__ = self.loader + if self.spec is not None: + main_mod.__spec__ = self.spec + + main_mod.__builtins__ = BUILTINS + + sys.modules['__main__'] = main_mod + + # Set sys.argv properly. + sys.argv = self.args + + try: + # Make a code object somehow. + if from_pyc: + code = make_code_from_pyc(self.arg0) + else: + code = make_code_from_py(self.arg0) + except CoverageException: + raise + except Exception as exc: + msg = "Couldn't run '{filename}' as Python code: {exc.__class__.__name__}: {exc}" + raise CoverageException(msg.format(filename=self.arg0, exc=exc)) + + # Execute the code object. + # Return to the original directory in case the test code exits in + # a non-existent directory. + cwd = os.getcwd() + try: + exec(code, main_mod.__dict__) + except SystemExit: # pylint: disable=try-except-raise + # The user called sys.exit(). Just pass it along to the upper + # layers, where it will be handled. + raise + except Exception: + # Something went wrong while executing the user code. + # Get the exc_info, and pack them into an exception that we can + # throw up to the outer loop. We peel one layer off the traceback + # so that the coverage.py code doesn't appear in the final printed + # traceback. + typ, err, tb = sys.exc_info() + + # PyPy3 weirdness. If I don't access __context__, then somehow it + # is non-None when the exception is reported at the upper layer, + # and a nested exception is shown to the user. This getattr fixes + # it somehow? https://bitbucket.org/pypy/pypy/issue/1903 + getattr(err, '__context__', None) + + # Call the excepthook. + try: + if hasattr(err, "__traceback__"): + err.__traceback__ = err.__traceback__.tb_next + sys.excepthook(typ, err, tb.tb_next) + except SystemExit: # pylint: disable=try-except-raise + raise + except Exception: + # Getting the output right in the case of excepthook + # shenanigans is kind of involved. + sys.stderr.write("Error in sys.excepthook:\n") + typ2, err2, tb2 = sys.exc_info() + err2.__suppress_context__ = True + if hasattr(err2, "__traceback__"): + err2.__traceback__ = err2.__traceback__.tb_next + sys.__excepthook__(typ2, err2, tb2.tb_next) + sys.stderr.write("\nOriginal exception was:\n") + raise ExceptionDuringRun(typ, err, tb.tb_next) + else: + sys.exit(1) + finally: + os.chdir(cwd) + + +def run_python_module(args): + """Run a Python module, as though with ``python -m name args...``. + + `args` is the argument array to present as sys.argv, including the first + element naming the module being executed. + + This is a helper for tests, to encapsulate how to use PyRunner. + + """ + runner = PyRunner(args, as_module=True) + runner.prepare() + runner.run() + + +def run_python_file(args): + """Run a Python file as if it were the main program on the command line. + + `args` is the argument array to present as sys.argv, including the first + element naming the file being executed. `package` is the name of the + enclosing package, if any. + + This is a helper for tests, to encapsulate how to use PyRunner. + + """ + runner = PyRunner(args, as_module=False) + runner.prepare() + runner.run() + + +def make_code_from_py(filename): + """Get source from `filename` and make a code object of it.""" + # Open the source file. + try: + source = get_python_source(filename) + except (IOError, NoSource): + raise NoSource("No file to run: '%s'" % filename) + + code = compile_unicode(source, filename, "exec") + return code + + +def make_code_from_pyc(filename): + """Get a code object from a .pyc file.""" + try: + fpyc = open(filename, "rb") + except IOError: + raise NoCode("No file to run: '%s'" % filename) + + with fpyc: + # First four bytes are a version-specific magic number. It has to + # match or we won't run the file. + magic = fpyc.read(4) + if magic != PYC_MAGIC_NUMBER: + raise NoCode("Bad magic number in .pyc file: {} != {}".format(magic, PYC_MAGIC_NUMBER)) + + date_based = True + if env.PYBEHAVIOR.hashed_pyc_pep552: + flags = struct.unpack(' MAX_FLAT: + h = hashlib.sha1(name.encode('UTF-8')).hexdigest() + name = name[-(MAX_FLAT-len(h)-1):] + '_' + h + return name + + +if env.WINDOWS: + + _ACTUAL_PATH_CACHE = {} + _ACTUAL_PATH_LIST_CACHE = {} + + def actual_path(path): + """Get the actual path of `path`, including the correct case.""" + if env.PY2 and isinstance(path, unicode_class): + path = path.encode(sys.getfilesystemencoding()) + if path in _ACTUAL_PATH_CACHE: + return _ACTUAL_PATH_CACHE[path] + + head, tail = os.path.split(path) + if not tail: + # This means head is the drive spec: normalize it. + actpath = head.upper() + elif not head: + actpath = tail + else: + head = actual_path(head) + if head in _ACTUAL_PATH_LIST_CACHE: + files = _ACTUAL_PATH_LIST_CACHE[head] + else: + try: + files = os.listdir(head) + except Exception: + # This will raise OSError, or this bizarre TypeError: + # https://bugs.python.org/issue1776160 + files = [] + _ACTUAL_PATH_LIST_CACHE[head] = files + normtail = os.path.normcase(tail) + for f in files: + if os.path.normcase(f) == normtail: + tail = f + break + actpath = os.path.join(head, tail) + _ACTUAL_PATH_CACHE[path] = actpath + return actpath + +else: + def actual_path(filename): + """The actual path for non-Windows platforms.""" + return filename + + +if env.PY2: + @contract(returns='unicode') + def unicode_filename(filename): + """Return a Unicode version of `filename`.""" + if isinstance(filename, str): + encoding = sys.getfilesystemencoding() or sys.getdefaultencoding() + filename = filename.decode(encoding, "replace") + return filename +else: + @contract(filename='unicode', returns='unicode') + def unicode_filename(filename): + """Return a Unicode version of `filename`.""" + return filename + + +@contract(returns='unicode') +def abs_file(path): + """Return the absolute normalized form of `path`.""" + try: + path = os.path.realpath(path) + except UnicodeError: + pass + path = os.path.abspath(path) + path = actual_path(path) + path = unicode_filename(path) + return path + + +def python_reported_file(filename): + """Return the string as Python would describe this file name.""" + if env.PYBEHAVIOR.report_absolute_files: + filename = os.path.abspath(filename) + return filename + + +RELATIVE_DIR = None +CANONICAL_FILENAME_CACHE = None +set_relative_directory() + + +def isabs_anywhere(filename): + """Is `filename` an absolute path on any OS?""" + return ntpath.isabs(filename) or posixpath.isabs(filename) + + +def prep_patterns(patterns): + """Prepare the file patterns for use in a `FnmatchMatcher`. + + If a pattern starts with a wildcard, it is used as a pattern + as-is. If it does not start with a wildcard, then it is made + absolute with the current directory. + + If `patterns` is None, an empty list is returned. + + """ + prepped = [] + for p in patterns or []: + if p.startswith(("*", "?")): + prepped.append(p) + else: + prepped.append(abs_file(p)) + return prepped + + +class TreeMatcher(object): + """A matcher for files in a tree. + + Construct with a list of paths, either files or directories. Paths match + with the `match` method if they are one of the files, or if they are + somewhere in a subtree rooted at one of the directories. + + """ + def __init__(self, paths): + self.paths = list(paths) + + def __repr__(self): + return "" % self.paths + + def info(self): + """A list of strings for displaying when dumping state.""" + return self.paths + + def match(self, fpath): + """Does `fpath` indicate a file in one of our trees?""" + for p in self.paths: + if fpath.startswith(p): + if fpath == p: + # This is the same file! + return True + if fpath[len(p)] == os.sep: + # This is a file in the directory + return True + return False + + +class ModuleMatcher(object): + """A matcher for modules in a tree.""" + def __init__(self, module_names): + self.modules = list(module_names) + + def __repr__(self): + return "" % (self.modules) + + def info(self): + """A list of strings for displaying when dumping state.""" + return self.modules + + def match(self, module_name): + """Does `module_name` indicate a module in one of our packages?""" + if not module_name: + return False + + for m in self.modules: + if module_name.startswith(m): + if module_name == m: + return True + if module_name[len(m)] == '.': + # This is a module in the package + return True + + return False + + +class FnmatchMatcher(object): + """A matcher for files by file name pattern.""" + def __init__(self, pats): + self.pats = list(pats) + self.re = fnmatches_to_regex(self.pats, case_insensitive=env.WINDOWS) + + def __repr__(self): + return "" % self.pats + + def info(self): + """A list of strings for displaying when dumping state.""" + return self.pats + + def match(self, fpath): + """Does `fpath` match one of our file name patterns?""" + return self.re.match(fpath) is not None + + +def sep(s): + """Find the path separator used in this string, or os.sep if none.""" + sep_match = re.search(r"[\\/]", s) + if sep_match: + the_sep = sep_match.group(0) + else: + the_sep = os.sep + return the_sep + + +def fnmatches_to_regex(patterns, case_insensitive=False, partial=False): + """Convert fnmatch patterns to a compiled regex that matches any of them. + + Slashes are always converted to match either slash or backslash, for + Windows support, even when running elsewhere. + + If `partial` is true, then the pattern will match if the target string + starts with the pattern. Otherwise, it must match the entire string. + + Returns: a compiled regex object. Use the .match method to compare target + strings. + + """ + regexes = (fnmatch.translate(pattern) for pattern in patterns) + # Python3.7 fnmatch translates "/" as "/". Before that, it translates as "\/", + # so we have to deal with maybe a backslash. + regexes = (re.sub(r"\\?/", r"[\\\\/]", regex) for regex in regexes) + + if partial: + # fnmatch always adds a \Z to match the whole string, which we don't + # want, so we remove the \Z. While removing it, we only replace \Z if + # followed by paren (introducing flags), or at end, to keep from + # destroying a literal \Z in the pattern. + regexes = (re.sub(r'\\Z(\(\?|$)', r'\1', regex) for regex in regexes) + + flags = 0 + if case_insensitive: + flags |= re.IGNORECASE + compiled = re.compile(join_regex(regexes), flags=flags) + + return compiled + + +class PathAliases(object): + """A collection of aliases for paths. + + When combining data files from remote machines, often the paths to source + code are different, for example, due to OS differences, or because of + serialized checkouts on continuous integration machines. + + A `PathAliases` object tracks a list of pattern/result pairs, and can + map a path through those aliases to produce a unified path. + + """ + def __init__(self): + self.aliases = [] + + def pprint(self): # pragma: debugging + """Dump the important parts of the PathAliases, for debugging.""" + for regex, result in self.aliases: + print("{!r} --> {!r}".format(regex.pattern, result)) + + def add(self, pattern, result): + """Add the `pattern`/`result` pair to the list of aliases. + + `pattern` is an `fnmatch`-style pattern. `result` is a simple + string. When mapping paths, if a path starts with a match against + `pattern`, then that match is replaced with `result`. This models + isomorphic source trees being rooted at different places on two + different machines. + + `pattern` can't end with a wildcard component, since that would + match an entire tree, and not just its root. + + """ + pattern_sep = sep(pattern) + + if len(pattern) > 1: + pattern = pattern.rstrip(r"\/") + + # The pattern can't end with a wildcard component. + if pattern.endswith("*"): + raise CoverageException("Pattern must not end with wildcards.") + + # The pattern is meant to match a filepath. Let's make it absolute + # unless it already is, or is meant to match any prefix. + if not pattern.startswith('*') and not isabs_anywhere(pattern + + pattern_sep): + pattern = abs_file(pattern) + if not pattern.endswith(pattern_sep): + pattern += pattern_sep + + # Make a regex from the pattern. + regex = fnmatches_to_regex([pattern], case_insensitive=True, partial=True) + + # Normalize the result: it must end with a path separator. + result_sep = sep(result) + result = result.rstrip(r"\/") + result_sep + self.aliases.append((regex, result)) + + def map(self, path): + """Map `path` through the aliases. + + `path` is checked against all of the patterns. The first pattern to + match is used to replace the root of the path with the result root. + Only one pattern is ever used. If no patterns match, `path` is + returned unchanged. + + The separator style in the result is made to match that of the result + in the alias. + + Returns the mapped path. If a mapping has happened, this is a + canonical path. If no mapping has happened, it is the original value + of `path` unchanged. + + """ + for regex, result in self.aliases: + m = regex.match(path) + if m: + new = path.replace(m.group(0), result) + new = new.replace(sep(path), sep(result)) + new = canonical_filename(new) + return new + return path + + +def find_python_files(dirname): + """Yield all of the importable Python files in `dirname`, recursively. + + To be importable, the files have to be in a directory with a __init__.py, + except for `dirname` itself, which isn't required to have one. The + assumption is that `dirname` was specified directly, so the user knows + best, but sub-directories are checked for a __init__.py to be sure we only + find the importable files. + + """ + for i, (dirpath, dirnames, filenames) in enumerate(os.walk(dirname)): + if i > 0 and '__init__.py' not in filenames: + # If a directory doesn't have __init__.py, then it isn't + # importable and neither are its files + del dirnames[:] + continue + for filename in filenames: + # We're only interested in files that look like reasonable Python + # files: Must end with .py or .pyw, and must not have certain funny + # characters that probably mean they are editor junk. + if re.match(r"^[^.#~!$@%^&*()+=,]+\.pyw?$", filename): + yield os.path.join(dirpath, filename) diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/fullcoverage/encodings.py b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/fullcoverage/encodings.py new file mode 100644 index 000000000..aeb416e40 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/fullcoverage/encodings.py @@ -0,0 +1,60 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +"""Imposter encodings module that installs a coverage-style tracer. + +This is NOT the encodings module; it is an imposter that sets up tracing +instrumentation and then replaces itself with the real encodings module. + +If the directory that holds this file is placed first in the PYTHONPATH when +using "coverage" to run Python's tests, then this file will become the very +first module imported by the internals of Python 3. It installs a +coverage.py-compatible trace function that can watch Standard Library modules +execute from the very earliest stages of Python's own boot process. This fixes +a problem with coverage.py - that it starts too late to trace the coverage of +many of the most fundamental modules in the Standard Library. + +""" + +import sys + +class FullCoverageTracer(object): + def __init__(self): + # `traces` is a list of trace events. Frames are tricky: the same + # frame object is used for a whole scope, with new line numbers + # written into it. So in one scope, all the frame objects are the + # same object, and will eventually all will point to the last line + # executed. So we keep the line numbers alongside the frames. + # The list looks like: + # + # traces = [ + # ((frame, event, arg), lineno), ... + # ] + # + self.traces = [] + + def fullcoverage_trace(self, *args): + frame, event, arg = args + self.traces.append((args, frame.f_lineno)) + return self.fullcoverage_trace + +sys.settrace(FullCoverageTracer().fullcoverage_trace) + +# In coverage/files.py is actual_filename(), which uses glob.glob. I don't +# understand why, but that use of glob borks everything if fullcoverage is in +# effect. So here we make an ugly hail-mary pass to switch off glob.glob over +# there. This means when using fullcoverage, Windows path names will not be +# their actual case. + +#sys.fullcoverage = True + +# Finally, remove our own directory from sys.path; remove ourselves from +# sys.modules; and re-import "encodings", which will be the real package +# this time. Note that the delete from sys.modules dictionary has to +# happen last, since all of the symbols in this module will become None +# at that exact moment, including "sys". + +parentdir = max(filter(__file__.startswith, sys.path), key=len) +sys.path.remove(parentdir) +del sys.modules['encodings'] +import encodings diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/html.py b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/html.py new file mode 100644 index 000000000..0dfee7ca8 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/html.py @@ -0,0 +1,520 @@ +# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +"""HTML reporting for coverage.py.""" + +import datetime +import json +import os +import re +import shutil + +import coverage +from coverage import env +from coverage.backward import iitems, SimpleNamespace, format_local_datetime +from coverage.data import add_data_to_hash +from coverage.files import flat_rootname +from coverage.misc import CoverageException, ensure_dir, file_be_gone, Hasher, isolate_module +from coverage.report import get_analysis_to_report +from coverage.results import Numbers +from coverage.templite import Templite + +os = isolate_module(os) + + +# Static files are looked for in a list of places. +STATIC_PATH = [ + # The place Debian puts system Javascript libraries. + "/usr/share/javascript", + + # Our htmlfiles directory. + os.path.join(os.path.dirname(__file__), "htmlfiles"), +] + + +def data_filename(fname, pkgdir=""): + """Return the path to a data file of ours. + + The file is searched for on `STATIC_PATH`, and the first place it's found, + is returned. + + Each directory in `STATIC_PATH` is searched as-is, and also, if `pkgdir` + is provided, at that sub-directory. + + """ + tried = [] + for static_dir in STATIC_PATH: + static_filename = os.path.join(static_dir, fname) + if os.path.exists(static_filename): + return static_filename + else: + tried.append(static_filename) + if pkgdir: + static_filename = os.path.join(static_dir, pkgdir, fname) + if os.path.exists(static_filename): + return static_filename + else: + tried.append(static_filename) + raise CoverageException( + "Couldn't find static file %r from %r, tried: %r" % (fname, os.getcwd(), tried) + ) + + +def read_data(fname): + """Return the contents of a data file of ours.""" + with open(data_filename(fname)) as data_file: + return data_file.read() + + +def write_html(fname, html): + """Write `html` to `fname`, properly encoded.""" + html = re.sub(r"(\A\s+)|(\s+$)", "", html, flags=re.MULTILINE) + "\n" + with open(fname, "wb") as fout: + fout.write(html.encode('ascii', 'xmlcharrefreplace')) + + +class HtmlDataGeneration(object): + """Generate structured data to be turned into HTML reports.""" + + EMPTY = "(empty)" + + def __init__(self, cov): + self.coverage = cov + self.config = self.coverage.config + data = self.coverage.get_data() + self.has_arcs = data.has_arcs() + if self.config.show_contexts: + if data.measured_contexts() == {""}: + self.coverage._warn("No contexts were measured") + data.set_query_contexts(self.config.report_contexts) + + def data_for_file(self, fr, analysis): + """Produce the data needed for one file's report.""" + if self.has_arcs: + missing_branch_arcs = analysis.missing_branch_arcs() + arcs_executed = analysis.arcs_executed() + + if self.config.show_contexts: + contexts_by_lineno = analysis.data.contexts_by_lineno(analysis.filename) + + lines = [] + + for lineno, tokens in enumerate(fr.source_token_lines(), start=1): + # Figure out how to mark this line. + category = None + short_annotations = [] + long_annotations = [] + + if lineno in analysis.excluded: + category = 'exc' + elif lineno in analysis.missing: + category = 'mis' + elif self.has_arcs and lineno in missing_branch_arcs: + category = 'par' + for b in missing_branch_arcs[lineno]: + if b < 0: + short_annotations.append("exit") + else: + short_annotations.append(b) + long_annotations.append(fr.missing_arc_description(lineno, b, arcs_executed)) + elif lineno in analysis.statements: + category = 'run' + + contexts = contexts_label = None + context_list = None + if category and self.config.show_contexts: + contexts = sorted(c or self.EMPTY for c in contexts_by_lineno[lineno]) + if contexts == [self.EMPTY]: + contexts_label = self.EMPTY + else: + contexts_label = "{} ctx".format(len(contexts)) + context_list = contexts + + lines.append(SimpleNamespace( + tokens=tokens, + number=lineno, + category=category, + statement=(lineno in analysis.statements), + contexts=contexts, + contexts_label=contexts_label, + context_list=context_list, + short_annotations=short_annotations, + long_annotations=long_annotations, + )) + + file_data = SimpleNamespace( + relative_filename=fr.relative_filename(), + nums=analysis.numbers, + lines=lines, + ) + + return file_data + + +class HtmlReporter(object): + """HTML reporting.""" + + # These files will be copied from the htmlfiles directory to the output + # directory. + STATIC_FILES = [ + ("style.css", ""), + ("jquery.min.js", "jquery"), + ("jquery.ba-throttle-debounce.min.js", "jquery-throttle-debounce"), + ("jquery.hotkeys.js", "jquery-hotkeys"), + ("jquery.isonscreen.js", "jquery-isonscreen"), + ("jquery.tablesorter.min.js", "jquery-tablesorter"), + ("coverage_html.js", ""), + ("keybd_closed.png", ""), + ("keybd_open.png", ""), + ("favicon_32.png", ""), + ] + + def __init__(self, cov): + self.coverage = cov + self.config = self.coverage.config + self.directory = self.config.html_dir + + self.skip_covered = self.config.html_skip_covered + if self.skip_covered is None: + self.skip_covered = self.config.skip_covered + self.skip_empty = self.config.html_skip_empty + if self.skip_empty is None: + self.skip_empty= self.config.skip_empty + + title = self.config.html_title + if env.PY2: + title = title.decode("utf8") + + if self.config.extra_css: + self.extra_css = os.path.basename(self.config.extra_css) + else: + self.extra_css = None + + self.data = self.coverage.get_data() + self.has_arcs = self.data.has_arcs() + + self.file_summaries = [] + self.all_files_nums = [] + self.incr = IncrementalChecker(self.directory) + self.datagen = HtmlDataGeneration(self.coverage) + self.totals = Numbers() + + self.template_globals = { + # Functions available in the templates. + 'escape': escape, + 'pair': pair, + 'len': len, + + # Constants for this report. + '__url__': coverage.__url__, + '__version__': coverage.__version__, + 'title': title, + 'time_stamp': format_local_datetime(datetime.datetime.now()), + 'extra_css': self.extra_css, + 'has_arcs': self.has_arcs, + 'show_contexts': self.config.show_contexts, + + # Constants for all reports. + # These css classes determine which lines are highlighted by default. + 'category': { + 'exc': 'exc show_exc', + 'mis': 'mis show_mis', + 'par': 'par run show_par', + 'run': 'run', + } + } + self.pyfile_html_source = read_data("pyfile.html") + self.source_tmpl = Templite(self.pyfile_html_source, self.template_globals) + + def report(self, morfs): + """Generate an HTML report for `morfs`. + + `morfs` is a list of modules or file names. + + """ + # Read the status data and check that this run used the same + # global data as the last run. + self.incr.read() + self.incr.check_global_data(self.config, self.pyfile_html_source) + + # Process all the files. + for fr, analysis in get_analysis_to_report(self.coverage, morfs): + self.html_file(fr, analysis) + + if not self.all_files_nums: + raise CoverageException("No data to report.") + + self.totals = sum(self.all_files_nums) + + # Write the index file. + self.index_file() + + self.make_local_static_report_files() + return self.totals.n_statements and self.totals.pc_covered + + def make_local_static_report_files(self): + """Make local instances of static files for HTML report.""" + # The files we provide must always be copied. + for static, pkgdir in self.STATIC_FILES: + shutil.copyfile( + data_filename(static, pkgdir), + os.path.join(self.directory, static) + ) + + # The user may have extra CSS they want copied. + if self.extra_css: + shutil.copyfile( + self.config.extra_css, + os.path.join(self.directory, self.extra_css) + ) + + def html_file(self, fr, analysis): + """Generate an HTML file for one source file.""" + rootname = flat_rootname(fr.relative_filename()) + html_filename = rootname + ".html" + ensure_dir(self.directory) + html_path = os.path.join(self.directory, html_filename) + + # Get the numbers for this file. + nums = analysis.numbers + self.all_files_nums.append(nums) + + if self.skip_covered: + # Don't report on 100% files. + no_missing_lines = (nums.n_missing == 0) + no_missing_branches = (nums.n_partial_branches == 0) + if no_missing_lines and no_missing_branches: + # If there's an existing file, remove it. + file_be_gone(html_path) + return + + if self.skip_empty: + # Don't report on empty files. + if nums.n_statements == 0: + file_be_gone(html_path) + return + + # Find out if the file on disk is already correct. + if self.incr.can_skip_file(self.data, fr, rootname): + self.file_summaries.append(self.incr.index_info(rootname)) + return + + # Write the HTML page for this file. + file_data = self.datagen.data_for_file(fr, analysis) + for ldata in file_data.lines: + # Build the HTML for the line. + html = [] + for tok_type, tok_text in ldata.tokens: + if tok_type == "ws": + html.append(escape(tok_text)) + else: + tok_html = escape(tok_text) or ' ' + html.append( + u'{}'.format(tok_type, tok_html) + ) + ldata.html = ''.join(html) + + if ldata.short_annotations: + # 202F is NARROW NO-BREAK SPACE. + # 219B is RIGHTWARDS ARROW WITH STROKE. + ldata.annotate = u",   ".join( + u"{} ↛ {}".format(ldata.number, d) + for d in ldata.short_annotations + ) + else: + ldata.annotate = None + + if ldata.long_annotations: + longs = ldata.long_annotations + if len(longs) == 1: + ldata.annotate_long = longs[0] + else: + ldata.annotate_long = u"{:d} missed branches: {}".format( + len(longs), + u", ".join( + u"{:d}) {}".format(num, ann_long) + for num, ann_long in enumerate(longs, start=1) + ), + ) + else: + ldata.annotate_long = None + + css_classes = [] + if ldata.category: + css_classes.append(self.template_globals['category'][ldata.category]) + ldata.css_class = ' '.join(css_classes) or "pln" + + html = self.source_tmpl.render(file_data.__dict__) + write_html(html_path, html) + + # Save this file's information for the index file. + index_info = { + 'nums': nums, + 'html_filename': html_filename, + 'relative_filename': fr.relative_filename(), + } + self.file_summaries.append(index_info) + self.incr.set_index_info(rootname, index_info) + + def index_file(self): + """Write the index.html file for this report.""" + index_tmpl = Templite(read_data("index.html"), self.template_globals) + + html = index_tmpl.render({ + 'files': self.file_summaries, + 'totals': self.totals, + }) + + write_html(os.path.join(self.directory, "index.html"), html) + + # Write the latest hashes for next time. + self.incr.write() + + +class IncrementalChecker(object): + """Logic and data to support incremental reporting.""" + + STATUS_FILE = "status.json" + STATUS_FORMAT = 2 + + # pylint: disable=wrong-spelling-in-comment,useless-suppression + # The data looks like: + # + # { + # "format": 2, + # "globals": "540ee119c15d52a68a53fe6f0897346d", + # "version": "4.0a1", + # "files": { + # "cogapp___init__": { + # "hash": "e45581a5b48f879f301c0f30bf77a50c", + # "index": { + # "html_filename": "cogapp___init__.html", + # "relative_filename": "cogapp/__init__", + # "nums": [ 1, 14, 0, 0, 0, 0, 0 ] + # } + # }, + # ... + # "cogapp_whiteutils": { + # "hash": "8504bb427fc488c4176809ded0277d51", + # "index": { + # "html_filename": "cogapp_whiteutils.html", + # "relative_filename": "cogapp/whiteutils", + # "nums": [ 1, 59, 0, 1, 28, 2, 2 ] + # } + # } + # } + # } + + def __init__(self, directory): + self.directory = directory + self.reset() + + def reset(self): + """Initialize to empty. Causes all files to be reported.""" + self.globals = '' + self.files = {} + + def read(self): + """Read the information we stored last time.""" + usable = False + try: + status_file = os.path.join(self.directory, self.STATUS_FILE) + with open(status_file) as fstatus: + status = json.load(fstatus) + except (IOError, ValueError): + usable = False + else: + usable = True + if status['format'] != self.STATUS_FORMAT: + usable = False + elif status['version'] != coverage.__version__: + usable = False + + if usable: + self.files = {} + for filename, fileinfo in iitems(status['files']): + fileinfo['index']['nums'] = Numbers(*fileinfo['index']['nums']) + self.files[filename] = fileinfo + self.globals = status['globals'] + else: + self.reset() + + def write(self): + """Write the current status.""" + status_file = os.path.join(self.directory, self.STATUS_FILE) + files = {} + for filename, fileinfo in iitems(self.files): + fileinfo['index']['nums'] = fileinfo['index']['nums'].init_args() + files[filename] = fileinfo + + status = { + 'format': self.STATUS_FORMAT, + 'version': coverage.__version__, + 'globals': self.globals, + 'files': files, + } + with open(status_file, "w") as fout: + json.dump(status, fout, separators=(',', ':')) + + def check_global_data(self, *data): + """Check the global data that can affect incremental reporting.""" + m = Hasher() + for d in data: + m.update(d) + these_globals = m.hexdigest() + if self.globals != these_globals: + self.reset() + self.globals = these_globals + + def can_skip_file(self, data, fr, rootname): + """Can we skip reporting this file? + + `data` is a CoverageData object, `fr` is a `FileReporter`, and + `rootname` is the name being used for the file. + """ + m = Hasher() + m.update(fr.source().encode('utf-8')) + add_data_to_hash(data, fr.filename, m) + this_hash = m.hexdigest() + + that_hash = self.file_hash(rootname) + + if this_hash == that_hash: + # Nothing has changed to require the file to be reported again. + return True + else: + self.set_file_hash(rootname, this_hash) + return False + + def file_hash(self, fname): + """Get the hash of `fname`'s contents.""" + return self.files.get(fname, {}).get('hash', '') + + def set_file_hash(self, fname, val): + """Set the hash of `fname`'s contents.""" + self.files.setdefault(fname, {})['hash'] = val + + def index_info(self, fname): + """Get the information for index.html for `fname`.""" + return self.files.get(fname, {}).get('index', {}) + + def set_index_info(self, fname, info): + """Set the information for index.html for `fname`.""" + self.files.setdefault(fname, {})['index'] = info + + +# Helpers for templates and generating HTML + +def escape(t): + """HTML-escape the text in `t`. + + This is only suitable for HTML text, not attributes. + + """ + # Convert HTML special chars into HTML entities. + return t.replace("&", "&").replace("<", "<") + + +def pair(ratio): + """Format a pair of numbers so JavaScript can read them in an attribute.""" + return "%s %s" % ratio diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/coverage_html.js b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/coverage_html.js new file mode 100644 index 000000000..27b49b36f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/coverage_html.js @@ -0,0 +1,616 @@ +// Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 +// For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt + +// Coverage.py HTML report browser code. +/*jslint browser: true, sloppy: true, vars: true, plusplus: true, maxerr: 50, indent: 4 */ +/*global coverage: true, document, window, $ */ + +coverage = {}; + +// Find all the elements with shortkey_* class, and use them to assign a shortcut key. +coverage.assign_shortkeys = function () { + $("*[class*='shortkey_']").each(function (i, e) { + $.each($(e).attr("class").split(" "), function (i, c) { + if (/^shortkey_/.test(c)) { + $(document).bind('keydown', c.substr(9), function () { + $(e).click(); + }); + } + }); + }); +}; + +// Create the events for the help panel. +coverage.wire_up_help_panel = function () { + $("#keyboard_icon").click(function () { + // Show the help panel, and position it so the keyboard icon in the + // panel is in the same place as the keyboard icon in the header. + $(".help_panel").show(); + var koff = $("#keyboard_icon").offset(); + var poff = $("#panel_icon").position(); + $(".help_panel").offset({ + top: koff.top-poff.top, + left: koff.left-poff.left + }); + }); + $("#panel_icon").click(function () { + $(".help_panel").hide(); + }); +}; + +// Create the events for the filter box. +coverage.wire_up_filter = function () { + // Cache elements. + var table = $("table.index"); + var table_rows = table.find("tbody tr"); + var table_row_names = table_rows.find("td.name a"); + var no_rows = $("#no_rows"); + + // Create a duplicate table footer that we can modify with dynamic summed values. + var table_footer = $("table.index tfoot tr"); + var table_dynamic_footer = table_footer.clone(); + table_dynamic_footer.attr('class', 'total_dynamic hidden'); + table_footer.after(table_dynamic_footer); + + // Observe filter keyevents. + $("#filter").on("keyup change", $.debounce(150, function (event) { + var filter_value = $(this).val(); + + if (filter_value === "") { + // Filter box is empty, remove all filtering. + table_rows.removeClass("hidden"); + + // Show standard footer, hide dynamic footer. + table_footer.removeClass("hidden"); + table_dynamic_footer.addClass("hidden"); + + // Hide placeholder, show table. + if (no_rows.length > 0) { + no_rows.hide(); + } + table.show(); + + } + else { + // Filter table items by value. + var hidden = 0; + var shown = 0; + + // Hide / show elements. + $.each(table_row_names, function () { + var element = $(this).parents("tr"); + + if ($(this).text().indexOf(filter_value) === -1) { + // hide + element.addClass("hidden"); + hidden++; + } + else { + // show + element.removeClass("hidden"); + shown++; + } + }); + + // Show placeholder if no rows will be displayed. + if (no_rows.length > 0) { + if (shown === 0) { + // Show placeholder, hide table. + no_rows.show(); + table.hide(); + } + else { + // Hide placeholder, show table. + no_rows.hide(); + table.show(); + } + } + + // Manage dynamic header: + if (hidden > 0) { + // Calculate new dynamic sum values based on visible rows. + for (var column = 2; column < 20; column++) { + // Calculate summed value. + var cells = table_rows.find('td:nth-child(' + column + ')'); + if (!cells.length) { + // No more columns...! + break; + } + + var sum = 0, numer = 0, denom = 0; + $.each(cells.filter(':visible'), function () { + var ratio = $(this).data("ratio"); + if (ratio) { + var splitted = ratio.split(" "); + numer += parseInt(splitted[0], 10); + denom += parseInt(splitted[1], 10); + } + else { + sum += parseInt(this.innerHTML, 10); + } + }); + + // Get footer cell element. + var footer_cell = table_dynamic_footer.find('td:nth-child(' + column + ')'); + + // Set value into dynamic footer cell element. + if (cells[0].innerHTML.indexOf('%') > -1) { + // Percentage columns use the numerator and denominator, + // and adapt to the number of decimal places. + var match = /\.([0-9]+)/.exec(cells[0].innerHTML); + var places = 0; + if (match) { + places = match[1].length; + } + var pct = numer * 100 / denom; + footer_cell.text(pct.toFixed(places) + '%'); + } + else { + footer_cell.text(sum); + } + } + + // Hide standard footer, show dynamic footer. + table_footer.addClass("hidden"); + table_dynamic_footer.removeClass("hidden"); + } + else { + // Show standard footer, hide dynamic footer. + table_footer.removeClass("hidden"); + table_dynamic_footer.addClass("hidden"); + } + } + })); + + // Trigger change event on setup, to force filter on page refresh + // (filter value may still be present). + $("#filter").trigger("change"); +}; + +// Loaded on index.html +coverage.index_ready = function ($) { + // Look for a localStorage item containing previous sort settings: + var sort_list = []; + var storage_name = "COVERAGE_INDEX_SORT"; + var stored_list = undefined; + try { + stored_list = localStorage.getItem(storage_name); + } catch(err) {} + + if (stored_list) { + sort_list = JSON.parse('[[' + stored_list + ']]'); + } + + // Create a new widget which exists only to save and restore + // the sort order: + $.tablesorter.addWidget({ + id: "persistentSort", + + // Format is called by the widget before displaying: + format: function (table) { + if (table.config.sortList.length === 0 && sort_list.length > 0) { + // This table hasn't been sorted before - we'll use + // our stored settings: + $(table).trigger('sorton', [sort_list]); + } + else { + // This is not the first load - something has + // already defined sorting so we'll just update + // our stored value to match: + sort_list = table.config.sortList; + } + } + }); + + // Configure our tablesorter to handle the variable number of + // columns produced depending on report options: + var headers = []; + var col_count = $("table.index > thead > tr > th").length; + + headers[0] = { sorter: 'text' }; + for (i = 1; i < col_count-1; i++) { + headers[i] = { sorter: 'digit' }; + } + headers[col_count-1] = { sorter: 'percent' }; + + // Enable the table sorter: + $("table.index").tablesorter({ + widgets: ['persistentSort'], + headers: headers + }); + + coverage.assign_shortkeys(); + coverage.wire_up_help_panel(); + coverage.wire_up_filter(); + + // Watch for page unload events so we can save the final sort settings: + $(window).on("unload", function () { + try { + localStorage.setItem(storage_name, sort_list.toString()) + } catch(err) {} + }); +}; + +// -- pyfile stuff -- + +coverage.LINE_FILTERS_STORAGE = "COVERAGE_LINE_FILTERS"; + +coverage.pyfile_ready = function ($) { + // If we're directed to a particular line number, highlight the line. + var frag = location.hash; + if (frag.length > 2 && frag[1] === 't') { + $(frag).addClass('highlight'); + coverage.set_sel(parseInt(frag.substr(2), 10)); + } + else { + coverage.set_sel(0); + } + + $(document) + .bind('keydown', 'j', coverage.to_next_chunk_nicely) + .bind('keydown', 'k', coverage.to_prev_chunk_nicely) + .bind('keydown', '0', coverage.to_top) + .bind('keydown', '1', coverage.to_first_chunk) + ; + + $(".button_toggle_run").click(function (evt) {coverage.toggle_lines(evt.target, "run");}); + $(".button_toggle_exc").click(function (evt) {coverage.toggle_lines(evt.target, "exc");}); + $(".button_toggle_mis").click(function (evt) {coverage.toggle_lines(evt.target, "mis");}); + $(".button_toggle_par").click(function (evt) {coverage.toggle_lines(evt.target, "par");}); + + coverage.filters = undefined; + try { + coverage.filters = localStorage.getItem(coverage.LINE_FILTERS_STORAGE); + } catch(err) {} + + if (coverage.filters) { + coverage.filters = JSON.parse(coverage.filters); + } + else { + coverage.filters = {run: false, exc: true, mis: true, par: true}; + } + + for (cls in coverage.filters) { + coverage.set_line_visibilty(cls, coverage.filters[cls]); + } + + coverage.assign_shortkeys(); + coverage.wire_up_help_panel(); + + coverage.init_scroll_markers(); + + // Rebuild scroll markers when the window height changes. + $(window).resize(coverage.build_scroll_markers); +}; + +coverage.toggle_lines = function (btn, cls) { + var onoff = !$(btn).hasClass("show_" + cls); + coverage.set_line_visibilty(cls, onoff); + coverage.build_scroll_markers(); + coverage.filters[cls] = onoff; + try { + localStorage.setItem(coverage.LINE_FILTERS_STORAGE, JSON.stringify(coverage.filters)); + } catch(err) {} +}; + +coverage.set_line_visibilty = function (cls, onoff) { + var show = "show_" + cls; + var btn = $(".button_toggle_" + cls); + if (onoff) { + $("#source ." + cls).addClass(show); + btn.addClass(show); + } + else { + $("#source ." + cls).removeClass(show); + btn.removeClass(show); + } +}; + +// Return the nth line div. +coverage.line_elt = function (n) { + return $("#t" + n); +}; + +// Return the nth line number div. +coverage.num_elt = function (n) { + return $("#n" + n); +}; + +// Set the selection. b and e are line numbers. +coverage.set_sel = function (b, e) { + // The first line selected. + coverage.sel_begin = b; + // The next line not selected. + coverage.sel_end = (e === undefined) ? b+1 : e; +}; + +coverage.to_top = function () { + coverage.set_sel(0, 1); + coverage.scroll_window(0); +}; + +coverage.to_first_chunk = function () { + coverage.set_sel(0, 1); + coverage.to_next_chunk(); +}; + +// Return a string indicating what kind of chunk this line belongs to, +// or null if not a chunk. +coverage.chunk_indicator = function (line_elt) { + var klass = line_elt.attr('class'); + if (klass) { + var m = klass.match(/\bshow_\w+\b/); + if (m) { + return m[0]; + } + } + return null; +}; + +coverage.to_next_chunk = function () { + var c = coverage; + + // Find the start of the next colored chunk. + var probe = c.sel_end; + var chunk_indicator, probe_line; + while (true) { + probe_line = c.line_elt(probe); + if (probe_line.length === 0) { + return; + } + chunk_indicator = c.chunk_indicator(probe_line); + if (chunk_indicator) { + break; + } + probe++; + } + + // There's a next chunk, `probe` points to it. + var begin = probe; + + // Find the end of this chunk. + var next_indicator = chunk_indicator; + while (next_indicator === chunk_indicator) { + probe++; + probe_line = c.line_elt(probe); + next_indicator = c.chunk_indicator(probe_line); + } + c.set_sel(begin, probe); + c.show_selection(); +}; + +coverage.to_prev_chunk = function () { + var c = coverage; + + // Find the end of the prev colored chunk. + var probe = c.sel_begin-1; + var probe_line = c.line_elt(probe); + if (probe_line.length === 0) { + return; + } + var chunk_indicator = c.chunk_indicator(probe_line); + while (probe > 0 && !chunk_indicator) { + probe--; + probe_line = c.line_elt(probe); + if (probe_line.length === 0) { + return; + } + chunk_indicator = c.chunk_indicator(probe_line); + } + + // There's a prev chunk, `probe` points to its last line. + var end = probe+1; + + // Find the beginning of this chunk. + var prev_indicator = chunk_indicator; + while (prev_indicator === chunk_indicator) { + probe--; + probe_line = c.line_elt(probe); + prev_indicator = c.chunk_indicator(probe_line); + } + c.set_sel(probe+1, end); + c.show_selection(); +}; + +// Return the line number of the line nearest pixel position pos +coverage.line_at_pos = function (pos) { + var l1 = coverage.line_elt(1), + l2 = coverage.line_elt(2), + result; + if (l1.length && l2.length) { + var l1_top = l1.offset().top, + line_height = l2.offset().top - l1_top, + nlines = (pos - l1_top) / line_height; + if (nlines < 1) { + result = 1; + } + else { + result = Math.ceil(nlines); + } + } + else { + result = 1; + } + return result; +}; + +// Returns 0, 1, or 2: how many of the two ends of the selection are on +// the screen right now? +coverage.selection_ends_on_screen = function () { + if (coverage.sel_begin === 0) { + return 0; + } + + var top = coverage.line_elt(coverage.sel_begin); + var next = coverage.line_elt(coverage.sel_end-1); + + return ( + (top.isOnScreen() ? 1 : 0) + + (next.isOnScreen() ? 1 : 0) + ); +}; + +coverage.to_next_chunk_nicely = function () { + coverage.finish_scrolling(); + if (coverage.selection_ends_on_screen() === 0) { + // The selection is entirely off the screen: select the top line on + // the screen. + var win = $(window); + coverage.select_line_or_chunk(coverage.line_at_pos(win.scrollTop())); + } + coverage.to_next_chunk(); +}; + +coverage.to_prev_chunk_nicely = function () { + coverage.finish_scrolling(); + if (coverage.selection_ends_on_screen() === 0) { + var win = $(window); + coverage.select_line_or_chunk(coverage.line_at_pos(win.scrollTop() + win.height())); + } + coverage.to_prev_chunk(); +}; + +// Select line number lineno, or if it is in a colored chunk, select the +// entire chunk +coverage.select_line_or_chunk = function (lineno) { + var c = coverage; + var probe_line = c.line_elt(lineno); + if (probe_line.length === 0) { + return; + } + var the_indicator = c.chunk_indicator(probe_line); + if (the_indicator) { + // The line is in a highlighted chunk. + // Search backward for the first line. + var probe = lineno; + var indicator = the_indicator; + while (probe > 0 && indicator === the_indicator) { + probe--; + probe_line = c.line_elt(probe); + if (probe_line.length === 0) { + break; + } + indicator = c.chunk_indicator(probe_line); + } + var begin = probe + 1; + + // Search forward for the last line. + probe = lineno; + indicator = the_indicator; + while (indicator === the_indicator) { + probe++; + probe_line = c.line_elt(probe); + indicator = c.chunk_indicator(probe_line); + } + + coverage.set_sel(begin, probe); + } + else { + coverage.set_sel(lineno); + } +}; + +coverage.show_selection = function () { + var c = coverage; + + // Highlight the lines in the chunk + $(".linenos .highlight").removeClass("highlight"); + for (var probe = c.sel_begin; probe > 0 && probe < c.sel_end; probe++) { + c.num_elt(probe).addClass("highlight"); + } + + c.scroll_to_selection(); +}; + +coverage.scroll_to_selection = function () { + // Scroll the page if the chunk isn't fully visible. + if (coverage.selection_ends_on_screen() < 2) { + // Need to move the page. The html,body trick makes it scroll in all + // browsers, got it from http://stackoverflow.com/questions/3042651 + var top = coverage.line_elt(coverage.sel_begin); + var top_pos = parseInt(top.offset().top, 10); + coverage.scroll_window(top_pos - 30); + } +}; + +coverage.scroll_window = function (to_pos) { + $("html,body").animate({scrollTop: to_pos}, 200); +}; + +coverage.finish_scrolling = function () { + $("html,body").stop(true, true); +}; + +coverage.init_scroll_markers = function () { + var c = coverage; + // Init some variables + c.lines_len = $('#source p').length; + c.body_h = $('body').height(); + c.header_h = $('div#header').height(); + + // Build html + c.build_scroll_markers(); +}; + +coverage.build_scroll_markers = function () { + var c = coverage, + min_line_height = 3, + max_line_height = 10, + visible_window_h = $(window).height(); + + c.lines_to_mark = $('#source').find('p.show_run, p.show_mis, p.show_exc, p.show_exc, p.show_par'); + $('#scroll_marker').remove(); + // Don't build markers if the window has no scroll bar. + if (c.body_h <= visible_window_h) { + return; + } + + $("body").append("
 
"); + var scroll_marker = $('#scroll_marker'), + marker_scale = scroll_marker.height() / c.body_h, + line_height = scroll_marker.height() / c.lines_len; + + // Line height must be between the extremes. + if (line_height > min_line_height) { + if (line_height > max_line_height) { + line_height = max_line_height; + } + } + else { + line_height = min_line_height; + } + + var previous_line = -99, + last_mark, + last_top, + offsets = {}; + + // Calculate line offsets outside loop to prevent relayouts + c.lines_to_mark.each(function() { + offsets[this.id] = $(this).offset().top; + }); + c.lines_to_mark.each(function () { + var id_name = $(this).attr('id'), + line_top = Math.round(offsets[id_name] * marker_scale), + line_number = parseInt(id_name.substring(1, id_name.length)); + + if (line_number === previous_line + 1) { + // If this solid missed block just make previous mark higher. + last_mark.css({ + 'height': line_top + line_height - last_top + }); + } + else { + // Add colored line in scroll_marker block. + scroll_marker.append('
'); + last_mark = $('#m' + line_number); + last_mark.css({ + 'height': line_height, + 'top': line_top + }); + last_top = line_top; + } + + previous_line = line_number; + }); +}; diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/favicon_32.png b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/favicon_32.png new file mode 100644 index 000000000..8649f0475 Binary files /dev/null and b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/favicon_32.png differ diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/index.html b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/index.html new file mode 100644 index 000000000..983db0612 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/index.html @@ -0,0 +1,119 @@ +{# Licensed under the Apache License: http://www.apache.org/licenses/LICENSE-2.0 #} +{# For details: https://github.com/nedbat/coveragepy/blob/master/NOTICE.txt #} + + + + + + {{ title|escape }} + + + {% if extra_css %} + + {% endif %} + + + + + + + + + + + +
+ Hide keyboard shortcuts +

Hot-keys on this page

+
+

+ n + s + m + x + {% if has_arcs %} + b + p + {% endif %} + c   change column sorting +

+
+
+ +
+ + + {# The title="" attr doesn"t work in Safari. #} + + + + + + {% if has_arcs %} + + + {% endif %} + + + + {# HTML syntax requires thead, tfoot, tbody #} + + + + + + + {% if has_arcs %} + + + {% endif %} + + + + + {% for file in files %} + + + + + + {% if has_arcs %} + + + {% endif %} + + + {% endfor %} + +
Modulestatementsmissingexcludedbranchespartialcoverage
Total{{totals.n_statements}}{{totals.n_missing}}{{totals.n_excluded}}{{totals.n_branches}}{{totals.n_partial_branches}}{{totals.pc_covered_str}}%
{{file.relative_filename}}{{file.nums.n_statements}}{{file.nums.n_missing}}{{file.nums.n_excluded}}{{file.nums.n_branches}}{{file.nums.n_partial_branches}}{{file.nums.pc_covered_str}}%
+ +

+ No items found using the specified filter. +

+
+ + + + + diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/jquery.ba-throttle-debounce.min.js b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/jquery.ba-throttle-debounce.min.js new file mode 100644 index 000000000..648fe5d3c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/jquery.ba-throttle-debounce.min.js @@ -0,0 +1,9 @@ +/* + * jQuery throttle / debounce - v1.1 - 3/7/2010 + * http://benalman.com/projects/jquery-throttle-debounce-plugin/ + * + * Copyright (c) 2010 "Cowboy" Ben Alman + * Dual licensed under the MIT and GPL licenses. + * http://benalman.com/about/license/ + */ +(function(b,c){var $=b.jQuery||b.Cowboy||(b.Cowboy={}),a;$.throttle=a=function(e,f,j,i){var h,d=0;if(typeof f!=="boolean"){i=j;j=f;f=c}function g(){var o=this,m=+new Date()-d,n=arguments;function l(){d=+new Date();j.apply(o,n)}function k(){h=c}if(i&&!h){l()}h&&clearTimeout(h);if(i===c&&m>e){l()}else{if(f!==true){h=setTimeout(i?k:l,i===c?e-m:e)}}}if($.guid){g.guid=j.guid=j.guid||$.guid++}return g};$.debounce=function(d,e,f){return f===c?a(d,e,false):a(d,f,e!==false)}})(this); diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/jquery.hotkeys.js b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/jquery.hotkeys.js new file mode 100644 index 000000000..09b21e03c --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/jquery.hotkeys.js @@ -0,0 +1,99 @@ +/* + * jQuery Hotkeys Plugin + * Copyright 2010, John Resig + * Dual licensed under the MIT or GPL Version 2 licenses. + * + * Based upon the plugin by Tzury Bar Yochay: + * http://github.com/tzuryby/hotkeys + * + * Original idea by: + * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/ +*/ + +(function(jQuery){ + + jQuery.hotkeys = { + version: "0.8", + + specialKeys: { + 8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause", + 20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home", + 37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del", + 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7", + 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/", + 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8", + 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta" + }, + + shiftNums: { + "`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&", + "8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<", + ".": ">", "/": "?", "\\": "|" + } + }; + + function keyHandler( handleObj ) { + // Only care when a possible input has been specified + if ( typeof handleObj.data !== "string" ) { + return; + } + + var origHandler = handleObj.handler, + keys = handleObj.data.toLowerCase().split(" "); + + handleObj.handler = function( event ) { + // Don't fire in text-accepting inputs that we didn't directly bind to + if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) || + event.target.type === "text") ) { + return; + } + + // Keypress represents characters, not special keys + var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ], + character = String.fromCharCode( event.which ).toLowerCase(), + key, modif = "", possible = {}; + + // check combinations (alt|ctrl|shift+anything) + if ( event.altKey && special !== "alt" ) { + modif += "alt+"; + } + + if ( event.ctrlKey && special !== "ctrl" ) { + modif += "ctrl+"; + } + + // TODO: Need to make sure this works consistently across platforms + if ( event.metaKey && !event.ctrlKey && special !== "meta" ) { + modif += "meta+"; + } + + if ( event.shiftKey && special !== "shift" ) { + modif += "shift+"; + } + + if ( special ) { + possible[ modif + special ] = true; + + } else { + possible[ modif + character ] = true; + possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true; + + // "$" can be triggered as "Shift+4" or "Shift+$" or just "$" + if ( modif === "shift+" ) { + possible[ jQuery.hotkeys.shiftNums[ character ] ] = true; + } + } + + for ( var i = 0, l = keys.length; i < l; i++ ) { + if ( possible[ keys[i] ] ) { + return origHandler.apply( this, arguments ); + } + } + }; + } + + jQuery.each([ "keydown", "keyup", "keypress" ], function() { + jQuery.event.special[ this ] = { add: keyHandler }; + }); + +})( jQuery ); diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/jquery.isonscreen.js b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/jquery.isonscreen.js new file mode 100644 index 000000000..0182ebd21 --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/jquery.isonscreen.js @@ -0,0 +1,53 @@ +/* Copyright (c) 2010 + * @author Laurence Wheway + * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php) + * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses. + * + * @version 1.2.0 + */ +(function($) { + jQuery.extend({ + isOnScreen: function(box, container) { + //ensure numbers come in as intgers (not strings) and remove 'px' is it's there + for(var i in box){box[i] = parseFloat(box[i])}; + for(var i in container){container[i] = parseFloat(container[i])}; + + if(!container){ + container = { + left: $(window).scrollLeft(), + top: $(window).scrollTop(), + width: $(window).width(), + height: $(window).height() + } + } + + if( box.left+box.width-container.left > 0 && + box.left < container.width+container.left && + box.top+box.height-container.top > 0 && + box.top < container.height+container.top + ) return true; + return false; + } + }) + + + jQuery.fn.isOnScreen = function (container) { + for(var i in container){container[i] = parseFloat(container[i])}; + + if(!container){ + container = { + left: $(window).scrollLeft(), + top: $(window).scrollTop(), + width: $(window).width(), + height: $(window).height() + } + } + + if( $(this).offset().left+$(this).width()-container.left > 0 && + $(this).offset().left < container.width+container.left && + $(this).offset().top+$(this).height()-container.top > 0 && + $(this).offset().top < container.height+container.top + ) return true; + return false; + } +})(jQuery); diff --git a/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/jquery.min.js b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/jquery.min.js new file mode 100644 index 000000000..d1608e37f --- /dev/null +++ b/inbm/venv-3.11/lib/python3.11/site-packages/coverage/htmlfiles/jquery.min.js @@ -0,0 +1,4 @@ +/*! jQuery v1.11.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */ +!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l="1.11.1",m=function(a,b){return new m.fn.init(a,b)},n=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,o=/^-ms-/,p=/-([\da-z])/gi,q=function(a,b){return b.toUpperCase()};m.fn=m.prototype={jquery:l,constructor:m,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=m.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return m.each(this,a,b)},map:function(a){return this.pushStack(m.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},m.extend=m.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||m.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(m.isPlainObject(c)||(b=m.isArray(c)))?(b?(b=!1,f=a&&m.isArray(a)?a:[]):f=a&&m.isPlainObject(a)?a:{},g[d]=m.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},m.extend({expando:"jQuery"+(l+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===m.type(a)},isArray:Array.isArray||function(a){return"array"===m.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){return!m.isArray(a)&&a-parseFloat(a)>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==m.type(a)||a.nodeType||m.isWindow(a))return!1;try{if(a.constructor&&!j.call(a,"constructor")&&!j.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(k.ownLast)for(b in a)return j.call(a,b);for(b in a);return void 0===b||j.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(b){b&&m.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(o,"ms-").replace(p,q)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=r(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(n,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(r(Object(a))?m.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(g)return g.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=r(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(f=a[b],b=a,a=f),m.isFunction(a)?(c=d.call(arguments,2),e=function(){return a.apply(b||this,c.concat(d.call(arguments)))},e.guid=a.guid=a.guid||m.guid++,e):void 0},now:function(){return+new Date},support:k}),m.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function r(a){var b=a.length,c=m.type(a);return"function"===c||m.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var s=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="
",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++db;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);m.find=s,m.expr=s.selectors,m.expr[":"]=m.expr.pseudos,m.unique=s.uniqueSort,m.text=s.getText,m.isXMLDoc=s.isXML,m.contains=s.contains;var t=m.expr.match.needsContext,u=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,v=/^.[^:#\[\.,]*$/;function w(a,b,c){if(m.isFunction(b))return m.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return m.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(v.test(b))return m.filter(b,a,c);b=m.filter(b,a)}return m.grep(a,function(a){return m.inArray(a,b)>=0!==c})}m.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?m.find.matchesSelector(d,a)?[d]:[]:m.find.matches(a,m.grep(b,function(a){return 1===a.nodeType}))},m.fn.extend({find:function(a){var b,c=[],d=this,e=d.length;if("string"!=typeof a)return this.pushStack(m(a).filter(function(){for(b=0;e>b;b++)if(m.contains(d[b],this))return!0}));for(b=0;e>b;b++)m.find(a,d[b],c);return c=this.pushStack(e>1?m.unique(c):c),c.selector=this.selector?this.selector+" "+a:a,c},filter:function(a){return this.pushStack(w(this,a||[],!1))},not:function(a){return this.pushStack(w(this,a||[],!0))},is:function(a){return!!w(this,"string"==typeof a&&t.test(a)?m(a):a||[],!1).length}});var x,y=a.document,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=m.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||x).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof m?b[0]:b,m.merge(this,m.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:y,!0)),u.test(c[1])&&m.isPlainObject(b))for(c in b)m.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}if(d=y.getElementById(c[2]),d&&d.parentNode){if(d.id!==c[2])return x.find(a);this.length=1,this[0]=d}return this.context=y,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):m.isFunction(a)?"undefined"!=typeof x.ready?x.ready(a):a(m):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),m.makeArray(a,this))};A.prototype=m.fn,x=m(y);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};m.extend({dir:function(a,b,c){var d=[],e=a[b];while(e&&9!==e.nodeType&&(void 0===c||1!==e.nodeType||!m(e).is(c)))1===e.nodeType&&d.push(e),e=e[b];return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),m.fn.extend({has:function(a){var b,c=m(a,this),d=c.length;return this.filter(function(){for(b=0;d>b;b++)if(m.contains(this,c[b]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=t.test(a)||"string"!=typeof a?m(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&m.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?m.unique(f):f)},index:function(a){return a?"string"==typeof a?m.inArray(this[0],m(a)):m.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(m.unique(m.merge(this.get(),m(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){do a=a[b];while(a&&1!==a.nodeType);return a}m.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return m.dir(a,"parentNode")},parentsUntil:function(a,b,c){return m.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return m.dir(a,"nextSibling")},prevAll:function(a){return m.dir(a,"previousSibling")},nextUntil:function(a,b,c){return m.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return m.dir(a,"previousSibling",c)},siblings:function(a){return m.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return m.sibling(a.firstChild)},contents:function(a){return m.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:m.merge([],a.childNodes)}},function(a,b){m.fn[a]=function(c,d){var e=m.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=m.filter(d,e)),this.length>1&&(C[a]||(e=m.unique(e)),B.test(a)&&(e=e.reverse())),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return m.each(a.match(E)||[],function(a,c){b[c]=!0}),b}m.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):m.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(c=a.memory&&l,d=!0,f=g||0,g=0,e=h.length,b=!0;h&&e>f;f++)if(h[f].apply(l[0],l[1])===!1&&a.stopOnFalse){c=!1;break}b=!1,h&&(i?i.length&&j(i.shift()):c?h=[]:k.disable())},k={add:function(){if(h){var d=h.length;!function f(b){m.each(b,function(b,c){var d=m.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&f(c)})}(arguments),b?e=h.length:c&&(g=d,j(c))}return this},remove:function(){return h&&m.each(arguments,function(a,c){var d;while((d=m.inArray(c,h,d))>-1)h.splice(d,1),b&&(e>=d&&e--,f>=d&&f--)}),this},has:function(a){return a?m.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],e=0,this},disable:function(){return h=i=c=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,c||k.disable(),this},locked:function(){return!i},fireWith:function(a,c){return!h||d&&!i||(c=c||[],c=[a,c.slice?c.slice():c],b?i.push(c):j(c)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!d}};return k},m.extend({Deferred:function(a){var b=[["resolve","done",m.Callbacks("once memory"),"resolved"],["reject","fail",m.Callbacks("once memory"),"rejected"],["notify","progress",m.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return m.Deferred(function(c){m.each(b,function(b,f){var g=m.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&m.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?m.extend(a,d):d}},e={};return d.pipe=d.then,m.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&m.isFunction(a.promise)?e:0,g=1===f?a:m.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&m.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;m.fn.ready=function(a){return m.ready.promise().done(a),this},m.extend({isReady:!1,readyWait:1,holdReady:function(a){a?m.readyWait++:m.ready(!0)},ready:function(a){if(a===!0?!--m.readyWait:!m.isReady){if(!y.body)return setTimeout(m.ready);m.isReady=!0,a!==!0&&--m.readyWait>0||(H.resolveWith(y,[m]),m.fn.triggerHandler&&(m(y).triggerHandler("ready"),m(y).off("ready")))}}});function I(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",J,!1),a.removeEventListener("load",J,!1)):(y.detachEvent("onreadystatechange",J),a.detachEvent("onload",J))}function J(){(y.addEventListener||"load"===event.type||"complete"===y.readyState)&&(I(),m.ready())}m.ready.promise=function(b){if(!H)if(H=m.Deferred(),"complete"===y.readyState)setTimeout(m.ready);else if(y.addEventListener)y.addEventListener("DOMContentLoaded",J,!1),a.addEventListener("load",J,!1);else{y.attachEvent("onreadystatechange",J),a.attachEvent("onload",J);var c=!1;try{c=null==a.frameElement&&y.documentElement}catch(d){}c&&c.doScroll&&!function e(){if(!m.isReady){try{c.doScroll("left")}catch(a){return setTimeout(e,50)}I(),m.ready()}}()}return H.promise(b)};var K="undefined",L;for(L in m(k))break;k.ownLast="0"!==L,k.inlineBlockNeedsLayout=!1,m(function(){var a,b,c,d;c=y.getElementsByTagName("body")[0],c&&c.style&&(b=y.createElement("div"),d=y.createElement("div"),d.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(d).appendChild(b),typeof b.style.zoom!==K&&(b.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",k.inlineBlockNeedsLayout=a=3===b.offsetWidth,a&&(c.style.zoom=1)),c.removeChild(d))}),function(){var a=y.createElement("div");if(null==k.deleteExpando){k.deleteExpando=!0;try{delete a.test}catch(b){k.deleteExpando=!1}}a=null}(),m.acceptData=function(a){var b=m.noData[(a.nodeName+" ").toLowerCase()],c=+a.nodeType||1;return 1!==c&&9!==c?!1:!b||b!==!0&&a.getAttribute("classid")===b};var M=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,N=/([A-Z])/g;function O(a,b,c){if(void 0===c&&1===a.nodeType){var d="data-"+b.replace(N,"-$1").toLowerCase();if(c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:M.test(c)?m.parseJSON(c):c}catch(e){}m.data(a,b,c)}else c=void 0}return c}function P(a){var b;for(b in a)if(("data"!==b||!m.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function Q(a,b,d,e){if(m.acceptData(a)){var f,g,h=m.expando,i=a.nodeType,j=i?m.cache:a,k=i?a[h]:a[h]&&h; +if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||m.guid++:h),j[k]||(j[k]=i?{}:{toJSON:m.noop}),("object"==typeof b||"function"==typeof b)&&(e?j[k]=m.extend(j[k],b):j[k].data=m.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[m.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[m.camelCase(b)])):f=g,f}}function R(a,b,c){if(m.acceptData(a)){var d,e,f=a.nodeType,g=f?m.cache:a,h=f?a[m.expando]:m.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){m.isArray(b)?b=b.concat(m.map(b,m.camelCase)):b in d?b=[b]:(b=m.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!P(d):!m.isEmptyObject(d))return}(c||(delete g[h].data,P(g[h])))&&(f?m.cleanData([a],!0):k.deleteExpando||g!=g.window?delete g[h]:g[h]=null)}}}m.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?m.cache[a[m.expando]]:a[m.expando],!!a&&!P(a)},data:function(a,b,c){return Q(a,b,c)},removeData:function(a,b){return R(a,b)},_data:function(a,b,c){return Q(a,b,c,!0)},_removeData:function(a,b){return R(a,b,!0)}}),m.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=m.data(f),1===f.nodeType&&!m._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=m.camelCase(d.slice(5)),O(f,d,e[d])));m._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){m.data(this,a)}):arguments.length>1?this.each(function(){m.data(this,a,b)}):f?O(f,a,m.data(f,a)):void 0},removeData:function(a){return this.each(function(){m.removeData(this,a)})}}),m.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=m._data(a,b),c&&(!d||m.isArray(c)?d=m._data(a,b,m.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=m.queue(a,b),d=c.length,e=c.shift(),f=m._queueHooks(a,b),g=function(){m.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return m._data(a,c)||m._data(a,c,{empty:m.Callbacks("once memory").add(function(){m._removeData(a,b+"queue"),m._removeData(a,c)})})}}),m.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.lengthh;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},W=/^(?:checkbox|radio)$/i;!function(){var a=y.createElement("input"),b=y.createElement("div"),c=y.createDocumentFragment();if(b.innerHTML="
a",k.leadingWhitespace=3===b.firstChild.nodeType,k.tbody=!b.getElementsByTagName("tbody").length,k.htmlSerialize=!!b.getElementsByTagName("link").length,k.html5Clone="<:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML,a.type="checkbox",a.checked=!0,c.appendChild(a),k.appendChecked=a.checked,b.innerHTML="",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue,c.appendChild(b),b.innerHTML="",k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,k.noCloneEvent=!0,b.attachEvent&&(b.attachEvent("onclick",function(){k.noCloneEvent=!1}),b.cloneNode(!0).click()),null==k.deleteExpando){k.deleteExpando=!0;try{delete b.test}catch(d){k.deleteExpando=!1}}}(),function(){var b,c,d=y.createElement("div");for(b in{submit:!0,change:!0,focusin:!0})c="on"+b,(k[b+"Bubbles"]=c in a)||(d.setAttribute(c,"t"),k[b+"Bubbles"]=d.attributes[c].expando===!1);d=null}();var X=/^(?:input|select|textarea)$/i,Y=/^key/,Z=/^(?:mouse|pointer|contextmenu)|click/,$=/^(?:focusinfocus|focusoutblur)$/,_=/^([^.]*)(?:\.(.+)|)$/;function ab(){return!0}function bb(){return!1}function cb(){try{return y.activeElement}catch(a){}}m.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m._data(a);if(r){c.handler&&(i=c,c=i.handler,e=i.selector),c.guid||(c.guid=m.guid++),(g=r.events)||(g=r.events={}),(k=r.handle)||(k=r.handle=function(a){return typeof m===K||a&&m.event.triggered===a.type?void 0:m.event.dispatch.apply(k.elem,arguments)},k.elem=a),b=(b||"").match(E)||[""],h=b.length;while(h--)f=_.exec(b[h])||[],o=q=f[1],p=(f[2]||"").split(".").sort(),o&&(j=m.event.special[o]||{},o=(e?j.delegateType:j.bindType)||o,j=m.event.special[o]||{},l=m.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&m.expr.match.needsContext.test(e),namespace:p.join(".")},i),(n=g[o])||(n=g[o]=[],n.delegateCount=0,j.setup&&j.setup.call(a,d,p,k)!==!1||(a.addEventListener?a.addEventListener(o,k,!1):a.attachEvent&&a.attachEvent("on"+o,k))),j.add&&(j.add.call(a,l),l.handler.guid||(l.handler.guid=c.guid)),e?n.splice(n.delegateCount++,0,l):n.push(l),m.event.global[o]=!0);a=null}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,n,o,p,q,r=m.hasData(a)&&m._data(a);if(r&&(k=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=_.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=m.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,n=k[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),i=f=n.length;while(f--)g=n[f],!e&&q!==g.origType||c&&c.guid!==g.guid||h&&!h.test(g.namespace)||d&&d!==g.selector&&("**"!==d||!g.selector)||(n.splice(f,1),g.selector&&n.delegateCount--,l.remove&&l.remove.call(a,g));i&&!n.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||m.removeEvent(a,o,r.handle),delete k[o])}else for(o in k)m.event.remove(a,o+b[j],c,d,!0);m.isEmptyObject(k)&&(delete r.handle,m._removeData(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,l,n,o=[d||y],p=j.call(b,"type")?b.type:b,q=j.call(b,"namespace")?b.namespace.split("."):[];if(h=l=d=d||y,3!==d.nodeType&&8!==d.nodeType&&!$.test(p+m.event.triggered)&&(p.indexOf(".")>=0&&(q=p.split("."),p=q.shift(),q.sort()),g=p.indexOf(":")<0&&"on"+p,b=b[m.expando]?b:new m.Event(p,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=q.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:m.makeArray(c,[b]),k=m.event.special[p]||{},e||!k.trigger||k.trigger.apply(d,c)!==!1)){if(!e&&!k.noBubble&&!m.isWindow(d)){for(i=k.delegateType||p,$.test(i+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),l=h;l===(d.ownerDocument||y)&&o.push(l.defaultView||l.parentWindow||a)}n=0;while((h=o[n++])&&!b.isPropagationStopped())b.type=n>1?i:k.bindType||p,f=(m._data(h,"events")||{})[b.type]&&m._data(h,"handle"),f&&f.apply(h,c),f=g&&h[g],f&&f.apply&&m.acceptData(h)&&(b.result=f.apply(h,c),b.result===!1&&b.preventDefault());if(b.type=p,!e&&!b.isDefaultPrevented()&&(!k._default||k._default.apply(o.pop(),c)===!1)&&m.acceptData(d)&&g&&d[p]&&!m.isWindow(d)){l=d[g],l&&(d[g]=null),m.event.triggered=p;try{d[p]()}catch(r){}m.event.triggered=void 0,l&&(d[g]=l)}return b.result}},dispatch:function(a){a=m.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(m._data(this,"events")||{})[a.type]||[],k=m.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=m.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,g=0;while((e=f.handlers[g++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(e.namespace))&&(a.handleObj=e,a.data=e.data,c=((m.event.special[e.origType]||{}).handle||e.handler).apply(f.elem,i),void 0!==c&&(a.result=c)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!=this;i=i.parentNode||this)if(1===i.nodeType&&(i.disabled!==!0||"click"!==a.type)){for(e=[],f=0;h>f;f++)d=b[f],c=d.selector+" ",void 0===e[c]&&(e[c]=d.needsContext?m(c,this).index(i)>=0:m.find(c,this,null,[i]).length),e[c]&&e.push(d);e.length&&g.push({elem:i,handlers:e})}return h]","i"),hb=/^\s+/,ib=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,jb=/<([\w:]+)/,kb=/\s*$/g,rb={option:[1,""],legend:[1,"
","
"],area:[1,"",""],param:[1,"",""],thead:[1,"","
"],tr:[2,"","
"],col:[2,"","
"],td:[3,"","
"],_default:k.htmlSerialize?[0,"",""]:[1,"X
","
"]},sb=db(y),tb=sb.appendChild(y.createElement("div"));rb.optgroup=rb.option,rb.tbody=rb.tfoot=rb.colgroup=rb.caption=rb.thead,rb.th=rb.td;function ub(a,b){var c,d,e=0,f=typeof a.getElementsByTagName!==K?a.getElementsByTagName(b||"*"):typeof a.querySelectorAll!==K?a.querySelectorAll(b||"*"):void 0;if(!f)for(f=[],c=a.childNodes||a;null!=(d=c[e]);e++)!b||m.nodeName(d,b)?f.push(d):m.merge(f,ub(d,b));return void 0===b||b&&m.nodeName(a,b)?m.merge([a],f):f}function vb(a){W.test(a.type)&&(a.defaultChecked=a.checked)}function wb(a,b){return m.nodeName(a,"table")&&m.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function xb(a){return a.type=(null!==m.find.attr(a,"type"))+"/"+a.type,a}function yb(a){var b=pb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function zb(a,b){for(var c,d=0;null!=(c=a[d]);d++)m._data(c,"globalEval",!b||m._data(b[d],"globalEval"))}function Ab(a,b){if(1===b.nodeType&&m.hasData(a)){var c,d,e,f=m._data(a),g=m._data(b,f),h=f.events;if(h){delete g.handle,g.events={};for(c in h)for(d=0,e=h[c].length;e>d;d++)m.event.add(b,c,h[c][d])}g.data&&(g.data=m.extend({},g.data))}}function Bb(a,b){var c,d,e;if(1===b.nodeType){if(c=b.nodeName.toLowerCase(),!k.noCloneEvent&&b[m.expando]){e=m._data(b);for(d in e.events)m.removeEvent(b,d,e.handle);b.removeAttribute(m.expando)}"script"===c&&b.text!==a.text?(xb(b).text=a.text,yb(b)):"object"===c?(b.parentNode&&(b.outerHTML=a.outerHTML),k.html5Clone&&a.innerHTML&&!m.trim(b.innerHTML)&&(b.innerHTML=a.innerHTML)):"input"===c&&W.test(a.type)?(b.defaultChecked=b.checked=a.checked,b.value!==a.value&&(b.value=a.value)):"option"===c?b.defaultSelected=b.selected=a.defaultSelected:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}}m.extend({clone:function(a,b,c){var d,e,f,g,h,i=m.contains(a.ownerDocument,a);if(k.html5Clone||m.isXMLDoc(a)||!gb.test("<"+a.nodeName+">")?f=a.cloneNode(!0):(tb.innerHTML=a.outerHTML,tb.removeChild(f=tb.firstChild)),!(k.noCloneEvent&&k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||m.isXMLDoc(a)))for(d=ub(f),h=ub(a),g=0;null!=(e=h[g]);++g)d[g]&&Bb(e,d[g]);if(b)if(c)for(h=h||ub(a),d=d||ub(f),g=0;null!=(e=h[g]);g++)Ab(e,d[g]);else Ab(a,f);return d=ub(f,"script"),d.length>0&&zb(d,!i&&ub(a,"script")),d=h=e=null,f},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,l,n=a.length,o=db(b),p=[],q=0;n>q;q++)if(f=a[q],f||0===f)if("object"===m.type(f))m.merge(p,f.nodeType?[f]:f);else if(lb.test(f)){h=h||o.appendChild(b.createElement("div")),i=(jb.exec(f)||["",""])[1].toLowerCase(),l=rb[i]||rb._default,h.innerHTML=l[1]+f.replace(ib,"<$1>")+l[2],e=l[0];while(e--)h=h.lastChild;if(!k.leadingWhitespace&&hb.test(f)&&p.push(b.createTextNode(hb.exec(f)[0])),!k.tbody){f="table"!==i||kb.test(f)?""!==l[1]||kb.test(f)?0:h:h.firstChild,e=f&&f.childNodes.length;while(e--)m.nodeName(j=f.childNodes[e],"tbody")&&!j.childNodes.length&&f.removeChild(j)}m.merge(p,h.childNodes),h.textContent="";while(h.firstChild)h.removeChild(h.firstChild);h=o.lastChild}else p.push(b.createTextNode(f));h&&o.removeChild(h),k.appendChecked||m.grep(ub(p,"input"),vb),q=0;while(f=p[q++])if((!d||-1===m.inArray(f,d))&&(g=m.contains(f.ownerDocument,f),h=ub(o.appendChild(f),"script"),g&&zb(h),c)){e=0;while(f=h[e++])ob.test(f.type||"")&&c.push(f)}return h=null,o},cleanData:function(a,b){for(var d,e,f,g,h=0,i=m.expando,j=m.cache,l=k.deleteExpando,n=m.event.special;null!=(d=a[h]);h++)if((b||m.acceptData(d))&&(f=d[i],g=f&&j[f])){if(g.events)for(e in g.events)n[e]?m.event.remove(d,e):m.removeEvent(d,e,g.handle);j[f]&&(delete j[f],l?delete d[i]:typeof d.removeAttribute!==K?d.removeAttribute(i):d[i]=null,c.push(f))}}}),m.fn.extend({text:function(a){return V(this,function(a){return void 0===a?m.text(this):this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=wb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?m.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||m.cleanData(ub(c)),c.parentNode&&(b&&m.contains(c.ownerDocument,c)&&zb(ub(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){1===a.nodeType&&m.cleanData(ub(a,!1));while(a.firstChild)a.removeChild(a.firstChild);a.options&&m.nodeName(a,"select")&&(a.options.length=0)}return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return m.clone(this,a,b)})},html:function(a){return V(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a)return 1===b.nodeType?b.innerHTML.replace(fb,""):void 0;if(!("string"!=typeof a||mb.test(a)||!k.htmlSerialize&&gb.test(a)||!k.leadingWhitespace&&hb.test(a)||rb[(jb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(ib,"<$1>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(m.cleanData(ub(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,m.cleanData(ub(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,n=this,o=l-1,p=a[0],q=m.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&nb.test(p))return this.each(function(c){var d=n.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(i=m.buildFragment(a,this[0].ownerDocument,!1,this),c=i.firstChild,1===i.childNodes.length&&(i=c),c)){for(g=m.map(ub(i,"script"),xb),f=g.length;l>j;j++)d=i,j!==o&&(d=m.clone(d,!0,!0),f&&m.merge(g,ub(d,"script"))),b.call(this[j],d,j);if(f)for(h=g[g.length-1].ownerDocument,m.map(g,yb),j=0;f>j;j++)d=g[j],ob.test(d.type||"")&&!m._data(d,"globalEval")&&m.contains(h,d)&&(d.src?m._evalUrl&&m._evalUrl(d.src):m.globalEval((d.text||d.textContent||d.innerHTML||"").replace(qb,"")));i=c=null}return this}}),m.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){m.fn[a]=function(a){for(var c,d=0,e=[],g=m(a),h=g.length-1;h>=d;d++)c=d===h?this:this.clone(!0),m(g[d])[b](c),f.apply(e,c.get());return this.pushStack(e)}});var Cb,Db={};function Eb(b,c){var d,e=m(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:m.css(e[0],"display");return e.detach(),f}function Fb(a){var b=y,c=Db[a];return c||(c=Eb(a,b),"none"!==c&&c||(Cb=(Cb||m("