mirror of
https://github.com/EvolutionAPI/evolution-client-python.git
synced 2025-12-12 11:29:34 -06:00
fix: remove cached env folder
This commit is contained in:
parent
f3001d6496
commit
a53948d4bf
247
env/bin/Activate.ps1
vendored
247
env/bin/Activate.ps1
vendored
@ -1,247 +0,0 @@
|
||||
<#
|
||||
.Synopsis
|
||||
Activate a Python virtual environment for the current PowerShell session.
|
||||
|
||||
.Description
|
||||
Pushes the python executable for a virtual environment to the front of the
|
||||
$Env:PATH environment variable and sets the prompt to signify that you are
|
||||
in a Python virtual environment. Makes use of the command line switches as
|
||||
well as the `pyvenv.cfg` file values present in the virtual environment.
|
||||
|
||||
.Parameter VenvDir
|
||||
Path to the directory that contains the virtual environment to activate. The
|
||||
default value for this is the parent of the directory that the Activate.ps1
|
||||
script is located within.
|
||||
|
||||
.Parameter Prompt
|
||||
The prompt prefix to display when this virtual environment is activated. By
|
||||
default, this prompt is the name of the virtual environment folder (VenvDir)
|
||||
surrounded by parentheses and followed by a single space (ie. '(.venv) ').
|
||||
|
||||
.Example
|
||||
Activate.ps1
|
||||
Activates the Python virtual environment that contains the Activate.ps1 script.
|
||||
|
||||
.Example
|
||||
Activate.ps1 -Verbose
|
||||
Activates the Python virtual environment that contains the Activate.ps1 script,
|
||||
and shows extra information about the activation as it executes.
|
||||
|
||||
.Example
|
||||
Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv
|
||||
Activates the Python virtual environment located in the specified location.
|
||||
|
||||
.Example
|
||||
Activate.ps1 -Prompt "MyPython"
|
||||
Activates the Python virtual environment that contains the Activate.ps1 script,
|
||||
and prefixes the current prompt with the specified string (surrounded in
|
||||
parentheses) while the virtual environment is active.
|
||||
|
||||
.Notes
|
||||
On Windows, it may be required to enable this Activate.ps1 script by setting the
|
||||
execution policy for the user. You can do this by issuing the following PowerShell
|
||||
command:
|
||||
|
||||
PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
|
||||
|
||||
For more information on Execution Policies:
|
||||
https://go.microsoft.com/fwlink/?LinkID=135170
|
||||
|
||||
#>
|
||||
Param(
|
||||
[Parameter(Mandatory = $false)]
|
||||
[String]
|
||||
$VenvDir,
|
||||
[Parameter(Mandatory = $false)]
|
||||
[String]
|
||||
$Prompt
|
||||
)
|
||||
|
||||
<# Function declarations --------------------------------------------------- #>
|
||||
|
||||
<#
|
||||
.Synopsis
|
||||
Remove all shell session elements added by the Activate script, including the
|
||||
addition of the virtual environment's Python executable from the beginning of
|
||||
the PATH variable.
|
||||
|
||||
.Parameter NonDestructive
|
||||
If present, do not remove this function from the global namespace for the
|
||||
session.
|
||||
|
||||
#>
|
||||
function global:deactivate ([switch]$NonDestructive) {
|
||||
# Revert to original values
|
||||
|
||||
# The prior prompt:
|
||||
if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) {
|
||||
Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt
|
||||
Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT
|
||||
}
|
||||
|
||||
# The prior PYTHONHOME:
|
||||
if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) {
|
||||
Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME
|
||||
Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME
|
||||
}
|
||||
|
||||
# The prior PATH:
|
||||
if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) {
|
||||
Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH
|
||||
Remove-Item -Path Env:_OLD_VIRTUAL_PATH
|
||||
}
|
||||
|
||||
# Just remove the VIRTUAL_ENV altogether:
|
||||
if (Test-Path -Path Env:VIRTUAL_ENV) {
|
||||
Remove-Item -Path env:VIRTUAL_ENV
|
||||
}
|
||||
|
||||
# Just remove VIRTUAL_ENV_PROMPT altogether.
|
||||
if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) {
|
||||
Remove-Item -Path env:VIRTUAL_ENV_PROMPT
|
||||
}
|
||||
|
||||
# Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether:
|
||||
if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) {
|
||||
Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force
|
||||
}
|
||||
|
||||
# Leave deactivate function in the global namespace if requested:
|
||||
if (-not $NonDestructive) {
|
||||
Remove-Item -Path function:deactivate
|
||||
}
|
||||
}
|
||||
|
||||
<#
|
||||
.Description
|
||||
Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the
|
||||
given folder, and returns them in a map.
|
||||
|
||||
For each line in the pyvenv.cfg file, if that line can be parsed into exactly
|
||||
two strings separated by `=` (with any amount of whitespace surrounding the =)
|
||||
then it is considered a `key = value` line. The left hand string is the key,
|
||||
the right hand is the value.
|
||||
|
||||
If the value starts with a `'` or a `"` then the first and last character is
|
||||
stripped from the value before being captured.
|
||||
|
||||
.Parameter ConfigDir
|
||||
Path to the directory that contains the `pyvenv.cfg` file.
|
||||
#>
|
||||
function Get-PyVenvConfig(
|
||||
[String]
|
||||
$ConfigDir
|
||||
) {
|
||||
Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg"
|
||||
|
||||
# Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue).
|
||||
$pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue
|
||||
|
||||
# An empty map will be returned if no config file is found.
|
||||
$pyvenvConfig = @{ }
|
||||
|
||||
if ($pyvenvConfigPath) {
|
||||
|
||||
Write-Verbose "File exists, parse `key = value` lines"
|
||||
$pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath
|
||||
|
||||
$pyvenvConfigContent | ForEach-Object {
|
||||
$keyval = $PSItem -split "\s*=\s*", 2
|
||||
if ($keyval[0] -and $keyval[1]) {
|
||||
$val = $keyval[1]
|
||||
|
||||
# Remove extraneous quotations around a string value.
|
||||
if ("'""".Contains($val.Substring(0, 1))) {
|
||||
$val = $val.Substring(1, $val.Length - 2)
|
||||
}
|
||||
|
||||
$pyvenvConfig[$keyval[0]] = $val
|
||||
Write-Verbose "Adding Key: '$($keyval[0])'='$val'"
|
||||
}
|
||||
}
|
||||
}
|
||||
return $pyvenvConfig
|
||||
}
|
||||
|
||||
|
||||
<# Begin Activate script --------------------------------------------------- #>
|
||||
|
||||
# Determine the containing directory of this script
|
||||
$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||
$VenvExecDir = Get-Item -Path $VenvExecPath
|
||||
|
||||
Write-Verbose "Activation script is located in path: '$VenvExecPath'"
|
||||
Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)"
|
||||
Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
|
||||
|
||||
# Set values required in priority: CmdLine, ConfigFile, Default
|
||||
# First, get the location of the virtual environment, it might not be
|
||||
# VenvExecDir if specified on the command line.
|
||||
if ($VenvDir) {
|
||||
Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
|
||||
}
|
||||
else {
|
||||
Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
|
||||
$VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
|
||||
Write-Verbose "VenvDir=$VenvDir"
|
||||
}
|
||||
|
||||
# Next, read the `pyvenv.cfg` file to determine any required value such
|
||||
# as `prompt`.
|
||||
$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
|
||||
|
||||
# Next, set the prompt from the command line, or the config file, or
|
||||
# just use the name of the virtual environment folder.
|
||||
if ($Prompt) {
|
||||
Write-Verbose "Prompt specified as argument, using '$Prompt'"
|
||||
}
|
||||
else {
|
||||
Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value"
|
||||
if ($pyvenvCfg -and $pyvenvCfg['prompt']) {
|
||||
Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'"
|
||||
$Prompt = $pyvenvCfg['prompt'];
|
||||
}
|
||||
else {
|
||||
Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)"
|
||||
Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'"
|
||||
$Prompt = Split-Path -Path $venvDir -Leaf
|
||||
}
|
||||
}
|
||||
|
||||
Write-Verbose "Prompt = '$Prompt'"
|
||||
Write-Verbose "VenvDir='$VenvDir'"
|
||||
|
||||
# Deactivate any currently active virtual environment, but leave the
|
||||
# deactivate function in place.
|
||||
deactivate -nondestructive
|
||||
|
||||
# Now set the environment variable VIRTUAL_ENV, used by many tools to determine
|
||||
# that there is an activated venv.
|
||||
$env:VIRTUAL_ENV = $VenvDir
|
||||
|
||||
if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) {
|
||||
|
||||
Write-Verbose "Setting prompt to '$Prompt'"
|
||||
|
||||
# Set the prompt to include the env name
|
||||
# Make sure _OLD_VIRTUAL_PROMPT is global
|
||||
function global:_OLD_VIRTUAL_PROMPT { "" }
|
||||
Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT
|
||||
New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt
|
||||
|
||||
function global:prompt {
|
||||
Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) "
|
||||
_OLD_VIRTUAL_PROMPT
|
||||
}
|
||||
$env:VIRTUAL_ENV_PROMPT = $Prompt
|
||||
}
|
||||
|
||||
# Clear PYTHONHOME
|
||||
if (Test-Path -Path Env:PYTHONHOME) {
|
||||
Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME
|
||||
Remove-Item -Path Env:PYTHONHOME
|
||||
}
|
||||
|
||||
# Add the venv to the PATH
|
||||
Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH
|
||||
$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH"
|
||||
69
env/bin/activate
vendored
69
env/bin/activate
vendored
@ -1,69 +0,0 @@
|
||||
# This file must be used with "source bin/activate" *from bash*
|
||||
# you cannot run it directly
|
||||
|
||||
deactivate () {
|
||||
# reset old environment variables
|
||||
if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then
|
||||
PATH="${_OLD_VIRTUAL_PATH:-}"
|
||||
export PATH
|
||||
unset _OLD_VIRTUAL_PATH
|
||||
fi
|
||||
if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then
|
||||
PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}"
|
||||
export PYTHONHOME
|
||||
unset _OLD_VIRTUAL_PYTHONHOME
|
||||
fi
|
||||
|
||||
# This should detect bash and zsh, which have a hash command that must
|
||||
# be called to get it to forget past commands. Without forgetting
|
||||
# past commands the $PATH changes we made may not be respected
|
||||
if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
|
||||
hash -r 2> /dev/null
|
||||
fi
|
||||
|
||||
if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
|
||||
PS1="${_OLD_VIRTUAL_PS1:-}"
|
||||
export PS1
|
||||
unset _OLD_VIRTUAL_PS1
|
||||
fi
|
||||
|
||||
unset VIRTUAL_ENV
|
||||
unset VIRTUAL_ENV_PROMPT
|
||||
if [ ! "${1:-}" = "nondestructive" ] ; then
|
||||
# Self destruct!
|
||||
unset -f deactivate
|
||||
fi
|
||||
}
|
||||
|
||||
# unset irrelevant variables
|
||||
deactivate nondestructive
|
||||
|
||||
VIRTUAL_ENV="/home/davidson/Projects/evolution_client/python/env"
|
||||
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="(env) ${PS1:-}"
|
||||
export PS1
|
||||
VIRTUAL_ENV_PROMPT="(env) "
|
||||
export VIRTUAL_ENV_PROMPT
|
||||
fi
|
||||
|
||||
# This should detect bash and zsh, which have a hash command that must
|
||||
# be called to get it to forget past commands. Without forgetting
|
||||
# past commands the $PATH changes we made may not be respected
|
||||
if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then
|
||||
hash -r 2> /dev/null
|
||||
fi
|
||||
26
env/bin/activate.csh
vendored
26
env/bin/activate.csh
vendored
@ -1,26 +0,0 @@
|
||||
# This file must be used with "source bin/activate.csh" *from csh*.
|
||||
# You cannot run it directly.
|
||||
# Created by Davide Di Blasi <davidedb@gmail.com>.
|
||||
# Ported to Python 3.3 venv by Andrew Svetlov <andrew.svetlov@gmail.com>
|
||||
|
||||
alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate'
|
||||
|
||||
# Unset irrelevant variables.
|
||||
deactivate nondestructive
|
||||
|
||||
setenv VIRTUAL_ENV "/home/davidson/Projects/evolution_client/python/env"
|
||||
|
||||
set _OLD_VIRTUAL_PATH="$PATH"
|
||||
setenv PATH "$VIRTUAL_ENV/bin:$PATH"
|
||||
|
||||
|
||||
set _OLD_VIRTUAL_PROMPT="$prompt"
|
||||
|
||||
if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
|
||||
set prompt = "(env) $prompt"
|
||||
setenv VIRTUAL_ENV_PROMPT "(env) "
|
||||
endif
|
||||
|
||||
alias pydoc python -m pydoc
|
||||
|
||||
rehash
|
||||
69
env/bin/activate.fish
vendored
69
env/bin/activate.fish
vendored
@ -1,69 +0,0 @@
|
||||
# This file must be used with "source <venv>/bin/activate.fish" *from fish*
|
||||
# (https://fishshell.com/); you cannot run it directly.
|
||||
|
||||
function deactivate -d "Exit virtual environment and return to normal shell environment"
|
||||
# reset old environment variables
|
||||
if test -n "$_OLD_VIRTUAL_PATH"
|
||||
set -gx PATH $_OLD_VIRTUAL_PATH
|
||||
set -e _OLD_VIRTUAL_PATH
|
||||
end
|
||||
if test -n "$_OLD_VIRTUAL_PYTHONHOME"
|
||||
set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME
|
||||
set -e _OLD_VIRTUAL_PYTHONHOME
|
||||
end
|
||||
|
||||
if test -n "$_OLD_FISH_PROMPT_OVERRIDE"
|
||||
set -e _OLD_FISH_PROMPT_OVERRIDE
|
||||
# prevents error when using nested fish instances (Issue #93858)
|
||||
if functions -q _old_fish_prompt
|
||||
functions -e fish_prompt
|
||||
functions -c _old_fish_prompt fish_prompt
|
||||
functions -e _old_fish_prompt
|
||||
end
|
||||
end
|
||||
|
||||
set -e VIRTUAL_ENV
|
||||
set -e VIRTUAL_ENV_PROMPT
|
||||
if test "$argv[1]" != "nondestructive"
|
||||
# Self-destruct!
|
||||
functions -e deactivate
|
||||
end
|
||||
end
|
||||
|
||||
# Unset irrelevant variables.
|
||||
deactivate nondestructive
|
||||
|
||||
set -gx VIRTUAL_ENV "/home/davidson/Projects/evolution_client/python/env"
|
||||
|
||||
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) "(env) " (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 "(env) "
|
||||
end
|
||||
8
env/bin/docutils
vendored
8
env/bin/docutils
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from docutils.__main__ import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
8
env/bin/keyring
vendored
8
env/bin/keyring
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from keyring.cli import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
8
env/bin/markdown-it
vendored
8
env/bin/markdown-it
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from markdown_it.cli.parse import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
8
env/bin/normalizer
vendored
8
env/bin/normalizer
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- 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())
|
||||
8
env/bin/pip
vendored
8
env/bin/pip
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from pip._internal.cli.main import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
8
env/bin/pip3
vendored
8
env/bin/pip3
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from pip._internal.cli.main import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
8
env/bin/pip3.10
vendored
8
env/bin/pip3.10
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from pip._internal.cli.main import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
8
env/bin/pkginfo
vendored
8
env/bin/pkginfo
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from pkginfo.commandline import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
8
env/bin/pygmentize
vendored
8
env/bin/pygmentize
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- 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())
|
||||
1
env/bin/python
vendored
1
env/bin/python
vendored
@ -1 +0,0 @@
|
||||
/usr/bin/python
|
||||
1
env/bin/python3
vendored
1
env/bin/python3
vendored
@ -1 +0,0 @@
|
||||
python
|
||||
1
env/bin/python3.10
vendored
1
env/bin/python3.10
vendored
@ -1 +0,0 @@
|
||||
python
|
||||
8
env/bin/rst2html
vendored
8
env/bin/rst2html
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from docutils.core import rst2html
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(rst2html())
|
||||
8
env/bin/rst2html4
vendored
8
env/bin/rst2html4
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from docutils.core import rst2html4
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(rst2html4())
|
||||
8
env/bin/rst2html5
vendored
8
env/bin/rst2html5
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from docutils.core import rst2html5
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(rst2html5())
|
||||
8
env/bin/rst2latex
vendored
8
env/bin/rst2latex
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from docutils.core import rst2latex
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(rst2latex())
|
||||
8
env/bin/rst2man
vendored
8
env/bin/rst2man
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from docutils.core import rst2man
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(rst2man())
|
||||
8
env/bin/rst2odt
vendored
8
env/bin/rst2odt
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from docutils.core import rst2odt
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(rst2odt())
|
||||
8
env/bin/rst2pseudoxml
vendored
8
env/bin/rst2pseudoxml
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from docutils.core import rst2pseudoxml
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(rst2pseudoxml())
|
||||
8
env/bin/rst2s5
vendored
8
env/bin/rst2s5
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from docutils.core import rst2s5
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(rst2s5())
|
||||
8
env/bin/rst2xetex
vendored
8
env/bin/rst2xetex
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from docutils.core import rst2xetex
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(rst2xetex())
|
||||
8
env/bin/rst2xml
vendored
8
env/bin/rst2xml
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from docutils.core import rst2xml
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(rst2xml())
|
||||
8
env/bin/twine
vendored
8
env/bin/twine
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from twine.__main__ import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
8
env/bin/wheel
vendored
8
env/bin/wheel
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from wheel.cli import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
8
env/bin/wsdump
vendored
8
env/bin/wsdump
vendored
@ -1,8 +0,0 @@
|
||||
#!/home/davidson/Projects/evolution_client/python/env/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import sys
|
||||
from websocket._wsdump import main
|
||||
if __name__ == '__main__':
|
||||
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
|
||||
sys.exit(main())
|
||||
@ -1 +0,0 @@
|
||||
pip
|
||||
@ -1,25 +0,0 @@
|
||||
Copyright 2012-2018 Dmitry Shachnev <mitya57@gmail.com>
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
3. Neither the name of the University nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@ -1,114 +0,0 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: SecretStorage
|
||||
Version: 3.3.3
|
||||
Summary: Python bindings to FreeDesktop.org Secret Service API
|
||||
Home-page: https://github.com/mitya57/secretstorage
|
||||
Author: Dmitry Shachnev
|
||||
Author-email: mitya57@gmail.com
|
||||
License: BSD 3-Clause License
|
||||
Platform: Linux
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: License :: OSI Approved :: BSD License
|
||||
Classifier: Operating System :: POSIX
|
||||
Classifier: Programming Language :: Python
|
||||
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: Topic :: Security
|
||||
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
||||
Requires-Python: >=3.6
|
||||
Description-Content-Type: text/x-rst
|
||||
License-File: LICENSE
|
||||
Requires-Dist: cryptography (>=2.0)
|
||||
Requires-Dist: jeepney (>=0.6)
|
||||
|
||||
.. image:: https://github.com/mitya57/secretstorage/workflows/tests/badge.svg
|
||||
:target: https://github.com/mitya57/secretstorage/actions
|
||||
:alt: GitHub Actions status
|
||||
.. image:: https://codecov.io/gh/mitya57/secretstorage/branch/master/graph/badge.svg
|
||||
:target: https://codecov.io/gh/mitya57/secretstorage
|
||||
:alt: Coverage status
|
||||
.. image:: https://readthedocs.org/projects/secretstorage/badge/?version=latest
|
||||
:target: https://secretstorage.readthedocs.io/en/latest/
|
||||
:alt: ReadTheDocs status
|
||||
|
||||
Module description
|
||||
==================
|
||||
|
||||
This module provides a way for securely storing passwords and other secrets.
|
||||
|
||||
It uses D-Bus `Secret Service`_ API that is supported by GNOME Keyring,
|
||||
KWallet (since version 5.97) and KeePassXC.
|
||||
|
||||
The main classes provided are ``secretstorage.Item``, representing a secret
|
||||
item (that has a *label*, a *secret* and some *attributes*) and
|
||||
``secretstorage.Collection``, a place items are stored in.
|
||||
|
||||
SecretStorage supports most of the functions provided by Secret Service,
|
||||
including creating and deleting items and collections, editing items,
|
||||
locking and unlocking collections (asynchronous unlocking is also supported).
|
||||
|
||||
The documentation can be found on `secretstorage.readthedocs.io`_.
|
||||
|
||||
.. _`Secret Service`: https://specifications.freedesktop.org/secret-service/
|
||||
.. _`secretstorage.readthedocs.io`: https://secretstorage.readthedocs.io/en/latest/
|
||||
|
||||
Building the module
|
||||
===================
|
||||
|
||||
.. note::
|
||||
SecretStorage 3.x supports Python 3.6 and newer versions.
|
||||
If you have an older version of Python, install SecretStorage 2.x::
|
||||
|
||||
pip install "SecretStorage < 3"
|
||||
|
||||
SecretStorage requires these packages to work:
|
||||
|
||||
* Jeepney_
|
||||
* `python-cryptography`_
|
||||
|
||||
To build SecretStorage, use this command::
|
||||
|
||||
python3 setup.py build
|
||||
|
||||
If you have Sphinx_ installed, you can also build the documentation::
|
||||
|
||||
python3 setup.py build_sphinx
|
||||
|
||||
.. _Jeepney: https://pypi.org/project/jeepney/
|
||||
.. _`python-cryptography`: https://pypi.org/project/cryptography/
|
||||
.. _Sphinx: http://sphinx-doc.org/
|
||||
|
||||
Testing the module
|
||||
==================
|
||||
|
||||
First, make sure that you have the Secret Service daemon installed.
|
||||
The `GNOME Keyring`_ is the reference server-side implementation for the
|
||||
Secret Service specification.
|
||||
|
||||
.. _`GNOME Keyring`: https://download.gnome.org/sources/gnome-keyring/
|
||||
|
||||
Then, start the daemon and unlock the ``default`` collection, if needed.
|
||||
The testsuite will fail to run if the ``default`` collection exists and is
|
||||
locked. If it does not exist, the testsuite can also use the temporary
|
||||
``session`` collection, as provided by the GNOME Keyring.
|
||||
|
||||
Then, run the Python unittest module::
|
||||
|
||||
python3 -m unittest discover -s tests
|
||||
|
||||
If you want to run the tests in an isolated or headless environment, run
|
||||
this command in a D-Bus session::
|
||||
|
||||
dbus-run-session -- python3 -m unittest discover -s tests
|
||||
|
||||
Get the code
|
||||
============
|
||||
|
||||
SecretStorage is available under BSD license. The source code can be found
|
||||
on GitHub_.
|
||||
|
||||
.. _GitHub: https://github.com/mitya57/secretstorage
|
||||
@ -1,21 +0,0 @@
|
||||
SecretStorage-3.3.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
SecretStorage-3.3.3.dist-info/LICENSE,sha256=cPa_yndjPDXvohgyjtpUhtcFTCkU1hggmA43h5dSCiU,1504
|
||||
SecretStorage-3.3.3.dist-info/METADATA,sha256=ZScD5voEgjme04wlw9OZigESMxLa2xG_eaIeZ_IMqJI,4027
|
||||
SecretStorage-3.3.3.dist-info/RECORD,,
|
||||
SecretStorage-3.3.3.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
|
||||
SecretStorage-3.3.3.dist-info/top_level.txt,sha256=hveSi1OWGaEt3kEVbjmZ0M-ASPxi6y-nTPVa-d3c0B4,14
|
||||
secretstorage/__init__.py,sha256=W1p-HB1Qh12Dv6K8ml0Wj_MzN09_dEeezJjQZAHf-O4,3364
|
||||
secretstorage/__pycache__/__init__.cpython-310.pyc,,
|
||||
secretstorage/__pycache__/collection.cpython-310.pyc,,
|
||||
secretstorage/__pycache__/defines.cpython-310.pyc,,
|
||||
secretstorage/__pycache__/dhcrypto.cpython-310.pyc,,
|
||||
secretstorage/__pycache__/exceptions.cpython-310.pyc,,
|
||||
secretstorage/__pycache__/item.cpython-310.pyc,,
|
||||
secretstorage/__pycache__/util.cpython-310.pyc,,
|
||||
secretstorage/collection.py,sha256=lHwSOkFO5sRspgcUBoBI8ZG2au2bcUSO6X64ksVdnsQ,9436
|
||||
secretstorage/defines.py,sha256=DzUrEWzSvBlN8kK2nVXnLGlCZv7HWNyfN1AYqRmjKGE,807
|
||||
secretstorage/dhcrypto.py,sha256=BiuDoNvNmd8i7Ul4ENouRnbqFE3SUmTUSAn6RVvn7Tg,2578
|
||||
secretstorage/exceptions.py,sha256=1uUZXTua4jRZf4PKDIT2SVWcSKP2lP97s8r3eJZudio,1655
|
||||
secretstorage/item.py,sha256=3niFSjOzwrB2hV1jrg78RXgBsTrpw44852VpZHXUpeE,5813
|
||||
secretstorage/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
secretstorage/util.py,sha256=vHu01QaooMQ5sRdRDFX9pg7rrzfJWF9vg0plm3Zg0Po,6755
|
||||
@ -1,5 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.37.1)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
||||
@ -1 +0,0 @@
|
||||
secretstorage
|
||||
Binary file not shown.
Binary file not shown.
@ -1,132 +0,0 @@
|
||||
import sys
|
||||
import os
|
||||
import re
|
||||
import importlib
|
||||
import warnings
|
||||
|
||||
|
||||
is_pypy = '__pypy__' in sys.builtin_module_names
|
||||
|
||||
|
||||
warnings.filterwarnings('ignore',
|
||||
r'.+ distutils\b.+ deprecated',
|
||||
DeprecationWarning)
|
||||
|
||||
|
||||
def warn_distutils_present():
|
||||
if 'distutils' not in sys.modules:
|
||||
return
|
||||
if is_pypy and sys.version_info < (3, 7):
|
||||
# PyPy for 3.6 unconditionally imports distutils, so bypass the warning
|
||||
# https://foss.heptapod.net/pypy/pypy/-/blob/be829135bc0d758997b3566062999ee8b23872b4/lib-python/3/site.py#L250
|
||||
return
|
||||
warnings.warn(
|
||||
"Distutils was imported before Setuptools, but importing Setuptools "
|
||||
"also replaces the `distutils` module in `sys.modules`. This may lead "
|
||||
"to undesirable behaviors or errors. To avoid these issues, avoid "
|
||||
"using distutils directly, ensure that setuptools is installed in the "
|
||||
"traditional way (e.g. not an editable install), and/or make sure "
|
||||
"that setuptools is always imported before distutils.")
|
||||
|
||||
|
||||
def clear_distutils():
|
||||
if 'distutils' not in sys.modules:
|
||||
return
|
||||
warnings.warn("Setuptools is replacing distutils.")
|
||||
mods = [name for name in sys.modules if re.match(r'distutils\b', name)]
|
||||
for name in mods:
|
||||
del sys.modules[name]
|
||||
|
||||
|
||||
def enabled():
|
||||
"""
|
||||
Allow selection of distutils by environment variable.
|
||||
"""
|
||||
which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'stdlib')
|
||||
return which == 'local'
|
||||
|
||||
|
||||
def ensure_local_distutils():
|
||||
clear_distutils()
|
||||
|
||||
# With the DistutilsMetaFinder in place,
|
||||
# perform an import to cause distutils to be
|
||||
# loaded from setuptools._distutils. Ref #2906.
|
||||
add_shim()
|
||||
importlib.import_module('distutils')
|
||||
remove_shim()
|
||||
|
||||
# check that submodules load as expected
|
||||
core = importlib.import_module('distutils.core')
|
||||
assert '_distutils' in core.__file__, core.__file__
|
||||
|
||||
|
||||
def do_override():
|
||||
"""
|
||||
Ensure that the local copy of distutils is preferred over stdlib.
|
||||
|
||||
See https://github.com/pypa/setuptools/issues/417#issuecomment-392298401
|
||||
for more motivation.
|
||||
"""
|
||||
if enabled():
|
||||
warn_distutils_present()
|
||||
ensure_local_distutils()
|
||||
|
||||
|
||||
class DistutilsMetaFinder:
|
||||
def find_spec(self, fullname, path, target=None):
|
||||
if path is not None:
|
||||
return
|
||||
|
||||
method_name = 'spec_for_{fullname}'.format(**locals())
|
||||
method = getattr(self, method_name, lambda: None)
|
||||
return method()
|
||||
|
||||
def spec_for_distutils(self):
|
||||
import importlib.abc
|
||||
import importlib.util
|
||||
|
||||
class DistutilsLoader(importlib.abc.Loader):
|
||||
|
||||
def create_module(self, spec):
|
||||
return importlib.import_module('setuptools._distutils')
|
||||
|
||||
def exec_module(self, module):
|
||||
pass
|
||||
|
||||
return importlib.util.spec_from_loader('distutils', DistutilsLoader())
|
||||
|
||||
def spec_for_pip(self):
|
||||
"""
|
||||
Ensure stdlib distutils when running under pip.
|
||||
See pypa/pip#8761 for rationale.
|
||||
"""
|
||||
if self.pip_imported_during_build():
|
||||
return
|
||||
clear_distutils()
|
||||
self.spec_for_distutils = lambda: None
|
||||
|
||||
@staticmethod
|
||||
def pip_imported_during_build():
|
||||
"""
|
||||
Detect if pip is being imported in a build script. Ref #2355.
|
||||
"""
|
||||
import traceback
|
||||
return any(
|
||||
frame.f_globals['__file__'].endswith('setup.py')
|
||||
for frame, line in traceback.walk_stack(None)
|
||||
)
|
||||
|
||||
|
||||
DISTUTILS_FINDER = DistutilsMetaFinder()
|
||||
|
||||
|
||||
def add_shim():
|
||||
sys.meta_path.insert(0, DISTUTILS_FINDER)
|
||||
|
||||
|
||||
def remove_shim():
|
||||
try:
|
||||
sys.meta_path.remove(DISTUTILS_FINDER)
|
||||
except ValueError:
|
||||
pass
|
||||
Binary file not shown.
Binary file not shown.
@ -1 +0,0 @@
|
||||
__import__('_distutils_hack').do_override()
|
||||
@ -1 +0,0 @@
|
||||
pip
|
||||
@ -1,17 +0,0 @@
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to
|
||||
deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
|
||||
sell copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
|
||||
IN THE SOFTWARE.
|
||||
@ -1,46 +0,0 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: backports.tarfile
|
||||
Version: 1.2.0
|
||||
Summary: Backport of CPython tarfile module
|
||||
Author-email: "Jason R. Coombs" <jaraco@jaraco.com>
|
||||
Project-URL: Homepage, https://github.com/jaraco/backports.tarfile
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: MIT License
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3 :: Only
|
||||
Requires-Python: >=3.8
|
||||
Description-Content-Type: text/x-rst
|
||||
License-File: LICENSE
|
||||
Provides-Extra: docs
|
||||
Requires-Dist: sphinx >=3.5 ; extra == 'docs'
|
||||
Requires-Dist: jaraco.packaging >=9.3 ; extra == 'docs'
|
||||
Requires-Dist: rst.linker >=1.9 ; extra == 'docs'
|
||||
Requires-Dist: furo ; extra == 'docs'
|
||||
Requires-Dist: sphinx-lint ; extra == 'docs'
|
||||
Provides-Extra: testing
|
||||
Requires-Dist: pytest !=8.1.*,>=6 ; extra == 'testing'
|
||||
Requires-Dist: pytest-checkdocs >=2.4 ; extra == 'testing'
|
||||
Requires-Dist: pytest-cov ; extra == 'testing'
|
||||
Requires-Dist: pytest-enabler >=2.2 ; extra == 'testing'
|
||||
Requires-Dist: jaraco.test ; extra == 'testing'
|
||||
Requires-Dist: pytest !=8.0.* ; extra == 'testing'
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/backports.tarfile.svg
|
||||
:target: https://pypi.org/project/backports.tarfile
|
||||
|
||||
.. image:: https://img.shields.io/pypi/pyversions/backports.tarfile.svg
|
||||
|
||||
.. image:: https://github.com/jaraco/backports.tarfile/actions/workflows/main.yml/badge.svg
|
||||
:target: https://github.com/jaraco/backports.tarfile/actions?query=workflow%3A%22tests%22
|
||||
:alt: tests
|
||||
|
||||
.. image:: https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json
|
||||
:target: https://github.com/astral-sh/ruff
|
||||
:alt: Ruff
|
||||
|
||||
.. .. image:: https://readthedocs.org/projects/backportstarfile/badge/?version=latest
|
||||
.. :target: https://backportstarfile.readthedocs.io/en/latest/?badge=latest
|
||||
|
||||
.. image:: https://img.shields.io/badge/skeleton-2024-informational
|
||||
:target: https://blog.jaraco.com/skeleton
|
||||
@ -1,16 +0,0 @@
|
||||
backports.tarfile-1.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
backports.tarfile-1.2.0.dist-info/LICENSE,sha256=htoPAa6uRjSKPD1GUZXcHOzN55956HdppkuNoEsqR0E,1023
|
||||
backports.tarfile-1.2.0.dist-info/METADATA,sha256=ghXFTq132dxaEIolxr3HK1mZqm9iyUmaRANZQSr6WlE,2020
|
||||
backports.tarfile-1.2.0.dist-info/RECORD,,
|
||||
backports.tarfile-1.2.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
|
||||
backports.tarfile-1.2.0.dist-info/top_level.txt,sha256=cGjaLMOoBR1FK0ApojtzWVmViTtJ7JGIK_HwXiEsvtU,10
|
||||
backports/__init__.py,sha256=iOEMwnlORWezdO8-2vxBIPSR37D7JGjluZ8f55vzxls,81
|
||||
backports/__pycache__/__init__.cpython-310.pyc,,
|
||||
backports/tarfile/__init__.py,sha256=Pwf2qUIfB0SolJPCKcx3vz3UEu_aids4g4sAfxy94qg,108491
|
||||
backports/tarfile/__main__.py,sha256=Yw2oGT1afrz2eBskzdPYL8ReB_3liApmhFkN2EbDmc4,59
|
||||
backports/tarfile/__pycache__/__init__.cpython-310.pyc,,
|
||||
backports/tarfile/__pycache__/__main__.cpython-310.pyc,,
|
||||
backports/tarfile/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
backports/tarfile/compat/__pycache__/__init__.cpython-310.pyc,,
|
||||
backports/tarfile/compat/__pycache__/py38.cpython-310.pyc,,
|
||||
backports/tarfile/compat/py38.py,sha256=iYkyt_gvWjLzGUTJD9TuTfMMjOk-ersXZmRlvQYN2qE,568
|
||||
@ -1,5 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.43.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
||||
@ -1 +0,0 @@
|
||||
backports
|
||||
@ -1 +0,0 @@
|
||||
__path__ = __import__('pkgutil').extend_path(__path__, __name__) # type: ignore
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@ -1,5 +0,0 @@
|
||||
from . import main
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,24 +0,0 @@
|
||||
import sys
|
||||
|
||||
|
||||
if sys.version_info < (3, 9):
|
||||
|
||||
def removesuffix(self, suffix):
|
||||
# suffix='' should not call self[:-0].
|
||||
if suffix and self.endswith(suffix):
|
||||
return self[: -len(suffix)]
|
||||
else:
|
||||
return self[:]
|
||||
|
||||
def removeprefix(self, prefix):
|
||||
if self.startswith(prefix):
|
||||
return self[len(prefix) :]
|
||||
else:
|
||||
return self[:]
|
||||
else:
|
||||
|
||||
def removesuffix(self, suffix):
|
||||
return self.removesuffix(suffix)
|
||||
|
||||
def removeprefix(self, prefix):
|
||||
return self.removeprefix(prefix)
|
||||
@ -1 +0,0 @@
|
||||
pip
|
||||
@ -1,376 +0,0 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
Copyright 2009-2024 Joshua Bronson. All rights reserved.
|
||||
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
@ -1,260 +0,0 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: bidict
|
||||
Version: 0.23.1
|
||||
Summary: The bidirectional mapping library for Python.
|
||||
Author-email: Joshua Bronson <jabronson@gmail.com>
|
||||
License: MPL 2.0
|
||||
Project-URL: Changelog, https://bidict.readthedocs.io/changelog.html
|
||||
Project-URL: Documentation, https://bidict.readthedocs.io
|
||||
Project-URL: Funding, https://bidict.readthedocs.io/#sponsoring
|
||||
Project-URL: Repository, https://github.com/jab/bidict
|
||||
Keywords: bidict,bimap,bidirectional,dict,dictionary,mapping,collections
|
||||
Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
|
||||
Classifier: Operating System :: OS Independent
|
||||
Classifier: Programming Language :: Python :: Implementation :: CPython
|
||||
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
||||
Classifier: Typing :: Typed
|
||||
Requires-Python: >=3.8
|
||||
Description-Content-Type: text/x-rst
|
||||
License-File: LICENSE
|
||||
|
||||
.. role:: doc
|
||||
.. (Forward declaration for the "doc" role that Sphinx defines for interop with renderers that
|
||||
are often used to show this doc and that are unaware of Sphinx (GitHub.com, PyPI.org, etc.).
|
||||
Use :doc: rather than :ref: here for better interop as well.)
|
||||
|
||||
|
||||
bidict
|
||||
======
|
||||
|
||||
*The bidirectional mapping library for Python.*
|
||||
|
||||
|
||||
Status
|
||||
------
|
||||
|
||||
.. image:: https://img.shields.io/pypi/v/bidict.svg
|
||||
:target: https://pypi.org/project/bidict
|
||||
:alt: Latest release
|
||||
|
||||
.. image:: https://img.shields.io/readthedocs/bidict/main.svg
|
||||
:target: https://bidict.readthedocs.io/en/main/
|
||||
:alt: Documentation
|
||||
|
||||
.. image:: https://github.com/jab/bidict/actions/workflows/test.yml/badge.svg
|
||||
:target: https://github.com/jab/bidict/actions/workflows/test.yml?query=branch%3Amain
|
||||
:alt: GitHub Actions CI status
|
||||
|
||||
.. image:: https://img.shields.io/pypi/l/bidict.svg
|
||||
:target: https://raw.githubusercontent.com/jab/bidict/main/LICENSE
|
||||
:alt: License
|
||||
|
||||
.. image:: https://static.pepy.tech/badge/bidict
|
||||
:target: https://pepy.tech/project/bidict
|
||||
:alt: PyPI Downloads
|
||||
|
||||
.. image:: https://img.shields.io/badge/GitHub-sponsor-ff69b4
|
||||
:target: https://github.com/sponsors/jab
|
||||
:alt: Sponsor
|
||||
|
||||
|
||||
Features
|
||||
--------
|
||||
|
||||
- Mature: Depended on by
|
||||
Google, Venmo, CERN, Baidu, Tencent,
|
||||
and teams across the world since 2009
|
||||
|
||||
- Familiar, Pythonic APIs
|
||||
that are carefully designed for
|
||||
safety, simplicity, flexibility, and ergonomics
|
||||
|
||||
- Lightweight, with no runtime dependencies
|
||||
outside Python's standard library
|
||||
|
||||
- Implemented in
|
||||
concise, well-factored, fully type-hinted Python code
|
||||
that is optimized for running efficiently
|
||||
as well as for long-term maintenance and stability
|
||||
(as well as `joy <#learning-from-bidict>`__)
|
||||
|
||||
- Extensively `documented <https://bidict.readthedocs.io>`__
|
||||
|
||||
- 100% test coverage
|
||||
running continuously across all supported Python versions
|
||||
(including property-based tests and benchmarks)
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
``pip install bidict``
|
||||
|
||||
|
||||
Quick Start
|
||||
-----------
|
||||
|
||||
.. code:: python
|
||||
|
||||
>>> from bidict import bidict
|
||||
>>> element_by_symbol = bidict({'H': 'hydrogen'})
|
||||
>>> element_by_symbol['H']
|
||||
'hydrogen'
|
||||
>>> element_by_symbol.inverse['hydrogen']
|
||||
'H'
|
||||
|
||||
|
||||
For more usage documentation,
|
||||
head to the :doc:`intro` [#fn-intro]_
|
||||
and proceed from there.
|
||||
|
||||
|
||||
Enterprise Support
|
||||
------------------
|
||||
|
||||
Enterprise-level support for bidict can be obtained via the
|
||||
`Tidelift subscription <https://tidelift.com/subscription/pkg/pypi-bidict?utm_source=pypi-bidict&utm_medium=referral&utm_campaign=readme>`__
|
||||
or by `contacting me directly <mailto:jabronson@gmail.com>`__.
|
||||
|
||||
I have a US-based LLC set up for invoicing,
|
||||
and I have 15+ years of professional experience
|
||||
delivering software and support to companies successfully.
|
||||
|
||||
You can also sponsor my work through several platforms, including GitHub Sponsors.
|
||||
See the `Sponsoring <#sponsoring>`__ section below for details,
|
||||
including rationale and examples of companies
|
||||
supporting the open source projects they depend on.
|
||||
|
||||
|
||||
Voluntary Community Support
|
||||
---------------------------
|
||||
|
||||
Please search through already-asked questions and answers
|
||||
in `GitHub Discussions <https://github.com/jab/bidict/discussions>`__
|
||||
and the `issue tracker <https://github.com/jab/bidict/issues?q=is%3Aissue>`__
|
||||
in case your question has already been addressed.
|
||||
|
||||
Otherwise, please feel free to
|
||||
`start a new discussion <https://github.com/jab/bidict/discussions>`__
|
||||
or `create a new issue <https://github.com/jab/bidict/issues/new>`__ on GitHub
|
||||
for voluntary community support.
|
||||
|
||||
|
||||
Notice of Usage
|
||||
---------------
|
||||
|
||||
If you use bidict,
|
||||
and especially if your usage or your organization is significant in some way,
|
||||
please let me know in any of the following ways:
|
||||
|
||||
- `star bidict on GitHub <https://github.com/jab/bidict>`__
|
||||
- post in `GitHub Discussions <https://github.com/jab/bidict/discussions>`__
|
||||
- `email me <mailto:jabronson@gmail.com>`__
|
||||
|
||||
|
||||
Changelog
|
||||
---------
|
||||
|
||||
For bidict release notes, see the :doc:`changelog`. [#fn-changelog]_
|
||||
|
||||
|
||||
Release Notifications
|
||||
---------------------
|
||||
|
||||
.. duplicated in CHANGELOG.rst:
|
||||
(Would use `.. include::` but GitHub's renderer doesn't support it.)
|
||||
|
||||
Watch `bidict releases on GitHub <https://github.com/jab/bidict/releases>`__
|
||||
to be notified when new versions of bidict are published.
|
||||
Click the "Watch" dropdown, choose "Custom", and then choose "Releases".
|
||||
|
||||
|
||||
Learning from bidict
|
||||
--------------------
|
||||
|
||||
One of the best things about bidict
|
||||
is that it touches a surprising number of
|
||||
interesting Python corners,
|
||||
especially given its small size and scope.
|
||||
|
||||
Check out :doc:`learning-from-bidict` [#fn-learning]_
|
||||
if you're interested in learning more.
|
||||
|
||||
|
||||
Contributing
|
||||
------------
|
||||
|
||||
I have been bidict's sole maintainer
|
||||
and `active contributor <https://github.com/jab/bidict/graphs/contributors>`__
|
||||
since I started the project ~15 years ago.
|
||||
|
||||
Your help would be most welcome!
|
||||
See the :doc:`contributors-guide` [#fn-contributing]_
|
||||
for more information.
|
||||
|
||||
|
||||
Sponsoring
|
||||
----------
|
||||
|
||||
.. duplicated in CONTRIBUTING.rst
|
||||
(Would use `.. include::` but GitHub's renderer doesn't support it.)
|
||||
|
||||
.. image:: https://img.shields.io/badge/GitHub-sponsor-ff69b4
|
||||
:target: https://github.com/sponsors/jab
|
||||
:alt: Sponsor through GitHub
|
||||
|
||||
Bidict is the product of thousands of hours of my unpaid work
|
||||
over the 15+ years that I've been the sole maintainer.
|
||||
|
||||
If bidict has helped you or your company accomplish your work,
|
||||
please sponsor my work through one of the following,
|
||||
and/or ask your company to do the same:
|
||||
|
||||
- `GitHub <https://github.com/sponsors/jab>`__
|
||||
- `PayPal <https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=jabronson%40gmail%2ecom&lc=US&item_name=Sponsor%20bidict>`__
|
||||
- `Tidelift <https://tidelift.com>`__
|
||||
- `thanks.dev <https://thanks.dev>`__
|
||||
- `Gumroad <https://gumroad.com/l/bidict>`__
|
||||
- `a support engagement with my LLC <#enterprise-support>`__
|
||||
|
||||
If you're not sure which to use, GitHub is an easy option,
|
||||
especially if you already have a GitHub account.
|
||||
Just choose a monthly or one-time amount, and GitHub handles everything else.
|
||||
Your bidict sponsorship on GitHub will automatically go
|
||||
on the same regular bill as any other GitHub charges you pay for.
|
||||
PayPal is another easy option for one-time contributions.
|
||||
|
||||
See the following for rationale and examples of companies
|
||||
supporting the open source projects they depend on
|
||||
in this manner:
|
||||
|
||||
- `<https://engineering.atspotify.com/2022/04/announcing-the-spotify-foss-fund/>`__
|
||||
- `<https://blog.sentry.io/2021/10/21/we-just-gave-154-999-dollars-and-89-cents-to-open-source-maintainers>`__
|
||||
- `<https://engineering.indeedblog.com/blog/2019/07/foss-fund-six-months-in/>`__
|
||||
|
||||
.. - `<https://sethmlarson.dev/blog/people-in-your-software-supply-chain>`__
|
||||
.. - `<https://www.cognitect.com/blog/supporting-open-source-developers>`__
|
||||
.. - `<https://vorpus.org/blog/the-unreasonable-effectiveness-of-investment-in-open-source-infrastructure/>`__
|
||||
|
||||
|
||||
Finding Documentation
|
||||
---------------------
|
||||
|
||||
If you're viewing this on `<https://bidict.readthedocs.io>`__,
|
||||
note that multiple versions of the documentation are available,
|
||||
and you can choose a different version using the popup menu at the bottom-right.
|
||||
Please make sure you're viewing the version of the documentation
|
||||
that corresponds to the version of bidict you'd like to use.
|
||||
|
||||
If you're viewing this on GitHub, PyPI, or some other place
|
||||
that can't render and link this documentation properly
|
||||
and are seeing broken links,
|
||||
try these alternate links instead:
|
||||
|
||||
.. [#fn-intro] `<https://bidict.readthedocs.io/intro.html>`__ | `<docs/intro.rst>`__
|
||||
|
||||
.. [#fn-changelog] `<https://bidict.readthedocs.io/changelog.html>`__ | `<CHANGELOG.rst>`__
|
||||
|
||||
.. [#fn-learning] `<https://bidict.readthedocs.io/learning-from-bidict.html>`__ | `<docs/learning-from-bidict.rst>`__
|
||||
|
||||
.. [#fn-contributing] `<https://bidict.readthedocs.io/contributors-guide.html>`__ | `<CONTRIBUTING.rst>`__
|
||||
@ -1,31 +0,0 @@
|
||||
bidict-0.23.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
bidict-0.23.1.dist-info/LICENSE,sha256=8_U63OyqSNc6ZuI4-lupBstBh2eDtF0ooTRrMULuvZo,16784
|
||||
bidict-0.23.1.dist-info/METADATA,sha256=2ovIRm6Df8gdwAMekGqkeBSF5TWj2mv1jpmh4W4ks7o,8704
|
||||
bidict-0.23.1.dist-info/RECORD,,
|
||||
bidict-0.23.1.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
||||
bidict-0.23.1.dist-info/top_level.txt,sha256=WuQO02jp0ODioS7sJoaHg3JJ5_3h6Sxo9RITvNGPYmc,7
|
||||
bidict/__init__.py,sha256=pL87KsrDpBsl3AG09LQk1t1TSFt0hIJVYa2POMdErN8,4398
|
||||
bidict/__pycache__/__init__.cpython-310.pyc,,
|
||||
bidict/__pycache__/_abc.cpython-310.pyc,,
|
||||
bidict/__pycache__/_base.cpython-310.pyc,,
|
||||
bidict/__pycache__/_bidict.cpython-310.pyc,,
|
||||
bidict/__pycache__/_dup.cpython-310.pyc,,
|
||||
bidict/__pycache__/_exc.cpython-310.pyc,,
|
||||
bidict/__pycache__/_frozen.cpython-310.pyc,,
|
||||
bidict/__pycache__/_iter.cpython-310.pyc,,
|
||||
bidict/__pycache__/_orderedbase.cpython-310.pyc,,
|
||||
bidict/__pycache__/_orderedbidict.cpython-310.pyc,,
|
||||
bidict/__pycache__/_typing.cpython-310.pyc,,
|
||||
bidict/__pycache__/metadata.cpython-310.pyc,,
|
||||
bidict/_abc.py,sha256=SMCNdCsmqSWg0OGnMZtnnXY8edjXcyZup5tva4HBm_c,3172
|
||||
bidict/_base.py,sha256=YiauA0aj52fNB6cfZ4gBt6OV-CRQoZm7WVhuw1nT-Cg,24439
|
||||
bidict/_bidict.py,sha256=Sr-RoEzWOaxpnDRbDJ7ngaGRIsyGnqZgzvR-NyT4jl4,6923
|
||||
bidict/_dup.py,sha256=YAn5gWA6lwMBA5A6ebVF19UTZyambGS8WxmbK4TN1Ww,2079
|
||||
bidict/_exc.py,sha256=HnD_WgteI5PrXa3zBx9RUiGlgnZTO6CF4nIU9p3-njk,1066
|
||||
bidict/_frozen.py,sha256=p4TaRHKeyTs0KmlpwSnZiTlN_CR4J97kAgBpNdZHQMs,1771
|
||||
bidict/_iter.py,sha256=zVUx-hJ1M4YuJROoFWRjPKlcaFnyo1AAuRpOaKAFhOQ,1530
|
||||
bidict/_orderedbase.py,sha256=M7v5rHa7vrym9Z3DxQBFQDxjnrr39Z8p26V0c1PggoE,8942
|
||||
bidict/_orderedbidict.py,sha256=pPnmC19mIISrj8_yjnb-4r_ti1B74tD5eTd08DETNuI,7080
|
||||
bidict/_typing.py,sha256=AylMZpBhEFTQegfziPSxfKkKLk7oUsH6o3awDIg2z_k,1289
|
||||
bidict/metadata.py,sha256=BMIKu6fBY_OKeV_q48EpumE7MdmFw8rFcdaUz8kcIYk,573
|
||||
bidict/py.typed,sha256=RJao5SVFYIp8IfbxhL_SpZkBQYe3XXzPlobSRdh4B_c,16
|
||||
@ -1,5 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: bdist_wheel (0.42.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
||||
@ -1 +0,0 @@
|
||||
bidict
|
||||
103
env/lib/python3.10/site-packages/bidict/__init__.py
vendored
103
env/lib/python3.10/site-packages/bidict/__init__.py
vendored
@ -1,103 +0,0 @@
|
||||
# Copyright 2009-2024 Joshua Bronson. All rights reserved.
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# * Welcome to the bidict source code *
|
||||
# ============================================================================
|
||||
|
||||
# Reading through the code? You'll find a "Code review nav" comment like the one
|
||||
# below at the top and bottom of the key source files. Follow these cues to take
|
||||
# a path through the code that's optimized for familiarizing yourself with it.
|
||||
#
|
||||
# If you're not reading this on https://github.com/jab/bidict already, go there
|
||||
# to ensure you have the latest version of the code. While there, you can also
|
||||
# star the project, watch it for updates, fork the code, and submit an issue or
|
||||
# pull request with any proposed changes. More information can be found linked
|
||||
# from README.rst, which is also shown on https://github.com/jab/bidict.
|
||||
|
||||
# * Code review nav *
|
||||
# ============================================================================
|
||||
# Current: __init__.py Next: _abc.py →
|
||||
# ============================================================================
|
||||
|
||||
|
||||
"""The bidirectional mapping library for Python.
|
||||
|
||||
----
|
||||
|
||||
bidict by example:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
>>> from bidict import bidict
|
||||
>>> element_by_symbol = bidict({'H': 'hydrogen'})
|
||||
>>> element_by_symbol['H']
|
||||
'hydrogen'
|
||||
>>> element_by_symbol.inverse['hydrogen']
|
||||
'H'
|
||||
|
||||
|
||||
Please see https://github.com/jab/bidict for the most up-to-date code and
|
||||
https://bidict.readthedocs.io for the most up-to-date documentation
|
||||
if you are reading this elsewhere.
|
||||
|
||||
----
|
||||
|
||||
.. :copyright: (c) 2009-2024 Joshua Bronson.
|
||||
.. :license: MPLv2. See LICENSE for details.
|
||||
"""
|
||||
|
||||
# Use private aliases to not re-export these publicly (for Sphinx automodule with imported-members).
|
||||
from __future__ import annotations as _annotations
|
||||
|
||||
from contextlib import suppress as _suppress
|
||||
|
||||
from ._abc import BidirectionalMapping as BidirectionalMapping
|
||||
from ._abc import MutableBidirectionalMapping as MutableBidirectionalMapping
|
||||
from ._base import BidictBase as BidictBase
|
||||
from ._base import BidictKeysView as BidictKeysView
|
||||
from ._base import GeneratedBidictInverse as GeneratedBidictInverse
|
||||
from ._bidict import MutableBidict as MutableBidict
|
||||
from ._bidict import bidict as bidict
|
||||
from ._dup import DROP_NEW as DROP_NEW
|
||||
from ._dup import DROP_OLD as DROP_OLD
|
||||
from ._dup import ON_DUP_DEFAULT as ON_DUP_DEFAULT
|
||||
from ._dup import ON_DUP_DROP_OLD as ON_DUP_DROP_OLD
|
||||
from ._dup import ON_DUP_RAISE as ON_DUP_RAISE
|
||||
from ._dup import RAISE as RAISE
|
||||
from ._dup import OnDup as OnDup
|
||||
from ._dup import OnDupAction as OnDupAction
|
||||
from ._exc import BidictException as BidictException
|
||||
from ._exc import DuplicationError as DuplicationError
|
||||
from ._exc import KeyAndValueDuplicationError as KeyAndValueDuplicationError
|
||||
from ._exc import KeyDuplicationError as KeyDuplicationError
|
||||
from ._exc import ValueDuplicationError as ValueDuplicationError
|
||||
from ._frozen import frozenbidict as frozenbidict
|
||||
from ._iter import inverted as inverted
|
||||
from ._orderedbase import OrderedBidictBase as OrderedBidictBase
|
||||
from ._orderedbidict import OrderedBidict as OrderedBidict
|
||||
from .metadata import __author__ as __author__
|
||||
from .metadata import __copyright__ as __copyright__
|
||||
from .metadata import __description__ as __description__
|
||||
from .metadata import __license__ as __license__
|
||||
from .metadata import __url__ as __url__
|
||||
from .metadata import __version__ as __version__
|
||||
|
||||
|
||||
# Set __module__ of re-exported classes to the 'bidict' top-level module, so that e.g.
|
||||
# 'bidict.bidict' shows up as 'bidict.bidict` rather than 'bidict._bidict.bidict'.
|
||||
for _obj in tuple(locals().values()): # pragma: no cover
|
||||
if not getattr(_obj, '__module__', '').startswith('bidict.'):
|
||||
continue
|
||||
with _suppress(AttributeError):
|
||||
_obj.__module__ = 'bidict'
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
# ============================================================================
|
||||
# Current: __init__.py Next: _abc.py →
|
||||
# ============================================================================
|
||||
79
env/lib/python3.10/site-packages/bidict/_abc.py
vendored
79
env/lib/python3.10/site-packages/bidict/_abc.py
vendored
@ -1,79 +0,0 @@
|
||||
# Copyright 2009-2024 Joshua Bronson. All rights reserved.
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
# (see comments in __init__.py)
|
||||
# ============================================================================
|
||||
# ← Prev: __init__.py Current: _abc.py Next: _base.py →
|
||||
# ============================================================================
|
||||
|
||||
|
||||
"""Provide the :class:`BidirectionalMapping` abstract base class."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import typing as t
|
||||
from abc import abstractmethod
|
||||
|
||||
from ._typing import KT
|
||||
from ._typing import VT
|
||||
|
||||
|
||||
class BidirectionalMapping(t.Mapping[KT, VT]):
|
||||
"""Abstract base class for bidirectional mapping types.
|
||||
|
||||
Extends :class:`collections.abc.Mapping` primarily by adding the
|
||||
(abstract) :attr:`inverse` property,
|
||||
which implementers of :class:`BidirectionalMapping`
|
||||
should override to return a reference to the inverse
|
||||
:class:`BidirectionalMapping` instance.
|
||||
"""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
@property
|
||||
@abstractmethod
|
||||
def inverse(self) -> BidirectionalMapping[VT, KT]:
|
||||
"""The inverse of this bidirectional mapping instance.
|
||||
|
||||
*See also* :attr:`bidict.BidictBase.inverse`, :attr:`bidict.BidictBase.inv`
|
||||
|
||||
:raises NotImplementedError: Meant to be overridden in subclasses.
|
||||
"""
|
||||
# The @abstractmethod decorator prevents subclasses from being instantiated unless they
|
||||
# override this method. But an overriding implementation may merely return super().inverse,
|
||||
# in which case this implementation is used. Raise NotImplementedError to indicate that
|
||||
# subclasses must actually provide their own implementation.
|
||||
raise NotImplementedError
|
||||
|
||||
def __inverted__(self) -> t.Iterator[tuple[VT, KT]]:
|
||||
"""Get an iterator over the items in :attr:`inverse`.
|
||||
|
||||
This is functionally equivalent to iterating over the items in the
|
||||
forward mapping and inverting each one on the fly, but this provides a
|
||||
more efficient implementation: Assuming the already-inverted items
|
||||
are stored in :attr:`inverse`, just return an iterator over them directly.
|
||||
|
||||
Providing this default implementation enables external functions,
|
||||
particularly :func:`~bidict.inverted`, to use this optimized
|
||||
implementation when available, instead of having to invert on the fly.
|
||||
|
||||
*See also* :func:`bidict.inverted`
|
||||
"""
|
||||
return iter(self.inverse.items())
|
||||
|
||||
|
||||
class MutableBidirectionalMapping(BidirectionalMapping[KT, VT], t.MutableMapping[KT, VT]):
|
||||
"""Abstract base class for mutable bidirectional mapping types."""
|
||||
|
||||
__slots__ = ()
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
# ============================================================================
|
||||
# ← Prev: __init__.py Current: _abc.py Next: _base.py →
|
||||
# ============================================================================
|
||||
556
env/lib/python3.10/site-packages/bidict/_base.py
vendored
556
env/lib/python3.10/site-packages/bidict/_base.py
vendored
@ -1,556 +0,0 @@
|
||||
# Copyright 2009-2024 Joshua Bronson. All rights reserved.
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
# (see comments in __init__.py)
|
||||
# ============================================================================
|
||||
# ← Prev: _abc.py Current: _base.py Next: _frozen.py →
|
||||
# ============================================================================
|
||||
|
||||
|
||||
"""Provide :class:`BidictBase`."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import typing as t
|
||||
import weakref
|
||||
from itertools import starmap
|
||||
from operator import eq
|
||||
from types import MappingProxyType
|
||||
|
||||
from ._abc import BidirectionalMapping
|
||||
from ._dup import DROP_NEW
|
||||
from ._dup import DROP_OLD
|
||||
from ._dup import ON_DUP_DEFAULT
|
||||
from ._dup import RAISE
|
||||
from ._dup import OnDup
|
||||
from ._exc import DuplicationError
|
||||
from ._exc import KeyAndValueDuplicationError
|
||||
from ._exc import KeyDuplicationError
|
||||
from ._exc import ValueDuplicationError
|
||||
from ._iter import inverted
|
||||
from ._iter import iteritems
|
||||
from ._typing import KT
|
||||
from ._typing import MISSING
|
||||
from ._typing import OKT
|
||||
from ._typing import OVT
|
||||
from ._typing import VT
|
||||
from ._typing import Maplike
|
||||
from ._typing import MapOrItems
|
||||
|
||||
|
||||
OldKV = t.Tuple[OKT[KT], OVT[VT]]
|
||||
DedupResult = t.Optional[OldKV[KT, VT]]
|
||||
Unwrites = t.List[t.Tuple[t.Any, ...]]
|
||||
BT = t.TypeVar('BT', bound='BidictBase[t.Any, t.Any]')
|
||||
|
||||
|
||||
class BidictKeysView(t.KeysView[KT], t.ValuesView[KT]):
|
||||
"""Since the keys of a bidict are the values of its inverse (and vice versa),
|
||||
the :class:`~collections.abc.ValuesView` result of calling *bi.values()*
|
||||
is also a :class:`~collections.abc.KeysView` of *bi.inverse*.
|
||||
"""
|
||||
|
||||
|
||||
class BidictBase(BidirectionalMapping[KT, VT]):
|
||||
"""Base class implementing :class:`BidirectionalMapping`."""
|
||||
|
||||
#: The default :class:`~bidict.OnDup`
|
||||
#: that governs behavior when a provided item
|
||||
#: duplicates the key or value of other item(s).
|
||||
#:
|
||||
#: *See also*
|
||||
#: :ref:`basic-usage:Values Must Be Unique` (https://bidict.rtfd.io/basic-usage.html#values-must-be-unique),
|
||||
#: :doc:`extending` (https://bidict.rtfd.io/extending.html)
|
||||
on_dup = ON_DUP_DEFAULT
|
||||
|
||||
_fwdm: t.MutableMapping[KT, VT] #: the backing forward mapping (*key* → *val*)
|
||||
_invm: t.MutableMapping[VT, KT] #: the backing inverse mapping (*val* → *key*)
|
||||
|
||||
# Use Any rather than KT/VT in the following to avoid "ClassVar cannot contain type variables" errors:
|
||||
_fwdm_cls: t.ClassVar[type[t.MutableMapping[t.Any, t.Any]]] = dict #: class of the backing forward mapping
|
||||
_invm_cls: t.ClassVar[type[t.MutableMapping[t.Any, t.Any]]] = dict #: class of the backing inverse mapping
|
||||
|
||||
#: The class of the inverse bidict instance.
|
||||
_inv_cls: t.ClassVar[type[BidictBase[t.Any, t.Any]]]
|
||||
|
||||
def __init_subclass__(cls) -> None:
|
||||
super().__init_subclass__()
|
||||
cls._init_class()
|
||||
|
||||
@classmethod
|
||||
def _init_class(cls) -> None:
|
||||
cls._ensure_inv_cls()
|
||||
cls._set_reversed()
|
||||
|
||||
__reversed__: t.ClassVar[t.Any]
|
||||
|
||||
@classmethod
|
||||
def _set_reversed(cls) -> None:
|
||||
"""Set __reversed__ for subclasses that do not set it explicitly
|
||||
according to whether backing mappings are reversible.
|
||||
"""
|
||||
if cls is not BidictBase:
|
||||
resolved = cls.__reversed__
|
||||
overridden = resolved is not BidictBase.__reversed__
|
||||
if overridden: # E.g. OrderedBidictBase, OrderedBidict
|
||||
return
|
||||
backing_reversible = all(issubclass(i, t.Reversible) for i in (cls._fwdm_cls, cls._invm_cls))
|
||||
cls.__reversed__ = _fwdm_reversed if backing_reversible else None
|
||||
|
||||
@classmethod
|
||||
def _ensure_inv_cls(cls) -> None:
|
||||
"""Ensure :attr:`_inv_cls` is set, computing it dynamically if necessary.
|
||||
|
||||
All subclasses provided in :mod:`bidict` are their own inverse classes,
|
||||
i.e., their backing forward and inverse mappings are both the same type,
|
||||
but users may define subclasses where this is not the case.
|
||||
This method ensures that the inverse class is computed correctly regardless.
|
||||
|
||||
See: :ref:`extending:Dynamic Inverse Class Generation`
|
||||
(https://bidict.rtfd.io/extending.html#dynamic-inverse-class-generation)
|
||||
"""
|
||||
# This _ensure_inv_cls() method is (indirectly) corecursive with _make_inv_cls() below
|
||||
# in the case that we need to dynamically generate the inverse class:
|
||||
# 1. _ensure_inv_cls() calls cls._make_inv_cls()
|
||||
# 2. cls._make_inv_cls() calls type(..., (cls, ...), ...) to dynamically generate inv_cls
|
||||
# 3. Our __init_subclass__ hook (see above) is automatically called on inv_cls
|
||||
# 4. inv_cls.__init_subclass__() calls inv_cls._ensure_inv_cls()
|
||||
# 5. inv_cls._ensure_inv_cls() resolves to this implementation
|
||||
# (inv_cls deliberately does not override this), so we're back where we started.
|
||||
# But since the _make_inv_cls() call will have set inv_cls.__dict__._inv_cls,
|
||||
# just check if it's already set before calling _make_inv_cls() to prevent infinite recursion.
|
||||
if getattr(cls, '__dict__', {}).get('_inv_cls'): # Don't assume cls.__dict__ (e.g. mypyc native class)
|
||||
return
|
||||
cls._inv_cls = cls._make_inv_cls()
|
||||
|
||||
@classmethod
|
||||
def _make_inv_cls(cls: type[BT]) -> type[BT]:
|
||||
diff = cls._inv_cls_dict_diff()
|
||||
cls_is_own_inv = all(getattr(cls, k, MISSING) == v for (k, v) in diff.items())
|
||||
if cls_is_own_inv:
|
||||
return cls
|
||||
# Suppress auto-calculation of _inv_cls's _inv_cls since we know it already.
|
||||
# Works with the guard in BidictBase._ensure_inv_cls() to prevent infinite recursion.
|
||||
diff['_inv_cls'] = cls
|
||||
inv_cls = type(f'{cls.__name__}Inv', (cls, GeneratedBidictInverse), diff)
|
||||
inv_cls.__module__ = cls.__module__
|
||||
return t.cast(t.Type[BT], inv_cls)
|
||||
|
||||
@classmethod
|
||||
def _inv_cls_dict_diff(cls) -> dict[str, t.Any]:
|
||||
return {
|
||||
'_fwdm_cls': cls._invm_cls,
|
||||
'_invm_cls': cls._fwdm_cls,
|
||||
}
|
||||
|
||||
def __init__(self, arg: MapOrItems[KT, VT] = (), /, **kw: VT) -> None:
|
||||
"""Make a new bidirectional mapping.
|
||||
The signature behaves like that of :class:`dict`.
|
||||
ktems passed via positional arg are processed first,
|
||||
followed by any items passed via keyword argument.
|
||||
Any duplication encountered along the way
|
||||
is handled as per :attr:`on_dup`.
|
||||
"""
|
||||
self._fwdm = self._fwdm_cls()
|
||||
self._invm = self._invm_cls()
|
||||
self._update(arg, kw, rollback=False)
|
||||
|
||||
# If Python ever adds support for higher-kinded types, `inverse` could use them, e.g.
|
||||
# def inverse(self: BT[KT, VT]) -> BT[VT, KT]:
|
||||
# Ref: https://github.com/python/typing/issues/548#issuecomment-621571821
|
||||
@property
|
||||
def inverse(self) -> BidictBase[VT, KT]:
|
||||
"""The inverse of this bidirectional mapping instance."""
|
||||
# When `bi.inverse` is called for the first time, this method
|
||||
# computes the inverse instance, stores it for subsequent use, and then
|
||||
# returns it. It also stores a reference on `bi.inverse` back to `bi`,
|
||||
# but uses a weakref to avoid creating a reference cycle. Strong references
|
||||
# to inverse instances are stored in ._inv, and weak references are stored
|
||||
# in ._invweak.
|
||||
|
||||
# First check if a strong reference is already stored.
|
||||
inv: BidictBase[VT, KT] | None = getattr(self, '_inv', None)
|
||||
if inv is not None:
|
||||
return inv
|
||||
# Next check if a weak reference is already stored.
|
||||
invweak = getattr(self, '_invweak', None)
|
||||
if invweak is not None:
|
||||
inv = invweak() # Try to resolve a strong reference and return it.
|
||||
if inv is not None:
|
||||
return inv
|
||||
# No luck. Compute the inverse reference and store it for subsequent use.
|
||||
inv = self._make_inverse()
|
||||
self._inv: BidictBase[VT, KT] | None = inv
|
||||
self._invweak: weakref.ReferenceType[BidictBase[VT, KT]] | None = None
|
||||
# Also store a weak reference back to `instance` on its inverse instance, so that
|
||||
# the second `.inverse` access in `bi.inverse.inverse` hits the cached weakref.
|
||||
inv._inv = None
|
||||
inv._invweak = weakref.ref(self)
|
||||
# In e.g. `bidict().inverse.inverse`, this design ensures that a strong reference
|
||||
# back to the original instance is retained before its refcount drops to zero,
|
||||
# avoiding an unintended potential deallocation.
|
||||
return inv
|
||||
|
||||
def _make_inverse(self) -> BidictBase[VT, KT]:
|
||||
inv: BidictBase[VT, KT] = self._inv_cls()
|
||||
inv._fwdm = self._invm
|
||||
inv._invm = self._fwdm
|
||||
return inv
|
||||
|
||||
@property
|
||||
def inv(self) -> BidictBase[VT, KT]:
|
||||
"""Alias for :attr:`inverse`."""
|
||||
return self.inverse
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""See :func:`repr`."""
|
||||
clsname = self.__class__.__name__
|
||||
items = dict(self.items()) if self else ''
|
||||
return f'{clsname}({items})'
|
||||
|
||||
def values(self) -> BidictKeysView[VT]:
|
||||
"""A set-like object providing a view on the contained values.
|
||||
|
||||
Since the values of a bidict are equivalent to the keys of its inverse,
|
||||
this method returns a set-like object for this bidict's values
|
||||
rather than just a collections.abc.ValuesView.
|
||||
This object supports set operations like union and difference,
|
||||
and constant- rather than linear-time containment checks,
|
||||
and is no more expensive to provide than the less capable
|
||||
collections.abc.ValuesView would be.
|
||||
|
||||
See :meth:`keys` for more information.
|
||||
"""
|
||||
return t.cast(BidictKeysView[VT], self.inverse.keys())
|
||||
|
||||
def keys(self) -> t.KeysView[KT]:
|
||||
"""A set-like object providing a view on the contained keys.
|
||||
|
||||
When *b._fwdm* is a :class:`dict`, *b.keys()* returns a
|
||||
*dict_keys* object that behaves exactly the same as
|
||||
*collections.abc.KeysView(b)*, except for
|
||||
|
||||
- offering better performance
|
||||
|
||||
- being reversible on Python 3.8+
|
||||
|
||||
- having a .mapping attribute in Python 3.10+
|
||||
that exposes a mappingproxy to *b._fwdm*.
|
||||
"""
|
||||
fwdm, fwdm_cls = self._fwdm, self._fwdm_cls
|
||||
return fwdm.keys() if fwdm_cls is dict else BidictKeysView(self)
|
||||
|
||||
def items(self) -> t.ItemsView[KT, VT]:
|
||||
"""A set-like object providing a view on the contained items.
|
||||
|
||||
When *b._fwdm* is a :class:`dict`, *b.items()* returns a
|
||||
*dict_items* object that behaves exactly the same as
|
||||
*collections.abc.ItemsView(b)*, except for:
|
||||
|
||||
- offering better performance
|
||||
|
||||
- being reversible on Python 3.8+
|
||||
|
||||
- having a .mapping attribute in Python 3.10+
|
||||
that exposes a mappingproxy to *b._fwdm*.
|
||||
"""
|
||||
return self._fwdm.items() if self._fwdm_cls is dict else super().items()
|
||||
|
||||
# The inherited collections.abc.Mapping.__contains__() method is implemented by doing a `try`
|
||||
# `except KeyError` around `self[key]`. The following implementation is much faster,
|
||||
# especially in the missing case.
|
||||
def __contains__(self, key: t.Any) -> bool:
|
||||
"""True if the mapping contains the specified key, else False."""
|
||||
return key in self._fwdm
|
||||
|
||||
# The inherited collections.abc.Mapping.__eq__() method is implemented in terms of an inefficient
|
||||
# `dict(self.items()) == dict(other.items())` comparison, so override it with a
|
||||
# more efficient implementation.
|
||||
def __eq__(self, other: object) -> bool:
|
||||
"""*x.__eq__(other) ⟺ x == other*
|
||||
|
||||
Equivalent to *dict(x.items()) == dict(other.items())*
|
||||
but more efficient.
|
||||
|
||||
Note that :meth:`bidict's __eq__() <bidict.BidictBase.__eq__>` implementation
|
||||
is inherited by subclasses,
|
||||
in particular by the ordered bidict subclasses,
|
||||
so even with ordered bidicts,
|
||||
:ref:`== comparison is order-insensitive <eq-order-insensitive>`
|
||||
(https://bidict.rtfd.io/other-bidict-types.html#eq-is-order-insensitive).
|
||||
|
||||
*See also* :meth:`equals_order_sensitive`
|
||||
"""
|
||||
if isinstance(other, t.Mapping):
|
||||
return self._fwdm.items() == other.items()
|
||||
# Ref: https://docs.python.org/3/library/constants.html#NotImplemented
|
||||
return NotImplemented
|
||||
|
||||
def equals_order_sensitive(self, other: object) -> bool:
|
||||
"""Order-sensitive equality check.
|
||||
|
||||
*See also* :ref:`eq-order-insensitive`
|
||||
(https://bidict.rtfd.io/other-bidict-types.html#eq-is-order-insensitive)
|
||||
"""
|
||||
if not isinstance(other, t.Mapping) or len(self) != len(other):
|
||||
return False
|
||||
return all(starmap(eq, zip(self.items(), other.items())))
|
||||
|
||||
def _dedup(self, key: KT, val: VT, on_dup: OnDup) -> DedupResult[KT, VT]:
|
||||
"""Check *key* and *val* for any duplication in self.
|
||||
|
||||
Handle any duplication as per the passed in *on_dup*.
|
||||
|
||||
If (key, val) is already present, return None
|
||||
since writing (key, val) would be a no-op.
|
||||
|
||||
If duplication is found and the corresponding :class:`~bidict.OnDupAction` is
|
||||
:attr:`~bidict.DROP_NEW`, return None.
|
||||
|
||||
If duplication is found and the corresponding :class:`~bidict.OnDupAction` is
|
||||
:attr:`~bidict.RAISE`, raise the appropriate exception.
|
||||
|
||||
If duplication is found and the corresponding :class:`~bidict.OnDupAction` is
|
||||
:attr:`~bidict.DROP_OLD`, or if no duplication is found,
|
||||
return *(oldkey, oldval)*.
|
||||
"""
|
||||
fwdm, invm = self._fwdm, self._invm
|
||||
oldval: OVT[VT] = fwdm.get(key, MISSING)
|
||||
oldkey: OKT[KT] = invm.get(val, MISSING)
|
||||
isdupkey, isdupval = oldval is not MISSING, oldkey is not MISSING
|
||||
if isdupkey and isdupval:
|
||||
if key == oldkey:
|
||||
assert val == oldval
|
||||
# (key, val) duplicates an existing item -> no-op.
|
||||
return None
|
||||
# key and val each duplicate a different existing item.
|
||||
if on_dup.val is RAISE:
|
||||
raise KeyAndValueDuplicationError(key, val)
|
||||
if on_dup.val is DROP_NEW:
|
||||
return None
|
||||
assert on_dup.val is DROP_OLD
|
||||
# Fall through to the return statement on the last line.
|
||||
elif isdupkey:
|
||||
if on_dup.key is RAISE:
|
||||
raise KeyDuplicationError(key)
|
||||
if on_dup.key is DROP_NEW:
|
||||
return None
|
||||
assert on_dup.key is DROP_OLD
|
||||
# Fall through to the return statement on the last line.
|
||||
elif isdupval:
|
||||
if on_dup.val is RAISE:
|
||||
raise ValueDuplicationError(val)
|
||||
if on_dup.val is DROP_NEW:
|
||||
return None
|
||||
assert on_dup.val is DROP_OLD
|
||||
# Fall through to the return statement on the last line.
|
||||
# else neither isdupkey nor isdupval.
|
||||
return oldkey, oldval
|
||||
|
||||
def _write(self, newkey: KT, newval: VT, oldkey: OKT[KT], oldval: OVT[VT], unwrites: Unwrites | None) -> None:
|
||||
"""Insert (newkey, newval), extending *unwrites* with associated inverse operations if provided.
|
||||
|
||||
*oldkey* and *oldval* are as returned by :meth:`_dedup`.
|
||||
|
||||
If *unwrites* is not None, it is extended with the inverse operations necessary to undo the write.
|
||||
This design allows :meth:`_update` to roll back a partially applied update that fails part-way through
|
||||
when necessary.
|
||||
|
||||
This design also allows subclasses that require additional operations to easily extend this implementation.
|
||||
For example, :class:`bidict.OrderedBidictBase` calls this inherited implementation, and then extends *unwrites*
|
||||
with additional operations needed to keep its internal linked list nodes consistent with its items' order
|
||||
as changes are made.
|
||||
"""
|
||||
fwdm, invm = self._fwdm, self._invm
|
||||
fwdm_set, invm_set = fwdm.__setitem__, invm.__setitem__
|
||||
fwdm_del, invm_del = fwdm.__delitem__, invm.__delitem__
|
||||
# Always perform the following writes regardless of duplication.
|
||||
fwdm_set(newkey, newval)
|
||||
invm_set(newval, newkey)
|
||||
if oldval is MISSING and oldkey is MISSING: # no key or value duplication
|
||||
# {0: 1, 2: 3} | {4: 5} => {0: 1, 2: 3, 4: 5}
|
||||
if unwrites is not None:
|
||||
unwrites.extend((
|
||||
(fwdm_del, newkey),
|
||||
(invm_del, newval),
|
||||
))
|
||||
elif oldval is not MISSING and oldkey is not MISSING: # key and value duplication across two different items
|
||||
# {0: 1, 2: 3} | {0: 3} => {0: 3}
|
||||
fwdm_del(oldkey)
|
||||
invm_del(oldval)
|
||||
if unwrites is not None:
|
||||
unwrites.extend((
|
||||
(fwdm_set, newkey, oldval),
|
||||
(invm_set, oldval, newkey),
|
||||
(fwdm_set, oldkey, newval),
|
||||
(invm_set, newval, oldkey),
|
||||
))
|
||||
elif oldval is not MISSING: # just key duplication
|
||||
# {0: 1, 2: 3} | {2: 4} => {0: 1, 2: 4}
|
||||
invm_del(oldval)
|
||||
if unwrites is not None:
|
||||
unwrites.extend((
|
||||
(fwdm_set, newkey, oldval),
|
||||
(invm_set, oldval, newkey),
|
||||
(invm_del, newval),
|
||||
))
|
||||
else:
|
||||
assert oldkey is not MISSING # just value duplication
|
||||
# {0: 1, 2: 3} | {4: 3} => {0: 1, 4: 3}
|
||||
fwdm_del(oldkey)
|
||||
if unwrites is not None:
|
||||
unwrites.extend((
|
||||
(fwdm_set, oldkey, newval),
|
||||
(invm_set, newval, oldkey),
|
||||
(fwdm_del, newkey),
|
||||
))
|
||||
|
||||
def _update(
|
||||
self,
|
||||
arg: MapOrItems[KT, VT],
|
||||
kw: t.Mapping[str, VT] = MappingProxyType({}),
|
||||
*,
|
||||
rollback: bool | None = None,
|
||||
on_dup: OnDup | None = None,
|
||||
) -> None:
|
||||
"""Update with the items from *arg* and *kw*, maybe failing and rolling back as per *on_dup* and *rollback*."""
|
||||
# Note: We must process input in a single pass, since arg may be a generator.
|
||||
if not isinstance(arg, (t.Iterable, Maplike)):
|
||||
raise TypeError(f"'{arg.__class__.__name__}' object is not iterable")
|
||||
if not arg and not kw:
|
||||
return
|
||||
if on_dup is None:
|
||||
on_dup = self.on_dup
|
||||
if rollback is None:
|
||||
rollback = RAISE in on_dup
|
||||
|
||||
# Fast path when we're empty and updating only from another bidict (i.e. no dup vals in new items).
|
||||
if not self and not kw and isinstance(arg, BidictBase):
|
||||
self._init_from(arg)
|
||||
return
|
||||
|
||||
# Fast path when we're adding more items than we contain already and rollback is enabled:
|
||||
# Update a copy of self with rollback disabled. Fail if that fails, otherwise become the copy.
|
||||
if rollback and isinstance(arg, t.Sized) and len(arg) + len(kw) > len(self):
|
||||
tmp = self.copy()
|
||||
tmp._update(arg, kw, rollback=False, on_dup=on_dup)
|
||||
self._init_from(tmp)
|
||||
return
|
||||
|
||||
# In all other cases, benchmarking has indicated that the update is best implemented as follows:
|
||||
# For each new item, perform a dup check (raising if necessary), and apply the associated writes we need to
|
||||
# perform on our backing _fwdm and _invm mappings. If rollback is enabled, also compute the associated unwrites
|
||||
# as we go. If the update results in a DuplicationError and rollback is enabled, apply the accumulated unwrites
|
||||
# before raising, to ensure that we fail clean.
|
||||
write = self._write
|
||||
unwrites: Unwrites | None = [] if rollback else None
|
||||
for key, val in iteritems(arg, **kw):
|
||||
try:
|
||||
dedup_result = self._dedup(key, val, on_dup)
|
||||
except DuplicationError:
|
||||
if unwrites is not None:
|
||||
for fn, *args in reversed(unwrites):
|
||||
fn(*args)
|
||||
raise
|
||||
if dedup_result is not None:
|
||||
write(key, val, *dedup_result, unwrites=unwrites)
|
||||
|
||||
def __copy__(self: BT) -> BT:
|
||||
"""Used for the copy protocol. See the :mod:`copy` module."""
|
||||
return self.copy()
|
||||
|
||||
def copy(self: BT) -> BT:
|
||||
"""Make a (shallow) copy of this bidict."""
|
||||
# Could just `return self.__class__(self)` here, but the below is faster. The former
|
||||
# would copy this bidict's items into a new instance one at a time (checking for duplication
|
||||
# for each item), whereas the below copies from the backing mappings all at once, and foregoes
|
||||
# item-by-item duplication checking since the backing mappings have been checked already.
|
||||
return self._from_other(self.__class__, self)
|
||||
|
||||
@staticmethod
|
||||
def _from_other(bt: type[BT], other: MapOrItems[KT, VT], inv: bool = False) -> BT:
|
||||
"""Fast, private constructor based on :meth:`_init_from`.
|
||||
|
||||
If *inv* is true, return the inverse of the instance instead of the instance itself.
|
||||
(Useful for pickling with dynamically-generated inverse classes -- see :meth:`__reduce__`.)
|
||||
"""
|
||||
inst = bt()
|
||||
inst._init_from(other)
|
||||
return t.cast(BT, inst.inverse) if inv else inst
|
||||
|
||||
def _init_from(self, other: MapOrItems[KT, VT]) -> None:
|
||||
"""Fast init from *other*, bypassing item-by-item duplication checking."""
|
||||
self._fwdm.clear()
|
||||
self._invm.clear()
|
||||
self._fwdm.update(other)
|
||||
# If other is a bidict, use its existing backing inverse mapping, otherwise
|
||||
# other could be a generator that's now exhausted, so invert self._fwdm on the fly.
|
||||
inv = other.inverse if isinstance(other, BidictBase) else inverted(self._fwdm)
|
||||
self._invm.update(inv)
|
||||
|
||||
# other's type is Mapping rather than Maplike since bidict() | SupportsKeysAndGetItem({})
|
||||
# raises a TypeError, just like dict() | SupportsKeysAndGetItem({}) does.
|
||||
def __or__(self: BT, other: t.Mapping[KT, VT]) -> BT:
|
||||
"""Return self|other."""
|
||||
if not isinstance(other, t.Mapping):
|
||||
return NotImplemented
|
||||
new = self.copy()
|
||||
new._update(other, rollback=False)
|
||||
return new
|
||||
|
||||
def __ror__(self: BT, other: t.Mapping[KT, VT]) -> BT:
|
||||
"""Return other|self."""
|
||||
if not isinstance(other, t.Mapping):
|
||||
return NotImplemented
|
||||
new = self.__class__(other)
|
||||
new._update(self, rollback=False)
|
||||
return new
|
||||
|
||||
def __len__(self) -> int:
|
||||
"""The number of contained items."""
|
||||
return len(self._fwdm)
|
||||
|
||||
def __iter__(self) -> t.Iterator[KT]:
|
||||
"""Iterator over the contained keys."""
|
||||
return iter(self._fwdm)
|
||||
|
||||
def __getitem__(self, key: KT) -> VT:
|
||||
"""*x.__getitem__(key) ⟺ x[key]*"""
|
||||
return self._fwdm[key]
|
||||
|
||||
def __reduce__(self) -> tuple[t.Any, ...]:
|
||||
"""Return state information for pickling."""
|
||||
cls = self.__class__
|
||||
inst: t.Mapping[t.Any, t.Any] = self
|
||||
# If this bidict's class is dynamically generated, pickle the inverse instead, whose (presumably not
|
||||
# dynamically generated) class the caller is more likely to have a reference to somewhere in sys.modules
|
||||
# that pickle can discover.
|
||||
if should_invert := isinstance(self, GeneratedBidictInverse):
|
||||
cls = self._inv_cls
|
||||
inst = self.inverse
|
||||
return self._from_other, (cls, dict(inst), should_invert)
|
||||
|
||||
|
||||
# See BidictBase._set_reversed() above.
|
||||
def _fwdm_reversed(self: BidictBase[KT, t.Any]) -> t.Iterator[KT]:
|
||||
"""Iterator over the contained keys in reverse order."""
|
||||
assert isinstance(self._fwdm, t.Reversible)
|
||||
return reversed(self._fwdm)
|
||||
|
||||
|
||||
BidictBase._init_class()
|
||||
|
||||
|
||||
class GeneratedBidictInverse:
|
||||
"""Base class for dynamically-generated inverse bidict classes."""
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
# ============================================================================
|
||||
# ← Prev: _abc.py Current: _base.py Next: _frozen.py →
|
||||
# ============================================================================
|
||||
194
env/lib/python3.10/site-packages/bidict/_bidict.py
vendored
194
env/lib/python3.10/site-packages/bidict/_bidict.py
vendored
@ -1,194 +0,0 @@
|
||||
# Copyright 2009-2024 Joshua Bronson. All rights reserved.
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
# (see comments in __init__.py)
|
||||
# ============================================================================
|
||||
# ← Prev: _frozen.py Current: _bidict.py Next: _orderedbase.py →
|
||||
# ============================================================================
|
||||
|
||||
|
||||
"""Provide :class:`MutableBidict` and :class:`bidict`."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import typing as t
|
||||
|
||||
from ._abc import MutableBidirectionalMapping
|
||||
from ._base import BidictBase
|
||||
from ._dup import ON_DUP_DROP_OLD
|
||||
from ._dup import ON_DUP_RAISE
|
||||
from ._dup import OnDup
|
||||
from ._typing import DT
|
||||
from ._typing import KT
|
||||
from ._typing import MISSING
|
||||
from ._typing import ODT
|
||||
from ._typing import VT
|
||||
from ._typing import MapOrItems
|
||||
|
||||
|
||||
class MutableBidict(BidictBase[KT, VT], MutableBidirectionalMapping[KT, VT]):
|
||||
"""Base class for mutable bidirectional mappings."""
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
|
||||
@property
|
||||
def inverse(self) -> MutableBidict[VT, KT]: ...
|
||||
|
||||
@property
|
||||
def inv(self) -> MutableBidict[VT, KT]: ...
|
||||
|
||||
def _pop(self, key: KT) -> VT:
|
||||
val = self._fwdm.pop(key)
|
||||
del self._invm[val]
|
||||
return val
|
||||
|
||||
def __delitem__(self, key: KT) -> None:
|
||||
"""*x.__delitem__(y) ⟺ del x[y]*"""
|
||||
self._pop(key)
|
||||
|
||||
def __setitem__(self, key: KT, val: VT) -> None:
|
||||
"""Set the value for *key* to *val*.
|
||||
|
||||
If *key* is already associated with *val*, this is a no-op.
|
||||
|
||||
If *key* is already associated with a different value,
|
||||
the old value will be replaced with *val*,
|
||||
as with dict's :meth:`__setitem__`.
|
||||
|
||||
If *val* is already associated with a different key,
|
||||
an exception is raised
|
||||
to protect against accidental removal of the key
|
||||
that's currently associated with *val*.
|
||||
|
||||
Use :meth:`put` instead if you want to specify different behavior in
|
||||
the case that the provided key or value duplicates an existing one.
|
||||
Or use :meth:`forceput` to unconditionally associate *key* with *val*,
|
||||
replacing any existing items as necessary to preserve uniqueness.
|
||||
|
||||
:raises bidict.ValueDuplicationError: if *val* duplicates that of an
|
||||
existing item.
|
||||
|
||||
:raises bidict.KeyAndValueDuplicationError: if *key* duplicates the key of an
|
||||
existing item and *val* duplicates the value of a different
|
||||
existing item.
|
||||
"""
|
||||
self.put(key, val, on_dup=self.on_dup)
|
||||
|
||||
def put(self, key: KT, val: VT, on_dup: OnDup = ON_DUP_RAISE) -> None:
|
||||
"""Associate *key* with *val*, honoring the :class:`OnDup` given in *on_dup*.
|
||||
|
||||
For example, if *on_dup* is :attr:`~bidict.ON_DUP_RAISE`,
|
||||
then *key* will be associated with *val* if and only if
|
||||
*key* is not already associated with an existing value and
|
||||
*val* is not already associated with an existing key,
|
||||
otherwise an exception will be raised.
|
||||
|
||||
If *key* is already associated with *val*, this is a no-op.
|
||||
|
||||
:raises bidict.KeyDuplicationError: if attempting to insert an item
|
||||
whose key only duplicates an existing item's, and *on_dup.key* is
|
||||
:attr:`~bidict.RAISE`.
|
||||
|
||||
:raises bidict.ValueDuplicationError: if attempting to insert an item
|
||||
whose value only duplicates an existing item's, and *on_dup.val* is
|
||||
:attr:`~bidict.RAISE`.
|
||||
|
||||
:raises bidict.KeyAndValueDuplicationError: if attempting to insert an
|
||||
item whose key duplicates one existing item's, and whose value
|
||||
duplicates another existing item's, and *on_dup.val* is
|
||||
:attr:`~bidict.RAISE`.
|
||||
"""
|
||||
self._update(((key, val),), on_dup=on_dup)
|
||||
|
||||
def forceput(self, key: KT, val: VT) -> None:
|
||||
"""Associate *key* with *val* unconditionally.
|
||||
|
||||
Replace any existing mappings containing key *key* or value *val*
|
||||
as necessary to preserve uniqueness.
|
||||
"""
|
||||
self.put(key, val, on_dup=ON_DUP_DROP_OLD)
|
||||
|
||||
def clear(self) -> None:
|
||||
"""Remove all items."""
|
||||
self._fwdm.clear()
|
||||
self._invm.clear()
|
||||
|
||||
@t.overload
|
||||
def pop(self, key: KT, /) -> VT: ...
|
||||
@t.overload
|
||||
def pop(self, key: KT, default: DT = ..., /) -> VT | DT: ...
|
||||
|
||||
def pop(self, key: KT, default: ODT[DT] = MISSING, /) -> VT | DT:
|
||||
"""*x.pop(k[, d]) → v*
|
||||
|
||||
Remove specified key and return the corresponding value.
|
||||
|
||||
:raises KeyError: if *key* is not found and no *default* is provided.
|
||||
"""
|
||||
try:
|
||||
return self._pop(key)
|
||||
except KeyError:
|
||||
if default is MISSING:
|
||||
raise
|
||||
return default
|
||||
|
||||
def popitem(self) -> tuple[KT, VT]:
|
||||
"""*x.popitem() → (k, v)*
|
||||
|
||||
Remove and return some item as a (key, value) pair.
|
||||
|
||||
:raises KeyError: if *x* is empty.
|
||||
"""
|
||||
key, val = self._fwdm.popitem()
|
||||
del self._invm[val]
|
||||
return key, val
|
||||
|
||||
def update(self, arg: MapOrItems[KT, VT] = (), /, **kw: VT) -> None:
|
||||
"""Like calling :meth:`putall` with *self.on_dup* passed for *on_dup*."""
|
||||
self._update(arg, kw=kw)
|
||||
|
||||
def forceupdate(self, arg: MapOrItems[KT, VT] = (), /, **kw: VT) -> None:
|
||||
"""Like a bulk :meth:`forceput`."""
|
||||
self._update(arg, kw=kw, on_dup=ON_DUP_DROP_OLD)
|
||||
|
||||
def putall(self, items: MapOrItems[KT, VT], on_dup: OnDup = ON_DUP_RAISE) -> None:
|
||||
"""Like a bulk :meth:`put`.
|
||||
|
||||
If one of the given items causes an exception to be raised,
|
||||
none of the items is inserted.
|
||||
"""
|
||||
self._update(items, on_dup=on_dup)
|
||||
|
||||
# other's type is Mapping rather than Maplike since bidict() |= SupportsKeysAndGetItem({})
|
||||
# raises a TypeError, just like dict() |= SupportsKeysAndGetItem({}) does.
|
||||
def __ior__(self, other: t.Mapping[KT, VT]) -> MutableBidict[KT, VT]:
|
||||
"""Return self|=other."""
|
||||
self.update(other)
|
||||
return self
|
||||
|
||||
|
||||
class bidict(MutableBidict[KT, VT]):
|
||||
"""The main bidirectional mapping type.
|
||||
|
||||
See :ref:`intro:Introduction` and :ref:`basic-usage:Basic Usage`
|
||||
to get started (also available at https://bidict.rtfd.io).
|
||||
"""
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
|
||||
@property
|
||||
def inverse(self) -> bidict[VT, KT]: ...
|
||||
|
||||
@property
|
||||
def inv(self) -> bidict[VT, KT]: ...
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
# ============================================================================
|
||||
# ← Prev: _frozen.py Current: _bidict.py Next: _orderedbase.py →
|
||||
# ============================================================================
|
||||
61
env/lib/python3.10/site-packages/bidict/_dup.py
vendored
61
env/lib/python3.10/site-packages/bidict/_dup.py
vendored
@ -1,61 +0,0 @@
|
||||
# Copyright 2009-2024 Joshua Bronson. All rights reserved.
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
|
||||
"""Provide :class:`OnDup` and related functionality."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import typing as t
|
||||
from enum import Enum
|
||||
|
||||
|
||||
class OnDupAction(Enum):
|
||||
"""An action to take to prevent duplication from occurring."""
|
||||
|
||||
#: Raise a :class:`~bidict.DuplicationError`.
|
||||
RAISE = 'RAISE'
|
||||
#: Overwrite existing items with new items.
|
||||
DROP_OLD = 'DROP_OLD'
|
||||
#: Keep existing items and drop new items.
|
||||
DROP_NEW = 'DROP_NEW'
|
||||
|
||||
def __repr__(self) -> str:
|
||||
return f'{self.__class__.__name__}.{self.name}'
|
||||
|
||||
|
||||
RAISE: t.Final[OnDupAction] = OnDupAction.RAISE
|
||||
DROP_OLD: t.Final[OnDupAction] = OnDupAction.DROP_OLD
|
||||
DROP_NEW: t.Final[OnDupAction] = OnDupAction.DROP_NEW
|
||||
|
||||
|
||||
class OnDup(t.NamedTuple):
|
||||
r"""A combination of :class:`~bidict.OnDupAction`\s specifying how to handle various types of duplication.
|
||||
|
||||
The :attr:`~OnDup.key` field specifies what action to take when a duplicate key is encountered.
|
||||
|
||||
The :attr:`~OnDup.val` field specifies what action to take when a duplicate value is encountered.
|
||||
|
||||
In the case of both key and value duplication across two different items,
|
||||
only :attr:`~OnDup.val` is used.
|
||||
|
||||
*See also* :ref:`basic-usage:Values Must Be Unique`
|
||||
(https://bidict.rtfd.io/basic-usage.html#values-must-be-unique)
|
||||
"""
|
||||
|
||||
key: OnDupAction = DROP_OLD
|
||||
val: OnDupAction = RAISE
|
||||
|
||||
|
||||
#: Default :class:`OnDup` used for the
|
||||
#: :meth:`~bidict.bidict.__init__`,
|
||||
#: :meth:`~bidict.bidict.__setitem__`, and
|
||||
#: :meth:`~bidict.bidict.update` methods.
|
||||
ON_DUP_DEFAULT: t.Final[OnDup] = OnDup(key=DROP_OLD, val=RAISE)
|
||||
#: An :class:`OnDup` whose members are all :obj:`RAISE`.
|
||||
ON_DUP_RAISE: t.Final[OnDup] = OnDup(key=RAISE, val=RAISE)
|
||||
#: An :class:`OnDup` whose members are all :obj:`DROP_OLD`.
|
||||
ON_DUP_DROP_OLD: t.Final[OnDup] = OnDup(key=DROP_OLD, val=DROP_OLD)
|
||||
36
env/lib/python3.10/site-packages/bidict/_exc.py
vendored
36
env/lib/python3.10/site-packages/bidict/_exc.py
vendored
@ -1,36 +0,0 @@
|
||||
# Copyright 2009-2024 Joshua Bronson. All rights reserved.
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
|
||||
"""Provide all bidict exceptions."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
|
||||
class BidictException(Exception):
|
||||
"""Base class for bidict exceptions."""
|
||||
|
||||
|
||||
class DuplicationError(BidictException):
|
||||
"""Base class for exceptions raised when uniqueness is violated
|
||||
as per the :attr:`~bidict.RAISE` :class:`~bidict.OnDupAction`.
|
||||
"""
|
||||
|
||||
|
||||
class KeyDuplicationError(DuplicationError):
|
||||
"""Raised when a given key is not unique."""
|
||||
|
||||
|
||||
class ValueDuplicationError(DuplicationError):
|
||||
"""Raised when a given value is not unique."""
|
||||
|
||||
|
||||
class KeyAndValueDuplicationError(KeyDuplicationError, ValueDuplicationError):
|
||||
"""Raised when a given item's key and value are not unique.
|
||||
|
||||
That is, its key duplicates that of another item,
|
||||
and its value duplicates that of a different other item.
|
||||
"""
|
||||
@ -1,50 +0,0 @@
|
||||
# Copyright 2009-2024 Joshua Bronson. All rights reserved.
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
# (see comments in __init__.py)
|
||||
# ============================================================================
|
||||
# ← Prev: _base.py Current: _frozen.py Next: _bidict.py →
|
||||
# ============================================================================
|
||||
|
||||
"""Provide :class:`frozenbidict`, an immutable, hashable bidirectional mapping type."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import typing as t
|
||||
|
||||
from ._base import BidictBase
|
||||
from ._typing import KT
|
||||
from ._typing import VT
|
||||
|
||||
|
||||
class frozenbidict(BidictBase[KT, VT]):
|
||||
"""Immutable, hashable bidict type."""
|
||||
|
||||
_hash: int
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
|
||||
@property
|
||||
def inverse(self) -> frozenbidict[VT, KT]: ...
|
||||
|
||||
@property
|
||||
def inv(self) -> frozenbidict[VT, KT]: ...
|
||||
|
||||
def __hash__(self) -> int:
|
||||
"""The hash of this bidict as determined by its items."""
|
||||
if getattr(self, '_hash', None) is None:
|
||||
# The following is like hash(frozenset(self.items()))
|
||||
# but more memory efficient. See also: https://bugs.python.org/issue46684
|
||||
self._hash = t.ItemsView(self)._hash()
|
||||
return self._hash
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
# ============================================================================
|
||||
# ← Prev: _base.py Current: _frozen.py Next: _bidict.py →
|
||||
# ============================================================================
|
||||
51
env/lib/python3.10/site-packages/bidict/_iter.py
vendored
51
env/lib/python3.10/site-packages/bidict/_iter.py
vendored
@ -1,51 +0,0 @@
|
||||
# Copyright 2009-2024 Joshua Bronson. All rights reserved.
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
|
||||
"""Functions for iterating over items in a mapping."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import typing as t
|
||||
from operator import itemgetter
|
||||
|
||||
from ._typing import KT
|
||||
from ._typing import VT
|
||||
from ._typing import ItemsIter
|
||||
from ._typing import Maplike
|
||||
from ._typing import MapOrItems
|
||||
|
||||
|
||||
def iteritems(arg: MapOrItems[KT, VT] = (), /, **kw: VT) -> ItemsIter[KT, VT]:
|
||||
"""Yield the items from *arg* and *kw* in the order given."""
|
||||
if isinstance(arg, t.Mapping):
|
||||
yield from arg.items()
|
||||
elif isinstance(arg, Maplike):
|
||||
yield from ((k, arg[k]) for k in arg.keys())
|
||||
else:
|
||||
yield from arg
|
||||
yield from t.cast(ItemsIter[KT, VT], kw.items())
|
||||
|
||||
|
||||
swap: t.Final = itemgetter(1, 0)
|
||||
|
||||
|
||||
def inverted(arg: MapOrItems[KT, VT]) -> ItemsIter[VT, KT]:
|
||||
"""Yield the inverse items of the provided object.
|
||||
|
||||
If *arg* has a :func:`callable` ``__inverted__`` attribute,
|
||||
return the result of calling it.
|
||||
|
||||
Otherwise, return an iterator over the items in `arg`,
|
||||
inverting each item on the fly.
|
||||
|
||||
*See also* :attr:`bidict.BidirectionalMapping.__inverted__`
|
||||
"""
|
||||
invattr = getattr(arg, '__inverted__', None)
|
||||
if callable(invattr):
|
||||
inv: ItemsIter[VT, KT] = invattr()
|
||||
return inv
|
||||
return map(swap, iteritems(arg))
|
||||
@ -1,238 +0,0 @@
|
||||
# Copyright 2009-2024 Joshua Bronson. All rights reserved.
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
# (see comments in __init__.py)
|
||||
# ============================================================================
|
||||
# ← Prev: _bidict.py Current: _orderedbase.py Next: _orderedbidict.py →
|
||||
# ============================================================================
|
||||
|
||||
|
||||
"""Provide :class:`OrderedBidictBase`."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import typing as t
|
||||
from weakref import ref as weakref
|
||||
|
||||
from ._base import BidictBase
|
||||
from ._base import Unwrites
|
||||
from ._bidict import bidict
|
||||
from ._iter import iteritems
|
||||
from ._typing import KT
|
||||
from ._typing import MISSING
|
||||
from ._typing import OKT
|
||||
from ._typing import OVT
|
||||
from ._typing import VT
|
||||
from ._typing import MapOrItems
|
||||
|
||||
|
||||
AT = t.TypeVar('AT') # attr type
|
||||
|
||||
|
||||
class WeakAttr(t.Generic[AT]):
|
||||
"""Descriptor to automatically manage (de)referencing the given slot as a weakref.
|
||||
|
||||
See https://docs.python.org/3/howto/descriptor.html#managed-attributes
|
||||
for an intro to using descriptors like this for managed attributes.
|
||||
"""
|
||||
|
||||
def __init__(self, *, slot: str) -> None:
|
||||
self.slot = slot
|
||||
|
||||
def __set__(self, instance: t.Any, value: AT) -> None:
|
||||
setattr(instance, self.slot, weakref(value))
|
||||
|
||||
def __get__(self, instance: t.Any, __owner: t.Any = None) -> AT:
|
||||
return t.cast(AT, getattr(instance, self.slot)())
|
||||
|
||||
|
||||
class Node:
|
||||
"""A node in a circular doubly-linked list
|
||||
used to encode the order of items in an ordered bidict.
|
||||
|
||||
A weak reference to the previous node is stored
|
||||
to avoid creating strong reference cycles.
|
||||
Referencing/dereferencing the weakref is handled automatically by :class:`WeakAttr`.
|
||||
"""
|
||||
|
||||
prv: WeakAttr[Node] = WeakAttr(slot='_prv_weak')
|
||||
__slots__ = ('__weakref__', '_prv_weak', 'nxt')
|
||||
|
||||
nxt: Node | WeakAttr[Node] # Allow subclasses to use a WeakAttr for nxt too (see SentinelNode)
|
||||
|
||||
def __init__(self, prv: Node, nxt: Node) -> None:
|
||||
self.prv = prv
|
||||
self.nxt = nxt
|
||||
|
||||
def unlink(self) -> None:
|
||||
"""Remove self from in between prv and nxt.
|
||||
Self's references to prv and nxt are retained so it can be relinked (see below).
|
||||
"""
|
||||
self.prv.nxt = self.nxt
|
||||
self.nxt.prv = self.prv
|
||||
|
||||
def relink(self) -> None:
|
||||
"""Restore self between prv and nxt after unlinking (see above)."""
|
||||
self.prv.nxt = self.nxt.prv = self
|
||||
|
||||
|
||||
class SentinelNode(Node):
|
||||
"""Special node in a circular doubly-linked list
|
||||
that links the first node with the last node.
|
||||
When its next and previous references point back to itself
|
||||
it represents an empty list.
|
||||
"""
|
||||
|
||||
nxt: WeakAttr[Node] = WeakAttr(slot='_nxt_weak')
|
||||
__slots__ = ('_nxt_weak',)
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__(self, self)
|
||||
|
||||
def iternodes(self, *, reverse: bool = False) -> t.Iterator[Node]:
|
||||
"""Iterator yielding nodes in the requested order."""
|
||||
attr = 'prv' if reverse else 'nxt'
|
||||
node = getattr(self, attr)
|
||||
while node is not self:
|
||||
yield node
|
||||
node = getattr(node, attr)
|
||||
|
||||
def new_last_node(self) -> Node:
|
||||
"""Create and return a new terminal node."""
|
||||
old_last = self.prv
|
||||
new_last = Node(old_last, self)
|
||||
old_last.nxt = self.prv = new_last
|
||||
return new_last
|
||||
|
||||
|
||||
class OrderedBidictBase(BidictBase[KT, VT]):
|
||||
"""Base class implementing an ordered :class:`BidirectionalMapping`."""
|
||||
|
||||
_node_by_korv: bidict[t.Any, Node]
|
||||
_bykey: bool
|
||||
|
||||
def __init__(self, arg: MapOrItems[KT, VT] = (), /, **kw: VT) -> None:
|
||||
"""Make a new ordered bidirectional mapping.
|
||||
The signature behaves like that of :class:`dict`.
|
||||
Items passed in are added in the order they are passed,
|
||||
respecting the :attr:`~bidict.BidictBase.on_dup`
|
||||
class attribute in the process.
|
||||
|
||||
The order in which items are inserted is remembered,
|
||||
similar to :class:`collections.OrderedDict`.
|
||||
"""
|
||||
self._sntl = SentinelNode()
|
||||
self._node_by_korv = bidict()
|
||||
self._bykey = True
|
||||
super().__init__(arg, **kw)
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
|
||||
@property
|
||||
def inverse(self) -> OrderedBidictBase[VT, KT]: ...
|
||||
|
||||
@property
|
||||
def inv(self) -> OrderedBidictBase[VT, KT]: ...
|
||||
|
||||
def _make_inverse(self) -> OrderedBidictBase[VT, KT]:
|
||||
inv = t.cast(OrderedBidictBase[VT, KT], super()._make_inverse())
|
||||
inv._sntl = self._sntl
|
||||
inv._node_by_korv = self._node_by_korv
|
||||
inv._bykey = not self._bykey
|
||||
return inv
|
||||
|
||||
def _assoc_node(self, node: Node, key: KT, val: VT) -> None:
|
||||
korv = key if self._bykey else val
|
||||
self._node_by_korv.forceput(korv, node)
|
||||
|
||||
def _dissoc_node(self, node: Node) -> None:
|
||||
del self._node_by_korv.inverse[node]
|
||||
node.unlink()
|
||||
|
||||
def _init_from(self, other: MapOrItems[KT, VT]) -> None:
|
||||
"""See :meth:`BidictBase._init_from`."""
|
||||
super()._init_from(other)
|
||||
bykey = self._bykey
|
||||
korv_by_node = self._node_by_korv.inverse
|
||||
korv_by_node.clear()
|
||||
korv_by_node_set = korv_by_node.__setitem__
|
||||
self._sntl.nxt = self._sntl.prv = self._sntl
|
||||
new_node = self._sntl.new_last_node
|
||||
for k, v in iteritems(other):
|
||||
korv_by_node_set(new_node(), k if bykey else v)
|
||||
|
||||
def _write(self, newkey: KT, newval: VT, oldkey: OKT[KT], oldval: OVT[VT], unwrites: Unwrites | None) -> None:
|
||||
"""See :meth:`bidict.BidictBase._spec_write`."""
|
||||
super()._write(newkey, newval, oldkey, oldval, unwrites)
|
||||
assoc, dissoc = self._assoc_node, self._dissoc_node
|
||||
node_by_korv, bykey = self._node_by_korv, self._bykey
|
||||
if oldval is MISSING and oldkey is MISSING: # no key or value duplication
|
||||
# {0: 1, 2: 3} | {4: 5} => {0: 1, 2: 3, 4: 5}
|
||||
newnode = self._sntl.new_last_node()
|
||||
assoc(newnode, newkey, newval)
|
||||
if unwrites is not None:
|
||||
unwrites.append((dissoc, newnode))
|
||||
elif oldval is not MISSING and oldkey is not MISSING: # key and value duplication across two different items
|
||||
# {0: 1, 2: 3} | {0: 3} => {0: 3}
|
||||
# n1, n2 => n1 (collapse n1 and n2 into n1)
|
||||
# oldkey: 2, oldval: 1, oldnode: n2, newkey: 0, newval: 3, newnode: n1
|
||||
if bykey:
|
||||
oldnode = node_by_korv[oldkey]
|
||||
newnode = node_by_korv[newkey]
|
||||
else:
|
||||
oldnode = node_by_korv[newval]
|
||||
newnode = node_by_korv[oldval]
|
||||
dissoc(oldnode)
|
||||
assoc(newnode, newkey, newval)
|
||||
if unwrites is not None:
|
||||
unwrites.extend((
|
||||
(assoc, newnode, newkey, oldval),
|
||||
(assoc, oldnode, oldkey, newval),
|
||||
(oldnode.relink,),
|
||||
))
|
||||
elif oldval is not MISSING: # just key duplication
|
||||
# {0: 1, 2: 3} | {2: 4} => {0: 1, 2: 4}
|
||||
# oldkey: MISSING, oldval: 3, newkey: 2, newval: 4
|
||||
node = node_by_korv[newkey if bykey else oldval]
|
||||
assoc(node, newkey, newval)
|
||||
if unwrites is not None:
|
||||
unwrites.append((assoc, node, newkey, oldval))
|
||||
else:
|
||||
assert oldkey is not MISSING # just value duplication
|
||||
# {0: 1, 2: 3} | {4: 3} => {0: 1, 4: 3}
|
||||
# oldkey: 2, oldval: MISSING, newkey: 4, newval: 3
|
||||
node = node_by_korv[oldkey if bykey else newval]
|
||||
assoc(node, newkey, newval)
|
||||
if unwrites is not None:
|
||||
unwrites.append((assoc, node, oldkey, newval))
|
||||
|
||||
def __iter__(self) -> t.Iterator[KT]:
|
||||
"""Iterator over the contained keys in insertion order."""
|
||||
return self._iter(reverse=False)
|
||||
|
||||
def __reversed__(self) -> t.Iterator[KT]:
|
||||
"""Iterator over the contained keys in reverse insertion order."""
|
||||
return self._iter(reverse=True)
|
||||
|
||||
def _iter(self, *, reverse: bool = False) -> t.Iterator[KT]:
|
||||
nodes = self._sntl.iternodes(reverse=reverse)
|
||||
korv_by_node = self._node_by_korv.inverse
|
||||
if self._bykey:
|
||||
for node in nodes:
|
||||
yield korv_by_node[node]
|
||||
else:
|
||||
key_by_val = self._invm
|
||||
for node in nodes:
|
||||
val = korv_by_node[node]
|
||||
yield key_by_val[val]
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
# ============================================================================
|
||||
# ← Prev: _bidict.py Current: _orderedbase.py Next: _orderedbidict.py →
|
||||
# ============================================================================
|
||||
@ -1,172 +0,0 @@
|
||||
# Copyright 2009-2024 Joshua Bronson. All rights reserved.
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
# (see comments in __init__.py)
|
||||
# ============================================================================
|
||||
# ← Prev: _orderedbase.py Current: _orderedbidict.py <FIN>
|
||||
# ============================================================================
|
||||
|
||||
|
||||
"""Provide :class:`OrderedBidict`."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import typing as t
|
||||
from collections.abc import Set
|
||||
|
||||
from ._base import BidictKeysView
|
||||
from ._bidict import MutableBidict
|
||||
from ._orderedbase import OrderedBidictBase
|
||||
from ._typing import KT
|
||||
from ._typing import VT
|
||||
|
||||
|
||||
class OrderedBidict(OrderedBidictBase[KT, VT], MutableBidict[KT, VT]):
|
||||
"""Mutable bidict type that maintains items in insertion order."""
|
||||
|
||||
if t.TYPE_CHECKING:
|
||||
|
||||
@property
|
||||
def inverse(self) -> OrderedBidict[VT, KT]: ...
|
||||
|
||||
@property
|
||||
def inv(self) -> OrderedBidict[VT, KT]: ...
|
||||
|
||||
def clear(self) -> None:
|
||||
"""Remove all items."""
|
||||
super().clear()
|
||||
self._node_by_korv.clear()
|
||||
self._sntl.nxt = self._sntl.prv = self._sntl
|
||||
|
||||
def _pop(self, key: KT) -> VT:
|
||||
val = super()._pop(key)
|
||||
node = self._node_by_korv[key if self._bykey else val]
|
||||
self._dissoc_node(node)
|
||||
return val
|
||||
|
||||
def popitem(self, last: bool = True) -> tuple[KT, VT]:
|
||||
"""*b.popitem() → (k, v)*
|
||||
|
||||
If *last* is true,
|
||||
remove and return the most recently added item as a (key, value) pair.
|
||||
Otherwise, remove and return the least recently added item.
|
||||
|
||||
:raises KeyError: if *b* is empty.
|
||||
"""
|
||||
if not self:
|
||||
raise KeyError('OrderedBidict is empty')
|
||||
node = getattr(self._sntl, 'prv' if last else 'nxt')
|
||||
korv = self._node_by_korv.inverse[node]
|
||||
if self._bykey:
|
||||
return korv, self._pop(korv)
|
||||
return self.inverse._pop(korv), korv
|
||||
|
||||
def move_to_end(self, key: KT, last: bool = True) -> None:
|
||||
"""Move the item with the given key to the end if *last* is true, else to the beginning.
|
||||
|
||||
:raises KeyError: if *key* is missing
|
||||
"""
|
||||
korv = key if self._bykey else self._fwdm[key]
|
||||
node = self._node_by_korv[korv]
|
||||
node.prv.nxt = node.nxt
|
||||
node.nxt.prv = node.prv
|
||||
sntl = self._sntl
|
||||
if last:
|
||||
lastnode = sntl.prv
|
||||
node.prv = lastnode
|
||||
node.nxt = sntl
|
||||
sntl.prv = lastnode.nxt = node
|
||||
else:
|
||||
firstnode = sntl.nxt
|
||||
node.prv = sntl
|
||||
node.nxt = firstnode
|
||||
sntl.nxt = firstnode.prv = node
|
||||
|
||||
# Override the keys() and items() implementations inherited from BidictBase,
|
||||
# which may delegate to the backing _fwdm dict, since this is a mutable ordered bidict,
|
||||
# and therefore the ordering of items can get out of sync with the backing mappings
|
||||
# after mutation. (Need not override values() because it delegates to .inverse.keys().)
|
||||
def keys(self) -> t.KeysView[KT]:
|
||||
"""A set-like object providing a view on the contained keys."""
|
||||
return _OrderedBidictKeysView(self)
|
||||
|
||||
def items(self) -> t.ItemsView[KT, VT]:
|
||||
"""A set-like object providing a view on the contained items."""
|
||||
return _OrderedBidictItemsView(self)
|
||||
|
||||
|
||||
# The following MappingView implementations use the __iter__ implementations
|
||||
# inherited from their superclass counterparts in collections.abc, so they
|
||||
# continue to yield items in the correct order even after an OrderedBidict
|
||||
# is mutated. They also provide a __reversed__ implementation, which is not
|
||||
# provided by the collections.abc superclasses.
|
||||
class _OrderedBidictKeysView(BidictKeysView[KT]):
|
||||
_mapping: OrderedBidict[KT, t.Any]
|
||||
|
||||
def __reversed__(self) -> t.Iterator[KT]:
|
||||
return reversed(self._mapping)
|
||||
|
||||
|
||||
class _OrderedBidictItemsView(t.ItemsView[KT, VT]):
|
||||
_mapping: OrderedBidict[KT, VT]
|
||||
|
||||
def __reversed__(self) -> t.Iterator[tuple[KT, VT]]:
|
||||
ob = self._mapping
|
||||
for key in reversed(ob):
|
||||
yield key, ob[key]
|
||||
|
||||
|
||||
# For better performance, make _OrderedBidictKeysView and _OrderedBidictItemsView delegate
|
||||
# to backing dicts for the methods they inherit from collections.abc.Set. (Cannot delegate
|
||||
# for __iter__ and __reversed__ since they are order-sensitive.) See also: https://bugs.python.org/issue46713
|
||||
_OView = t.Union[t.Type[_OrderedBidictKeysView[KT]], t.Type[_OrderedBidictItemsView[KT, t.Any]]]
|
||||
_setmethodnames: t.Iterable[str] = (
|
||||
'__lt__ __le__ __gt__ __ge__ __eq__ __ne__ __sub__ __rsub__ '
|
||||
'__or__ __ror__ __xor__ __rxor__ __and__ __rand__ isdisjoint'
|
||||
).split()
|
||||
|
||||
|
||||
def _override_set_methods_to_use_backing_dict(cls: _OView[KT], viewname: str) -> None:
|
||||
def make_proxy_method(methodname: str) -> t.Any:
|
||||
def method(self: _OrderedBidictKeysView[KT] | _OrderedBidictItemsView[KT, t.Any], *args: t.Any) -> t.Any:
|
||||
fwdm = self._mapping._fwdm
|
||||
if not isinstance(fwdm, dict): # dict view speedup not available, fall back to Set's implementation.
|
||||
return getattr(Set, methodname)(self, *args)
|
||||
fwdm_dict_view = getattr(fwdm, viewname)()
|
||||
fwdm_dict_view_method = getattr(fwdm_dict_view, methodname)
|
||||
if (
|
||||
len(args) != 1
|
||||
or not isinstance((arg := args[0]), self.__class__)
|
||||
or not isinstance(arg._mapping._fwdm, dict)
|
||||
):
|
||||
return fwdm_dict_view_method(*args)
|
||||
# self and arg are both _OrderedBidictKeysViews or _OrderedBidictItemsViews whose bidicts are backed by
|
||||
# a dict. Use arg's backing dict's corresponding view instead of arg. Otherwise, e.g. `ob1.keys()
|
||||
# < ob2.keys()` would give "TypeError: '<' not supported between instances of '_OrderedBidictKeysView' and
|
||||
# '_OrderedBidictKeysView'", because both `dict_keys(ob1).__lt__(ob2.keys()) is NotImplemented` and
|
||||
# `dict_keys(ob2).__gt__(ob1.keys()) is NotImplemented`.
|
||||
arg_dict = arg._mapping._fwdm
|
||||
arg_dict_view = getattr(arg_dict, viewname)()
|
||||
return fwdm_dict_view_method(arg_dict_view)
|
||||
|
||||
method.__name__ = methodname
|
||||
method.__qualname__ = f'{cls.__qualname__}.{methodname}'
|
||||
return method
|
||||
|
||||
for name in _setmethodnames:
|
||||
setattr(cls, name, make_proxy_method(name))
|
||||
|
||||
|
||||
_override_set_methods_to_use_backing_dict(_OrderedBidictKeysView, 'keys')
|
||||
_override_set_methods_to_use_backing_dict(_OrderedBidictItemsView, 'items')
|
||||
|
||||
|
||||
# * Code review nav *
|
||||
# ============================================================================
|
||||
# ← Prev: _orderedbase.py Current: _orderedbidict.py <FIN>
|
||||
# ============================================================================
|
||||
@ -1,49 +0,0 @@
|
||||
# Copyright 2009-2024 Joshua Bronson. All rights reserved.
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
|
||||
"""Provide typing-related objects."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import typing as t
|
||||
from enum import Enum
|
||||
|
||||
|
||||
KT = t.TypeVar('KT')
|
||||
VT = t.TypeVar('VT')
|
||||
VT_co = t.TypeVar('VT_co', covariant=True)
|
||||
|
||||
|
||||
Items = t.Iterable[t.Tuple[KT, VT]]
|
||||
|
||||
|
||||
@t.runtime_checkable
|
||||
class Maplike(t.Protocol[KT, VT_co]):
|
||||
"""Like typeshed's SupportsKeysAndGetItem, but usable at runtime."""
|
||||
|
||||
def keys(self) -> t.Iterable[KT]: ...
|
||||
|
||||
def __getitem__(self, __key: KT) -> VT_co: ...
|
||||
|
||||
|
||||
MapOrItems = t.Union[Maplike[KT, VT], Items[KT, VT]]
|
||||
MappOrItems = t.Union[t.Mapping[KT, VT], Items[KT, VT]]
|
||||
ItemsIter = t.Iterator[t.Tuple[KT, VT]]
|
||||
|
||||
|
||||
class MissingT(Enum):
|
||||
"""Sentinel used to represent none/missing when None itself can't be used."""
|
||||
|
||||
MISSING = 'MISSING'
|
||||
|
||||
|
||||
MISSING: t.Final[t.Literal[MissingT.MISSING]] = MissingT.MISSING
|
||||
OKT = t.Union[KT, MissingT] #: optional key type
|
||||
OVT = t.Union[VT, MissingT] #: optional value type
|
||||
|
||||
DT = t.TypeVar('DT') #: for default arguments
|
||||
ODT = t.Union[DT, MissingT] #: optional default arg type
|
||||
@ -1,14 +0,0 @@
|
||||
# Copyright 2009-2024 Joshua Bronson. All rights reserved.
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
"""Define bidict package metadata."""
|
||||
|
||||
__version__ = '0.23.1'
|
||||
__author__ = {'name': 'Joshua Bronson', 'email': 'jabronson@gmail.com'}
|
||||
__copyright__ = '© 2009-2024 Joshua Bronson'
|
||||
__description__ = 'The bidirectional mapping library for Python.'
|
||||
__license__ = 'MPL 2.0'
|
||||
__url__ = 'https://bidict.readthedocs.io'
|
||||
@ -1 +0,0 @@
|
||||
PEP-561 marker.
|
||||
@ -1 +0,0 @@
|
||||
pip
|
||||
@ -1,20 +0,0 @@
|
||||
This package contains a modified version of ca-bundle.crt:
|
||||
|
||||
ca-bundle.crt -- Bundle of CA Root Certificates
|
||||
|
||||
This is a bundle of X.509 certificates of public Certificate Authorities
|
||||
(CA). These were automatically extracted from Mozilla's root certificates
|
||||
file (certdata.txt). This file can be found in the mozilla source tree:
|
||||
https://hg.mozilla.org/mozilla-central/file/tip/security/nss/lib/ckfw/builtins/certdata.txt
|
||||
It contains the certificates in PEM format and therefore
|
||||
can be directly used with curl / libcurl / php_curl, or with
|
||||
an Apache+mod_ssl webserver for SSL client authentication.
|
||||
Just configure this file as the SSLCACertificateFile.#
|
||||
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
This Source Code Form is subject to the terms of the Mozilla Public License,
|
||||
v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain
|
||||
one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
@(#) $RCSfile: certdata.txt,v $ $Revision: 1.80 $ $Date: 2011/11/03 15:11:58 $
|
||||
@ -1,67 +0,0 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: certifi
|
||||
Version: 2024.8.30
|
||||
Summary: Python package for providing Mozilla's CA Bundle.
|
||||
Home-page: https://github.com/certifi/python-certifi
|
||||
Author: Kenneth Reitz
|
||||
Author-email: me@kennethreitz.com
|
||||
License: MPL-2.0
|
||||
Project-URL: Source, https://github.com/certifi/python-certifi
|
||||
Classifier: Development Status :: 5 - Production/Stable
|
||||
Classifier: Intended Audience :: Developers
|
||||
Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
|
||||
Classifier: Natural Language :: English
|
||||
Classifier: Programming Language :: Python
|
||||
Classifier: Programming Language :: Python :: 3
|
||||
Classifier: Programming Language :: Python :: 3 :: Only
|
||||
Classifier: Programming Language :: Python :: 3.6
|
||||
Classifier: Programming Language :: Python :: 3.7
|
||||
Classifier: Programming Language :: Python :: 3.8
|
||||
Classifier: Programming Language :: Python :: 3.9
|
||||
Classifier: Programming Language :: Python :: 3.10
|
||||
Classifier: Programming Language :: Python :: 3.11
|
||||
Classifier: Programming Language :: Python :: 3.12
|
||||
Requires-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.
|
||||
@ -1,14 +0,0 @@
|
||||
certifi-2024.8.30.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
certifi-2024.8.30.dist-info/LICENSE,sha256=6TcW2mucDVpKHfYP5pWzcPBpVgPSH2-D8FPkLPwQyvc,989
|
||||
certifi-2024.8.30.dist-info/METADATA,sha256=GhBHRVUN6a4ZdUgE_N5wmukJfyuoE-QyIl8Y3ifNQBM,2222
|
||||
certifi-2024.8.30.dist-info/RECORD,,
|
||||
certifi-2024.8.30.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
|
||||
certifi-2024.8.30.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8
|
||||
certifi/__init__.py,sha256=p_GYZrjUwPBUhpLlCZoGb0miKBKSqDAyZC5DvIuqbHQ,94
|
||||
certifi/__main__.py,sha256=xBBoj905TUWBLRGANOcf7oi6e-3dMP4cEoG9OyMs11g,243
|
||||
certifi/__pycache__/__init__.cpython-310.pyc,,
|
||||
certifi/__pycache__/__main__.cpython-310.pyc,,
|
||||
certifi/__pycache__/core.cpython-310.pyc,,
|
||||
certifi/cacert.pem,sha256=lO3rZukXdPyuk6BWUJFOKQliWaXH6HGh9l1GGrUgG0c,299427
|
||||
certifi/core.py,sha256=qRDDFyXVJwTB_EmoGppaXU_R9qCZvhl-EzxPMuV3nTA,4426
|
||||
certifi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
||||
@ -1,5 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: setuptools (74.0.0)
|
||||
Root-Is-Purelib: true
|
||||
Tag: py3-none-any
|
||||
|
||||
@ -1 +0,0 @@
|
||||
certifi
|
||||
@ -1,4 +0,0 @@
|
||||
from .core import contents, where
|
||||
|
||||
__all__ = ["contents", "where"]
|
||||
__version__ = "2024.08.30"
|
||||
@ -1,12 +0,0 @@
|
||||
import argparse
|
||||
|
||||
from certifi import contents, where
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument("-c", "--contents", action="store_true")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.contents:
|
||||
print(contents())
|
||||
else:
|
||||
print(where())
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
4929
env/lib/python3.10/site-packages/certifi/cacert.pem
vendored
4929
env/lib/python3.10/site-packages/certifi/cacert.pem
vendored
File diff suppressed because it is too large
Load Diff
114
env/lib/python3.10/site-packages/certifi/core.py
vendored
114
env/lib/python3.10/site-packages/certifi/core.py
vendored
@ -1,114 +0,0 @@
|
||||
"""
|
||||
certifi.py
|
||||
~~~~~~~~~~
|
||||
|
||||
This module returns the installation location of cacert.pem or its contents.
|
||||
"""
|
||||
import sys
|
||||
import atexit
|
||||
|
||||
def exit_cacert_ctx() -> None:
|
||||
_CACERT_CTX.__exit__(None, None, None) # type: ignore[union-attr]
|
||||
|
||||
|
||||
if sys.version_info >= (3, 11):
|
||||
|
||||
from importlib.resources import as_file, files
|
||||
|
||||
_CACERT_CTX = None
|
||||
_CACERT_PATH = None
|
||||
|
||||
def where() -> str:
|
||||
# This is slightly terrible, but we want to delay extracting the file
|
||||
# in cases where we're inside of a zipimport situation until someone
|
||||
# actually calls where(), but we don't want to re-extract the file
|
||||
# on every call of where(), so we'll do it once then store it in a
|
||||
# global variable.
|
||||
global _CACERT_CTX
|
||||
global _CACERT_PATH
|
||||
if _CACERT_PATH is None:
|
||||
# This is slightly janky, the importlib.resources API wants you to
|
||||
# manage the cleanup of this file, so it doesn't actually return a
|
||||
# path, it returns a context manager that will give you the path
|
||||
# when you enter it and will do any cleanup when you leave it. In
|
||||
# the common case of not needing a temporary file, it will just
|
||||
# return the file system location and the __exit__() is a no-op.
|
||||
#
|
||||
# We also have to hold onto the actual context manager, because
|
||||
# it will do the cleanup whenever it gets garbage collected, so
|
||||
# we will also store that at the global level as well.
|
||||
_CACERT_CTX = as_file(files("certifi").joinpath("cacert.pem"))
|
||||
_CACERT_PATH = str(_CACERT_CTX.__enter__())
|
||||
atexit.register(exit_cacert_ctx)
|
||||
|
||||
return _CACERT_PATH
|
||||
|
||||
def contents() -> str:
|
||||
return files("certifi").joinpath("cacert.pem").read_text(encoding="ascii")
|
||||
|
||||
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__())
|
||||
atexit.register(exit_cacert_ctx)
|
||||
|
||||
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")
|
||||
@ -1 +0,0 @@
|
||||
pip
|
||||
@ -1,26 +0,0 @@
|
||||
|
||||
Except when otherwise stated (look for LICENSE files in directories or
|
||||
information at the beginning of each file) all software and
|
||||
documentation is licensed as follows:
|
||||
|
||||
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.
|
||||
|
||||
@ -1,40 +0,0 @@
|
||||
Metadata-Version: 2.1
|
||||
Name: cffi
|
||||
Version: 1.17.1
|
||||
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 :: 3.13
|
||||
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 <http://cffi.readthedocs.org/>`_.
|
||||
|
||||
Contact
|
||||
-------
|
||||
|
||||
`Mailing list <https://groups.google.com/forum/#!forum/python-cffi>`_
|
||||
@ -1,48 +0,0 @@
|
||||
_cffi_backend.cpython-310-x86_64-linux-gnu.so,sha256=pciUVwDoiYkGtuoos7gi5U2TSTeBHVoDkneECMzaObI,985520
|
||||
cffi-1.17.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
|
||||
cffi-1.17.1.dist-info/LICENSE,sha256=BLgPWwd7vtaICM_rreteNSPyqMmpZJXFh72W3x6sKjM,1294
|
||||
cffi-1.17.1.dist-info/METADATA,sha256=u6nuvP_qPJKu2zvIbi2zkGzVu7KjnnRIYUFyIrOY3j4,1531
|
||||
cffi-1.17.1.dist-info/RECORD,,
|
||||
cffi-1.17.1.dist-info/WHEEL,sha256=AxiTY2sz_GcPOsKDeggQV_FGgAhpyJSKs70WYTq6kog,151
|
||||
cffi-1.17.1.dist-info/entry_points.txt,sha256=y6jTxnyeuLnL-XJcDv8uML3n6wyYiGRg8MTp_QGJ9Ho,75
|
||||
cffi-1.17.1.dist-info/top_level.txt,sha256=rE7WR3rZfNKxWI9-jn6hsHCAl7MDkB-FmuQbxWjFehQ,19
|
||||
cffi/__init__.py,sha256=H6t_ebva6EeHpUuItFLW1gbRp94eZRNJODLaWKdbx1I,513
|
||||
cffi/__pycache__/__init__.cpython-310.pyc,,
|
||||
cffi/__pycache__/_imp_emulation.cpython-310.pyc,,
|
||||
cffi/__pycache__/_shimmed_dist_utils.cpython-310.pyc,,
|
||||
cffi/__pycache__/api.cpython-310.pyc,,
|
||||
cffi/__pycache__/backend_ctypes.cpython-310.pyc,,
|
||||
cffi/__pycache__/cffi_opcode.cpython-310.pyc,,
|
||||
cffi/__pycache__/commontypes.cpython-310.pyc,,
|
||||
cffi/__pycache__/cparser.cpython-310.pyc,,
|
||||
cffi/__pycache__/error.cpython-310.pyc,,
|
||||
cffi/__pycache__/ffiplatform.cpython-310.pyc,,
|
||||
cffi/__pycache__/lock.cpython-310.pyc,,
|
||||
cffi/__pycache__/model.cpython-310.pyc,,
|
||||
cffi/__pycache__/pkgconfig.cpython-310.pyc,,
|
||||
cffi/__pycache__/recompiler.cpython-310.pyc,,
|
||||
cffi/__pycache__/setuptools_ext.cpython-310.pyc,,
|
||||
cffi/__pycache__/vengine_cpy.cpython-310.pyc,,
|
||||
cffi/__pycache__/vengine_gen.cpython-310.pyc,,
|
||||
cffi/__pycache__/verifier.cpython-310.pyc,,
|
||||
cffi/_cffi_errors.h,sha256=zQXt7uR_m8gUW-fI2hJg0KoSkJFwXv8RGUkEDZ177dQ,3908
|
||||
cffi/_cffi_include.h,sha256=Exhmgm9qzHWzWivjfTe0D7Xp4rPUkVxdNuwGhMTMzbw,15055
|
||||
cffi/_embedding.h,sha256=EDKw5QrLvQoe3uosXB3H1xPVTYxsn33eV3A43zsA_Fw,18787
|
||||
cffi/_imp_emulation.py,sha256=RxREG8zAbI2RPGBww90u_5fi8sWdahpdipOoPzkp7C0,2960
|
||||
cffi/_shimmed_dist_utils.py,sha256=Bjj2wm8yZbvFvWEx5AEfmqaqZyZFhYfoyLLQHkXZuao,2230
|
||||
cffi/api.py,sha256=alBv6hZQkjpmZplBphdaRn2lPO9-CORs_M7ixabvZWI,42169
|
||||
cffi/backend_ctypes.py,sha256=h5ZIzLc6BFVXnGyc9xPqZWUS7qGy7yFSDqXe68Sa8z4,42454
|
||||
cffi/cffi_opcode.py,sha256=JDV5l0R0_OadBX_uE7xPPTYtMdmpp8I9UYd6av7aiDU,5731
|
||||
cffi/commontypes.py,sha256=7N6zPtCFlvxXMWhHV08psUjdYIK2XgsN3yo5dgua_v4,2805
|
||||
cffi/cparser.py,sha256=0qI3mEzZSNVcCangoyXOoAcL-RhpQL08eG8798T024s,44789
|
||||
cffi/error.py,sha256=v6xTiS4U0kvDcy4h_BDRo5v39ZQuj-IMRYLv5ETddZs,877
|
||||
cffi/ffiplatform.py,sha256=avxFjdikYGJoEtmJO7ewVmwG_VEVl6EZ_WaNhZYCqv4,3584
|
||||
cffi/lock.py,sha256=l9TTdwMIMpi6jDkJGnQgE9cvTIR7CAntIJr8EGHt3pY,747
|
||||
cffi/model.py,sha256=W30UFQZE73jL5Mx5N81YT77us2W2iJjTm0XYfnwz1cg,21797
|
||||
cffi/parse_c_type.h,sha256=OdwQfwM9ktq6vlCB43exFQmxDBtj2MBNdK8LYl15tjw,5976
|
||||
cffi/pkgconfig.py,sha256=LP1w7vmWvmKwyqLaU1Z243FOWGNQMrgMUZrvgFuOlco,4374
|
||||
cffi/recompiler.py,sha256=sim4Tm7lamt2Jn8uzKN0wMYp6ODByk3g7of47-h9LD4,65367
|
||||
cffi/setuptools_ext.py,sha256=-ebj79lO2_AUH-kRcaja2pKY1Z_5tloGwsJgzK8P3Cc,8871
|
||||
cffi/vengine_cpy.py,sha256=8UagT6ZEOZf6Dju7_CfNulue8CnsHLEzJYhnqUhoF04,43752
|
||||
cffi/vengine_gen.py,sha256=DUlEIrDiVin1Pnhn1sfoamnS5NLqfJcOdhRoeSNeJRg,26939
|
||||
cffi/verifier.py,sha256=oX8jpaohg2Qm3aHcznidAdvrVm5N4sQYG0a3Eo5mIl4,11182
|
||||
@ -1,6 +0,0 @@
|
||||
Wheel-Version: 1.0
|
||||
Generator: setuptools (74.1.1)
|
||||
Root-Is-Purelib: false
|
||||
Tag: cp310-cp310-manylinux_2_17_x86_64
|
||||
Tag: cp310-cp310-manylinux2014_x86_64
|
||||
|
||||
@ -1,2 +0,0 @@
|
||||
[distutils.setup_keywords]
|
||||
cffi_modules = cffi.setuptools_ext:cffi_modules
|
||||
@ -1,2 +0,0 @@
|
||||
_cffi_backend
|
||||
cffi
|
||||
@ -1,14 +0,0 @@
|
||||
__all__ = ['FFI', 'VerificationError', 'VerificationMissing', 'CDefError',
|
||||
'FFIError']
|
||||
|
||||
from .api import FFI
|
||||
from .error import CDefError, FFIError, VerificationError, VerificationMissing
|
||||
from .error import PkgConfigError
|
||||
|
||||
__version__ = "1.17.1"
|
||||
__version_info__ = (1, 17, 1)
|
||||
|
||||
# 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"
|
||||
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user