Delete venv directory

This commit is contained in:
Lain 2025-03-27 11:16:17 +03:00 committed by GitHub
parent 7e58d94786
commit fca2d580b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
832 changed files with 0 additions and 412757 deletions

View File

@ -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"

View File

@ -1,71 +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
# Call hash to forget past locations. Without forgetting
# past locations the $PATH changes we made may not be respected.
# See "man bash" for more details. hash is usually a builtin of your shell
hash -r 2> /dev/null
if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then
PS1="${_OLD_VIRTUAL_PS1:-}"
export PS1
unset _OLD_VIRTUAL_PS1
fi
unset VIRTUAL_ENV
unset VIRTUAL_ENV_PROMPT
if [ ! "${1:-}" = "nondestructive" ] ; then
# Self destruct!
unset -f deactivate
fi
}
# unset irrelevant variables
deactivate nondestructive
# on Windows, a path can contain colons and backslashes and has to be converted:
if [ "${OSTYPE:-}" = "cygwin" ] || [ "${OSTYPE:-}" = "msys" ] ; then
# transform D:\path\to\venv to /d/path/to/venv on MSYS
# and to /cygdrive/d/path/to/venv on Cygwin
export VIRTUAL_ENV=$(cygpath /Users/arbung/work/talc/venv)
else
# use the path as-is
export VIRTUAL_ENV=/Users/arbung/work/talc/venv
fi
_OLD_VIRTUAL_PATH="$PATH"
PATH="$VIRTUAL_ENV/"bin":$PATH"
export PATH
# unset PYTHONHOME if set
# this will fail if PYTHONHOME is set to the empty string (which is bad anyway)
# could use `if (set -u; : $PYTHONHOME) ;` in bash
if [ -n "${PYTHONHOME:-}" ] ; then
_OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}"
unset PYTHONHOME
fi
if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
_OLD_VIRTUAL_PS1="${PS1:-}"
PS1='(venv) '"${PS1:-}"
export PS1
VIRTUAL_ENV_PROMPT='(venv) '
export VIRTUAL_ENV_PROMPT
fi
# Call hash to forget past commands. Without forgetting
# past commands the $PATH changes we made may not be respected
hash -r 2> /dev/null

View File

@ -1,27 +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 /Users/arbung/work/talc/venv
set _OLD_VIRTUAL_PATH="$PATH"
setenv PATH "$VIRTUAL_ENV/"bin":$PATH"
set _OLD_VIRTUAL_PROMPT="$prompt"
if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
set prompt = '(venv) '"$prompt"
setenv VIRTUAL_ENV_PROMPT '(venv) '
endif
alias pydoc python -m pydoc
rehash

View File

@ -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 /Users/arbung/work/talc/venv
set -gx _OLD_VIRTUAL_PATH $PATH
set -gx PATH "$VIRTUAL_ENV/"bin $PATH
# Unset PYTHONHOME if set.
if set -q PYTHONHOME
set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME
set -e PYTHONHOME
end
if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
# fish uses a function instead of an env var to generate the prompt.
# Save the current fish_prompt function as the function _old_fish_prompt.
functions -c fish_prompt _old_fish_prompt
# With the original prompt function renamed, we can override with our own.
function fish_prompt
# Save the return status of the last command.
set -l old_status $status
# Output the venv prompt; color taken from the blue of the Python logo.
printf "%s%s%s" (set_color 4B8BBE) '(venv) ' (set_color normal)
# Restore the return status of the previous command.
echo "exit $old_status" | .
# Output the original/"old" prompt.
_old_fish_prompt
end
set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV"
set -gx VIRTUAL_ENV_PROMPT '(venv) '
end

View File

@ -1,8 +0,0 @@
#!/Users/arbung/work/talc/venv/bin/python3.12
# -*- coding: utf-8 -*-
import re
import sys
from dotenv.__main__ import cli
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(cli())

View File

@ -1,8 +0,0 @@
#!/Users/arbung/work/talc/venv/bin/python3.12
# -*- 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())

View File

@ -1,8 +0,0 @@
#!/Users/arbung/work/talc/venv/bin/python3.12
# -*- 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())

View File

@ -1,8 +0,0 @@
#!/Users/arbung/work/talc/venv/bin/python3.12
# -*- 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())

View File

@ -1,8 +0,0 @@
#!/Users/arbung/work/talc/venv/bin/python3.12
# -*- coding: utf-8 -*-
import re
import sys
from rsa.cli import decrypt
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(decrypt())

View File

@ -1,8 +0,0 @@
#!/Users/arbung/work/talc/venv/bin/python3.12
# -*- coding: utf-8 -*-
import re
import sys
from rsa.cli import encrypt
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(encrypt())

View File

@ -1,8 +0,0 @@
#!/Users/arbung/work/talc/venv/bin/python3.12
# -*- coding: utf-8 -*-
import re
import sys
from rsa.cli import keygen
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(keygen())

View File

@ -1,8 +0,0 @@
#!/Users/arbung/work/talc/venv/bin/python3.12
# -*- coding: utf-8 -*-
import re
import sys
from rsa.util import private_to_public
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(private_to_public())

View File

@ -1,8 +0,0 @@
#!/Users/arbung/work/talc/venv/bin/python3.12
# -*- coding: utf-8 -*-
import re
import sys
from rsa.cli import sign
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(sign())

View File

@ -1,8 +0,0 @@
#!/Users/arbung/work/talc/venv/bin/python3.12
# -*- coding: utf-8 -*-
import re
import sys
from rsa.cli import verify
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(verify())

View File

@ -1 +0,0 @@
python3.12

View File

@ -1 +0,0 @@
python3.12

View File

@ -1 +0,0 @@
/opt/homebrew/opt/python@3.12/bin/python3.12

View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2016-Present LonamiWebs
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.

View File

@ -1,125 +0,0 @@
Metadata-Version: 2.2
Name: Telethon
Version: 1.39.0
Summary: Full-featured Telegram client library for Python 3
Home-page: https://github.com/LonamiWebs/Telethon
Download-URL: https://github.com/LonamiWebs/Telethon/releases
Author: Lonami Exo
Author-email: totufals@hotmail.com
License: MIT
Keywords: telegram api chat client library messaging mtproto
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Topic :: Communications :: Chat
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Requires-Python: >=3.5
License-File: LICENSE
Requires-Dist: pyaes
Requires-Dist: rsa
Provides-Extra: cryptg
Requires-Dist: cryptg; extra == "cryptg"
Dynamic: author
Dynamic: author-email
Dynamic: classifier
Dynamic: description
Dynamic: download-url
Dynamic: home-page
Dynamic: keywords
Dynamic: license
Dynamic: provides-extra
Dynamic: requires-dist
Dynamic: requires-python
Dynamic: summary
Telethon
========
.. epigraph::
⭐️ Thanks **everyone** who has starred the project, it means a lot!
|logo| **Telethon** is an asyncio_ **Python 3**
MTProto_ library to interact with Telegram_'s API
as a user or through a bot account (bot API alternative).
.. important::
If you have code using Telethon before its 1.0 version, you must
read `Compatibility and Convenience`_ to learn how to migrate.
As with any third-party library for Telegram, be careful not to
break `Telegram's ToS`_ or `Telegram can ban the account`_.
What is this?
-------------
Telegram is a popular messaging application. This library is meant
to make it easy for you to write Python programs that can interact
with Telegram. Think of it as a wrapper that has already done the
heavy job for you, so you can focus on developing an application.
Installing
----------
.. code-block:: sh
pip3 install telethon
Creating a client
-----------------
.. code-block:: python
from telethon import TelegramClient, events, sync
# These example values won't work. You must get your own api_id and
# api_hash from https://my.telegram.org, under API Development.
api_id = 12345
api_hash = '0123456789abcdef0123456789abcdef'
client = TelegramClient('session_name', api_id, api_hash)
client.start()
Doing stuff
-----------
.. code-block:: python
print(client.get_me().stringify())
client.send_message('username', 'Hello! Talking to you from Telethon')
client.send_file('username', '/home/myself/Pictures/holidays.jpg')
client.download_profile_photo('me')
messages = client.get_messages('username')
messages[0].download_media()
@client.on(events.NewMessage(pattern='(?i)hi|hello'))
async def handler(event):
await event.respond('Hey!')
Next steps
----------
Do you like how Telethon looks? Check out `Read The Docs`_ for a more
in-depth explanation, with examples, troubleshooting issues, and more
useful information.
.. _asyncio: https://docs.python.org/3/library/asyncio.html
.. _MTProto: https://core.telegram.org/mtproto
.. _Telegram: https://telegram.org
.. _Compatibility and Convenience: https://docs.telethon.dev/en/stable/misc/compatibility-and-convenience.html
.. _Telegram's ToS: https://core.telegram.org/api/terms
.. _Telegram can ban the account: https://docs.telethon.dev/en/stable/quick-references/faq.html#my-account-was-deleted-limited-when-using-the-library
.. _Read The Docs: https://docs.telethon.dev
.. |logo| image:: logo.svg
:width: 24pt
:height: 24pt

View File

@ -1,307 +0,0 @@
Telethon-1.39.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
Telethon-1.39.0.dist-info/LICENSE,sha256=fVKCkA2Onr4PPTdCF4odI2522BGE9PyCkOIhE18rCyo,1075
Telethon-1.39.0.dist-info/METADATA,sha256=qyNrRKfB1rUELAkCT7qA_0ROumxIePguZNLwLWnlWlM,3874
Telethon-1.39.0.dist-info/RECORD,,
Telethon-1.39.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
Telethon-1.39.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
Telethon-1.39.0.dist-info/top_level.txt,sha256=qeAt2E18Wt064tJzUgGawTlQsyRHbQI-Z0s59fzrO3E,9
telethon/__init__.py,sha256=LoGXeU9VlvO1jwF4WJLd38MtekchxJEX4ZlRHXJgyQA,407
telethon/__pycache__/__init__.cpython-312.pyc,,
telethon/__pycache__/custom.cpython-312.pyc,,
telethon/__pycache__/functions.cpython-312.pyc,,
telethon/__pycache__/helpers.cpython-312.pyc,,
telethon/__pycache__/hints.cpython-312.pyc,,
telethon/__pycache__/password.cpython-312.pyc,,
telethon/__pycache__/requestiter.cpython-312.pyc,,
telethon/__pycache__/sync.cpython-312.pyc,,
telethon/__pycache__/types.cpython-312.pyc,,
telethon/__pycache__/utils.cpython-312.pyc,,
telethon/__pycache__/version.cpython-312.pyc,,
telethon/_updates/__init__.py,sha256=onnrxSuMvNCQRGFEkdMoKXKlkQur5E36NPs2_byPBLI,170
telethon/_updates/__pycache__/__init__.cpython-312.pyc,,
telethon/_updates/__pycache__/entitycache.cpython-312.pyc,,
telethon/_updates/__pycache__/messagebox.cpython-312.pyc,,
telethon/_updates/__pycache__/session.cpython-312.pyc,,
telethon/_updates/entitycache.py,sha256=bbzakxz13e3E689tr0FTPHXnSV43X5O_BFsuLioiXyU,1853
telethon/_updates/messagebox.py,sha256=9uJR0a3okED5igZL7xkwzJS03B7AYq9w8TdKQc0QPPA,34919
telethon/_updates/session.py,sha256=uKq0RBYrjzsPU-_ZDdOJKGwRvSjoaLC5UK96wRUd044,6168
telethon/client/__init__.py,sha256=6Xi6IwVuOcx8jRW9GozoczlGIGDm_mo2iYK8BbfvH2U,1200
telethon/client/__pycache__/__init__.cpython-312.pyc,,
telethon/client/__pycache__/account.cpython-312.pyc,,
telethon/client/__pycache__/auth.cpython-312.pyc,,
telethon/client/__pycache__/bots.cpython-312.pyc,,
telethon/client/__pycache__/buttons.cpython-312.pyc,,
telethon/client/__pycache__/chats.cpython-312.pyc,,
telethon/client/__pycache__/dialogs.cpython-312.pyc,,
telethon/client/__pycache__/downloads.cpython-312.pyc,,
telethon/client/__pycache__/messageparse.cpython-312.pyc,,
telethon/client/__pycache__/messages.cpython-312.pyc,,
telethon/client/__pycache__/telegrambaseclient.cpython-312.pyc,,
telethon/client/__pycache__/telegramclient.cpython-312.pyc,,
telethon/client/__pycache__/updates.cpython-312.pyc,,
telethon/client/__pycache__/uploads.cpython-312.pyc,,
telethon/client/__pycache__/users.cpython-312.pyc,,
telethon/client/account.py,sha256=a9ZZZM1Jx0NvkO28eSvHC5iDseP9LQPXC24jqp2tVMw,9572
telethon/client/auth.py,sha256=P9r0EekjnopnLGn1iXAToST-etiORd6E6iYxwIwFGgg,24970
telethon/client/bots.py,sha256=R2PDg8Mae5a65Dfd9G6dcvRL-KFv4rOgm8ZIAC-DF1M,2453
telethon/client/buttons.py,sha256=8MCxliLl1KYO7N_2t7PcnN5Ule5sPKN7Ibud9nj-FE0,3280
telethon/client/chats.py,sha256=IjO1hFc_D7JV-b8RP0OdbZm-v7eotTfsZo2NFexQROc,51321
telethon/client/dialogs.py,sha256=M6jTGqZTVZUo78JULgQg90w7PCga480dey9_kjQikOc,23008
telethon/client/downloads.py,sha256=BOm84KxZr58Sag2_vIM980tFG7dbnzlzJ1w4Np0Qowo,41691
telethon/client/messageparse.py,sha256=ifPKP74a8nxUmK6IFnq-oVy4vYWBT20gWJk_EJZNGQ8,9387
telethon/client/messages.py,sha256=S6gSxPx_lFRFWLpb55P5fvxWpqbXOFLQMxXXzQe3sXM,63546
telethon/client/telegrambaseclient.py,sha256=fFRO8cNV4JPdfTjxWyFht3mIE0EIr7djCMfWmO3xfi8,39287
telethon/client/telegramclient.py,sha256=jbDY2zhJYV_Vu6vK90JG5wZ16yuBphMrYm_uOTFWAOY,478
telethon/client/updates.py,sha256=75bJIXJMqq2zWQMjy6EyYGcGS1qrBCdtVbrWmWQ5sY4,29980
telethon/client/uploads.py,sha256=iIMcdDxw5f6hQ1R9KUsKXznOvJn1AGTBWfykZ9a7zGI,36730
telethon/client/users.py,sha256=RC5aWyshGxrdiYQDdTZ-Ld6Sb_iAJ-uZuJ599Am8ZVw,25684
telethon/crypto/__init__.py,sha256=qxhA1GYOg35PY06BZO92I7MGubVa8Rcy1vt9kCmWpsU,349
telethon/crypto/__pycache__/__init__.cpython-312.pyc,,
telethon/crypto/__pycache__/aes.cpython-312.pyc,,
telethon/crypto/__pycache__/aesctr.cpython-312.pyc,,
telethon/crypto/__pycache__/authkey.cpython-312.pyc,,
telethon/crypto/__pycache__/cdndecrypter.cpython-312.pyc,,
telethon/crypto/__pycache__/factorization.cpython-312.pyc,,
telethon/crypto/__pycache__/libssl.cpython-312.pyc,,
telethon/crypto/__pycache__/rsa.cpython-312.pyc,,
telethon/crypto/aes.py,sha256=cNdfiN6SWtNL6q7S1PyU6dwpwGo0UOIzlhvuq6g1tRg,3138
telethon/crypto/aesctr.py,sha256=v_8BYNk0Al4TkLrItonoZeFn7aKOY-pPzpyMg81de20,1216
telethon/crypto/authkey.py,sha256=tP3gB3C_xAwrl2-pIcuQNTDeTnAg_dvNocuYuQ-Rbh4,1887
telethon/crypto/cdndecrypter.py,sha256=0J2iONAg0H8YS7MWKZQzvcBup5bXlJOGfxOXUGC9VN4,3844
telethon/crypto/factorization.py,sha256=a5ik8nFAU6YtGq_YBTpiHh8Ie5JTd4QKngVO413sMVU,1633
telethon/crypto/libssl.py,sha256=3UZYo24QFlUenrLB35kcIiDZWPY99xIg58iHAZxbFRg,4528
telethon/crypto/rsa.py,sha256=BeLLJ0gX15xTmOZLfoVtJN3DJWZlmYpJZYYiZ3Nms8c,6525
telethon/custom.py,sha256=eoVN0Me6yxeaQ9vCMHlrggNYa0gjNN-IWD-quDkWrqI,25
telethon/errors/__init__.py,sha256=WnwrAziTx7CHZIEtjl21P3U4o6Rd89MBtSYn_VNlJYw,1659
telethon/errors/__pycache__/__init__.cpython-312.pyc,,
telethon/errors/__pycache__/common.cpython-312.pyc,,
telethon/errors/__pycache__/rpcbaseerrors.cpython-312.pyc,,
telethon/errors/__pycache__/rpcerrorlist.cpython-312.pyc,,
telethon/errors/common.py,sha256=8eF9JpztGs21hxZAaNbmVRqLpS9Wz8rrWmgKdSJkS5I,6485
telethon/errors/rpcbaseerrors.py,sha256=2blg7dETd_JcEXP6DpYxHEAzBOxBpAdWSN45h-1_ryY,3470
telethon/errors/rpcerrorlist.py,sha256=ZlHgw8M6MkJe3xeEdhNevMZIBevG4TFJ6oJjsw-CbRQ,197688
telethon/events/__init__.py,sha256=z_gTOmcqDltd631fSWPuwMKdEqErZCMRu_gGB8cJSPg,4275
telethon/events/__pycache__/__init__.cpython-312.pyc,,
telethon/events/__pycache__/album.cpython-312.pyc,,
telethon/events/__pycache__/callbackquery.cpython-312.pyc,,
telethon/events/__pycache__/chataction.cpython-312.pyc,,
telethon/events/__pycache__/common.cpython-312.pyc,,
telethon/events/__pycache__/inlinequery.cpython-312.pyc,,
telethon/events/__pycache__/messagedeleted.cpython-312.pyc,,
telethon/events/__pycache__/messageedited.cpython-312.pyc,,
telethon/events/__pycache__/messageread.cpython-312.pyc,,
telethon/events/__pycache__/newmessage.cpython-312.pyc,,
telethon/events/__pycache__/raw.cpython-312.pyc,,
telethon/events/__pycache__/userupdate.cpython-312.pyc,,
telethon/events/album.py,sha256=Mvbv-sW5MpoBhc37iORJ_o0wYMa4Xgeyk6Qxy185g04,12890
telethon/events/callbackquery.py,sha256=23OiI3hRYKiZVAJZmhXgSU2aCklrtrc4zA8x4NDsay8,13651
telethon/events/chataction.py,sha256=7ahZhhinTzJSlPieoll4DK3RGRwf2XZbnWNy72PdCq4,17966
telethon/events/common.py,sha256=pnS5xPZ-vdYXlMsTP2e8VLyZ1lNkqxcbh2aekz5el74,6315
telethon/events/inlinequery.py,sha256=RL98F5UsH5Tk8mW73nQe-CmCJGMJJkE0HvpWJEFa_e4,8974
telethon/events/messagedeleted.py,sha256=zerWLmfGl37llNHyZR56rOgogQD9dYjqFhoTiUYFZ-A,2128
telethon/events/messageedited.py,sha256=IiwDodzSYqDTgbxL0YYPGBnYnxJWDzobg4lQ3O8lWG0,1886
telethon/events/messageread.py,sha256=MVOwnob8szisy0hu9_V00hQ0ViTf89fyKFpAezoRX-8,5470
telethon/events/newmessage.py,sha256=RujplQy3R8zb18VPS1BbCJcyRk__kbZfyWYfoKF1gi4,9161
telethon/events/raw.py,sha256=xsA128s5A02heXsdp3GXksMNBbELpkCGB9uks56mlBk,1651
telethon/events/userupdate.py,sha256=L5EIwWtwa2wf_sGkeR9vVk3t2myNU6gNeKu6Sm5ZzFs,10620
telethon/extensions/__init__.py,sha256=Dds8fDdiAudiJTAVdOy_dZS4BWesSbDbX2uItBB8m3Y,280
telethon/extensions/__pycache__/__init__.cpython-312.pyc,,
telethon/extensions/__pycache__/binaryreader.cpython-312.pyc,,
telethon/extensions/__pycache__/html.cpython-312.pyc,,
telethon/extensions/__pycache__/markdown.cpython-312.pyc,,
telethon/extensions/__pycache__/messagepacker.cpython-312.pyc,,
telethon/extensions/binaryreader.py,sha256=0fZWr_4xt45klyN1nf3c8BYN-Xi7KP02wzT_C0-_U4E,5745
telethon/extensions/html.py,sha256=wymcFxq5sw1lBe34OVCaShNRkamcPzi2GuSqZsVs7ig,6713
telethon/extensions/markdown.py,sha256=VPSkj7kayaXUj9RmDS8u-R32mD_DFzrstxI-sYk19So,6907
telethon/extensions/messagepacker.py,sha256=ENWb3eqW8QvAVTbcYlYedBADIFopW8nZUX945uZR7kM,4075
telethon/functions.py,sha256=oOvyAy283XgToCVDJjkY0ajwtHiNBt8-HQgV7Q_a5KE,28
telethon/helpers.py,sha256=itQieYj7BY5HOPZ051gccsKcKVg8SwEcoKa4ncYvgDg,14651
telethon/hints.py,sha256=r2k9avwVsWqdW_o6u_bTobcxAszyuJCqZvp7gkms8l4,1562
telethon/network/__init__.py,sha256=Yo7FYAQSzh7u9EVYULPyxMzRKbQ7X7dAK9x-RIEUgbk,585
telethon/network/__pycache__/__init__.cpython-312.pyc,,
telethon/network/__pycache__/authenticator.cpython-312.pyc,,
telethon/network/__pycache__/mtprotoplainsender.cpython-312.pyc,,
telethon/network/__pycache__/mtprotosender.cpython-312.pyc,,
telethon/network/__pycache__/mtprotostate.cpython-312.pyc,,
telethon/network/__pycache__/requeststate.cpython-312.pyc,,
telethon/network/authenticator.py,sha256=zHIsMl3pQUaA46aU-AM8Z_yWuuIJ0FiRAEMwwQcpKdc,7869
telethon/network/connection/__init__.py,sha256=pzMWk8sKUd-_w0rkVKqkZvBv7SuKbnKs6EcMA2gfxNc,423
telethon/network/connection/__pycache__/__init__.cpython-312.pyc,,
telethon/network/connection/__pycache__/connection.cpython-312.pyc,,
telethon/network/connection/__pycache__/http.cpython-312.pyc,,
telethon/network/connection/__pycache__/tcpabridged.cpython-312.pyc,,
telethon/network/connection/__pycache__/tcpfull.cpython-312.pyc,,
telethon/network/connection/__pycache__/tcpintermediate.cpython-312.pyc,,
telethon/network/connection/__pycache__/tcpmtproxy.cpython-312.pyc,,
telethon/network/connection/__pycache__/tcpobfuscated.cpython-312.pyc,,
telethon/network/connection/connection.py,sha256=7I7md3x6i09iEULk1jegZ7hyC6OxAbS8J2ESPPcfIvY,16161
telethon/network/connection/http.py,sha256=M7lJmVzKBRbJOy7fcJWLCIWNpqR5Yk6Iz1OtHG8D_F4,1220
telethon/network/connection/tcpabridged.py,sha256=J-GzWkPkPhehkjreCYLewEOBsulKqtPhnXclUcLaEZk,961
telethon/network/connection/tcpfull.py,sha256=SUFA4DY_d6Pi59W62TWI9JFWvHOqAx1ijtNRo1BcJNk,2038
telethon/network/connection/tcpintermediate.py,sha256=tX9NSs9rMTlGCC0EmCp0lWfYDrFbqyGOFkiUOh1T_Y4,1374
telethon/network/connection/tcpmtproxy.py,sha256=OjwL177N9V2JSSGWkWntuWru9DfG9MJVkFSt6G66Rfc,5755
telethon/network/connection/tcpobfuscated.py,sha256=-ulMJdzXYahVoUcmPfYcLhWQv66gKAchI1Cs11VWdto,2003
telethon/network/mtprotoplainsender.py,sha256=f8UbLhGlFE6htDvMkAN8RNBxKjXNPDAumZF2btT56z0,2019
telethon/network/mtprotosender.py,sha256=zj6vNQsfq6lGPm_9l4dKZ4-IKut6N6tV_xerVgqtPrQ,38626
telethon/network/mtprotostate.py,sha256=7OZZMUqtCLk5ymsepcIV9zMPM02FB5M0r4jXj-QhV0k,10968
telethon/network/requeststate.py,sha256=z2LiyRmnAcdjW34RtjuOPDiHPZVo-Dv5i8CBvIsi5QI,644
telethon/password.py,sha256=8hpJUihXO3UMNmId4tOHqP3nvyEjSxN81phILsCXE00,7194
telethon/requestiter.py,sha256=pzSJAJ5SU8dGDzv2zizNmS52PsxQx4qEbUymt5-bdCA,4386
telethon/sessions/__init__.py,sha256=cgGTwNhWfx_Txe1-TFL73DIZUEI6rp_4eyOOoG5aLlY,132
telethon/sessions/__pycache__/__init__.cpython-312.pyc,,
telethon/sessions/__pycache__/abstract.cpython-312.pyc,,
telethon/sessions/__pycache__/memory.cpython-312.pyc,,
telethon/sessions/__pycache__/sqlite.cpython-312.pyc,,
telethon/sessions/__pycache__/string.cpython-312.pyc,,
telethon/sessions/abstract.py,sha256=aljDD1ODDz9e4teV1OfHu-jSbnxCDrdoMQRdTsf783w,5091
telethon/sessions/memory.py,sha256=gipRjKIwsoceSezxdue1_D7MjeJwa5Q9-9x55OOAp1Y,8328
telethon/sessions/sqlite.py,sha256=Cq7RoITcAsN5ZDGFug6x1zAQaMpfLffrfGyJWSBKLt4,12575
telethon/sessions/string.py,sha256=EYX7CoLK6X6HV1zeZ298oW-XkdPu-rIhytlw2EMgjr0,1990
telethon/sync.py,sha256=BGTMlQOj60rx4P_FoH1_YA-YAuzo6p3GphW60_Bayrc,2609
telethon/tl/__init__.py,sha256=l-L4V9hN_ylGAkgI2OATJMHr-wWI2pwmcL3bB7kJ_co,42
telethon/tl/__pycache__/__init__.cpython-312.pyc,,
telethon/tl/__pycache__/alltlobjects.cpython-312.pyc,,
telethon/tl/__pycache__/tlobject.cpython-312.pyc,,
telethon/tl/alltlobjects.py,sha256=TVU0YByBzVonTxE9eTIdDiUwewbow4ARxGOhAIx_K5o,109638
telethon/tl/core/__init__.py,sha256=BnmaEvfiHdwNnxpNDaR0_M6oLHvAa3WHK7kPjBLuBBo,1104
telethon/tl/core/__pycache__/__init__.cpython-312.pyc,,
telethon/tl/core/__pycache__/gzippacked.cpython-312.pyc,,
telethon/tl/core/__pycache__/messagecontainer.cpython-312.pyc,,
telethon/tl/core/__pycache__/rpcresult.cpython-312.pyc,,
telethon/tl/core/__pycache__/tlmessage.cpython-312.pyc,,
telethon/tl/core/gzippacked.py,sha256=9hgb_aX2ZVjAgcVUj5WWlo0q3GwnApvWbDY2UtjXi_M,1316
telethon/tl/core/messagecontainer.py,sha256=fE-Tqc7nL0BcoFsy0h0U0vsuVdXM26IjVO0uZ-6pjp0,1763
telethon/tl/core/rpcresult.py,sha256=cWyVXrLITBTQq5Ahtk9Vtgs-TK0MaoKwImlGHhruJd0,1157
telethon/tl/core/tlmessage.py,sha256=7BlNdkGjd-TxK8iYEH7k88KUwMUMtSPpcctuvFHpYxM,1070
telethon/tl/custom/__init__.py,sha256=ZzeRE1a5mg5ShRlZceGiRCwkdAuyKVTIh1x5W2jp5w0,510
telethon/tl/custom/__pycache__/__init__.cpython-312.pyc,,
telethon/tl/custom/__pycache__/adminlogevent.cpython-312.pyc,,
telethon/tl/custom/__pycache__/button.cpython-312.pyc,,
telethon/tl/custom/__pycache__/chatgetter.cpython-312.pyc,,
telethon/tl/custom/__pycache__/conversation.cpython-312.pyc,,
telethon/tl/custom/__pycache__/dialog.cpython-312.pyc,,
telethon/tl/custom/__pycache__/draft.cpython-312.pyc,,
telethon/tl/custom/__pycache__/file.cpython-312.pyc,,
telethon/tl/custom/__pycache__/forward.cpython-312.pyc,,
telethon/tl/custom/__pycache__/inlinebuilder.cpython-312.pyc,,
telethon/tl/custom/__pycache__/inlineresult.cpython-312.pyc,,
telethon/tl/custom/__pycache__/inlineresults.cpython-312.pyc,,
telethon/tl/custom/__pycache__/inputsizedfile.cpython-312.pyc,,
telethon/tl/custom/__pycache__/message.cpython-312.pyc,,
telethon/tl/custom/__pycache__/messagebutton.cpython-312.pyc,,
telethon/tl/custom/__pycache__/participantpermissions.cpython-312.pyc,,
telethon/tl/custom/__pycache__/qrlogin.cpython-312.pyc,,
telethon/tl/custom/__pycache__/sendergetter.cpython-312.pyc,,
telethon/tl/custom/adminlogevent.py,sha256=d-I7AEIm8JUXoTUV30UyQ2IR6VbXQ-pMt8ucRt35uqI,16228
telethon/tl/custom/button.py,sha256=ufG49IdP7iOZbgSR57atyguRlz9upiC4J9F-44NZDMs,12411
telethon/tl/custom/chatgetter.py,sha256=eGtlD3sLXImh0Qcb11Jphz7LIpelIhnPQgevdUZqvxg,5276
telethon/tl/custom/conversation.py,sha256=EYIuKvaWj-0ZFcXrZYf2mUaXGqUHmAJVkVwmIb-NM8k,19403
telethon/tl/custom/dialog.py,sha256=PRQcsm4_h4arQUikJY-lvTI-4lEXZtgJE9l7xv6SKnA,5630
telethon/tl/custom/draft.py,sha256=Ybpk27nH_kLRPQT3T_W9iLwpqq1dREUS_cKfwhNYyMs,5978
telethon/tl/custom/file.py,sha256=fwJ7iQjTHDHpD_DCYP7GHA14F9Q-UUQ6dyr6Wi9PJ_I,4229
telethon/tl/custom/forward.py,sha256=BFoVW8BDeYtIzX48HgVhph5eJbDImN9Cf8XW2cRMSFQ,2129
telethon/tl/custom/inlinebuilder.py,sha256=J7dTymhk0RXLBAZDFpadNQSO8NIe1-KGWFJm5NRZy84,17011
telethon/tl/custom/inlineresult.py,sha256=-UB2mCGtu0zXBM1jPXziPjMCGVSPMHyQ6T-d7NerplY,6304
telethon/tl/custom/inlineresults.py,sha256=W-jiYShcLcx4DbDRy4L9vdz-j446n9AO3e20xxKLERY,2754
telethon/tl/custom/inputsizedfile.py,sha256=f26v6speewqAT29v2ebeEwo8bZMBEXh6JawdO26yFCE,310
telethon/tl/custom/message.py,sha256=yVMvXAzR6LXiS9xSWYEZqRbz8fz96G4AQWnZbXc7lXY,45417
telethon/tl/custom/messagebutton.py,sha256=K_irHfNe_SeUbT5LGGhYwaSeMcMCht20wDLv_AiyHPQ,6110
telethon/tl/custom/participantpermissions.py,sha256=E8_0v4eHd6K650BJc1_6qVaUhhl-Dbs3iD37gGA6Sv4,4131
telethon/tl/custom/qrlogin.py,sha256=I2PZS-J9i9NT_pQYiLWMzGZLTk__CF1CFgUouAE474o,4205
telethon/tl/custom/sendergetter.py,sha256=YpbFRZ_VVlLdWXdwnbry1kGxF-pJxqokOqXywDoT0pM,3854
telethon/tl/functions/__init__.py,sha256=v4CB7eZ55VaGpJjiyf6ukC10gKdbGieXgj6mxO5Wc-M,21947
telethon/tl/functions/__pycache__/__init__.cpython-312.pyc,,
telethon/tl/functions/__pycache__/account.cpython-312.pyc,,
telethon/tl/functions/__pycache__/auth.cpython-312.pyc,,
telethon/tl/functions/__pycache__/bots.cpython-312.pyc,,
telethon/tl/functions/__pycache__/channels.cpython-312.pyc,,
telethon/tl/functions/__pycache__/chatlists.cpython-312.pyc,,
telethon/tl/functions/__pycache__/contacts.cpython-312.pyc,,
telethon/tl/functions/__pycache__/folders.cpython-312.pyc,,
telethon/tl/functions/__pycache__/fragment.cpython-312.pyc,,
telethon/tl/functions/__pycache__/help.cpython-312.pyc,,
telethon/tl/functions/__pycache__/langpack.cpython-312.pyc,,
telethon/tl/functions/__pycache__/messages.cpython-312.pyc,,
telethon/tl/functions/__pycache__/payments.cpython-312.pyc,,
telethon/tl/functions/__pycache__/phone.cpython-312.pyc,,
telethon/tl/functions/__pycache__/photos.cpython-312.pyc,,
telethon/tl/functions/__pycache__/premium.cpython-312.pyc,,
telethon/tl/functions/__pycache__/smsjobs.cpython-312.pyc,,
telethon/tl/functions/__pycache__/stats.cpython-312.pyc,,
telethon/tl/functions/__pycache__/stickers.cpython-312.pyc,,
telethon/tl/functions/__pycache__/stories.cpython-312.pyc,,
telethon/tl/functions/__pycache__/updates.cpython-312.pyc,,
telethon/tl/functions/__pycache__/upload.cpython-312.pyc,,
telethon/tl/functions/__pycache__/users.cpython-312.pyc,,
telethon/tl/functions/account.py,sha256=gB9W5q_JAmGcZ9LcO8Y7Jw9HLNmVC8YzIu23cHm85Mg,109199
telethon/tl/functions/auth.py,sha256=yZdHE-qzAp0SZmJDQXxsFJDQEykPkZzTMEVLaNGQ-MY,26516
telethon/tl/functions/bots.py,sha256=X0jS3CsKMYi5tcRifMvidhns8F8xvqz3_QmgztyOd-w,36635
telethon/tl/functions/channels.py,sha256=u6ZfCcnw98WhP8u3puvkqbc4wct8kXqMALG_eZgaunQ,86483
telethon/tl/functions/chatlists.py,sha256=r1OTssim2BI617d5Q8i3QH5A0Bqo30AXo0XtT5_Rtk8,13688
telethon/tl/functions/contacts.py,sha256=drxy7JcFgWrmf1VCvDBDggzOX0r0rvXhoT24EUrVuh4,27694
telethon/tl/functions/folders.py,sha256=oV5dOauHhX4eiX-JwWZeuwU55E8joN5vdPOLhpGurfM,1493
telethon/tl/functions/fragment.py,sha256=MTazMRnh55QF5NjjqsZu_7r2HSaEa5tLDQSc0ZVdhGE,1161
telethon/tl/functions/help.py,sha256=PJZh-I2KkZehxQKaGKWhRdemPffKEtZynoD-7bzaV0A,17245
telethon/tl/functions/langpack.py,sha256=nS_ueOiArKd1tA9gHBR3Gg5ZZK4CI_brmm4DDF7Udzk,5323
telethon/tl/functions/messages.py,sha256=OwpZ9NbmdRh8CwKcZXJzgG1aVJbowHrPUXfMmgXXdCQ,344516
telethon/tl/functions/payments.py,sha256=_WTDPXWo_UQNj8DxscLTifEh39SShgLa-Y7O4TgWcWw,56928
telethon/tl/functions/phone.py,sha256=-mxaJez4QfPaTNGx6ONiT7JIPibFpqTklKVQKQMev6s,46508
telethon/tl/functions/photos.py,sha256=EqKeE3fkvTO1DeQZ6mgs64q3eLc9h6je77CMEBe3d8Q,11349
telethon/tl/functions/premium.py,sha256=WOHGfBi9VJyouxzhnjYdvgMsGw_3qPtGU0w_sg-Frxc,5751
telethon/tl/functions/smsjobs.py,sha256=e6nMNwhA-dBEp3tnaYkJRhr1qoJbZPgi7tsHH6rij9w,4376
telethon/tl/functions/stats.py,sha256=ti-hvEMrefv38lNkPjoCbFJ0V8mWQoCkTFcuOYwsGhY,12766
telethon/tl/functions/stickers.py,sha256=hGmnTK3-HeFL2bkuSP_26bzy1dpYVA6Bz6nlKC9Ghhs,15680
telethon/tl/functions/stories.py,sha256=3Ug4IYqzbHDHiYyjsZHrmjcsQ8tu7t7HWn9S5dSOQTE,42991
telethon/tl/functions/updates.py,sha256=4NaS1JnJJl6Q-Jjh0Vch5M7hT0B-i8n0OZqIOjh0ADw,4995
telethon/tl/functions/upload.py,sha256=w4s5OSToPMBR169MPDxX66re4opNnvW4UaPXHgfLqlg,9391
telethon/tl/functions/users.py,sha256=pWbSGqdkwLnF3c45T7vSejmn4P0QwBUgYC-ODpwGDD4,4755
telethon/tl/patched/__init__.py,sha256=sHj3X66Nay0U7H56xUGdyC1dH-tYIqRk7Acfe0L14Hg,552
telethon/tl/patched/__pycache__/__init__.cpython-312.pyc,,
telethon/tl/tlobject.py,sha256=FiPp2YVEu2Q-bERYrZ4wz-uSVtTSoqSi__58YDPvsGo,7390
telethon/tl/types/__init__.py,sha256=M_KjKqgG2Bkw4yQxPZoAiceRz4itY6rzM4MxRIfGasU,2318237
telethon/tl/types/__pycache__/__init__.cpython-312.pyc,,
telethon/tl/types/__pycache__/account.cpython-312.pyc,,
telethon/tl/types/__pycache__/auth.cpython-312.pyc,,
telethon/tl/types/__pycache__/bots.cpython-312.pyc,,
telethon/tl/types/__pycache__/channels.cpython-312.pyc,,
telethon/tl/types/__pycache__/chatlists.cpython-312.pyc,,
telethon/tl/types/__pycache__/contacts.cpython-312.pyc,,
telethon/tl/types/__pycache__/fragment.cpython-312.pyc,,
telethon/tl/types/__pycache__/help.cpython-312.pyc,,
telethon/tl/types/__pycache__/messages.cpython-312.pyc,,
telethon/tl/types/__pycache__/payments.cpython-312.pyc,,
telethon/tl/types/__pycache__/phone.cpython-312.pyc,,
telethon/tl/types/__pycache__/photos.cpython-312.pyc,,
telethon/tl/types/__pycache__/premium.cpython-312.pyc,,
telethon/tl/types/__pycache__/smsjobs.cpython-312.pyc,,
telethon/tl/types/__pycache__/stats.cpython-312.pyc,,
telethon/tl/types/__pycache__/stickers.cpython-312.pyc,,
telethon/tl/types/__pycache__/storage.cpython-312.pyc,,
telethon/tl/types/__pycache__/stories.cpython-312.pyc,,
telethon/tl/types/__pycache__/updates.cpython-312.pyc,,
telethon/tl/types/__pycache__/upload.cpython-312.pyc,,
telethon/tl/types/__pycache__/users.cpython-312.pyc,,
telethon/tl/types/account.py,sha256=KFoVExKkW9IdmRoDwuYNb2yqUo1A5g4Kj7R6eGnyDOg,45222
telethon/tl/types/auth.py,sha256=EPaAIHmvaqTCWk6g4waE_Iosrheu1CZJhpWL-V-15-I,31993
telethon/tl/types/bots.py,sha256=KLZ5YeckzBmZ36jU3VBInj7vmvDs1LvVKpL5Lj6Ql4w,4250
telethon/tl/types/channels.py,sha256=pMAXC2BsnOzhlLSHYMGami5d7sdgnMMxQlF66ZUbeVw,10727
telethon/tl/types/chatlists.py,sha256=14mPPIhhlCpli_fSQPx_9bowqeR78fWe2agbEWjarvw,11071
telethon/tl/types/contacts.py,sha256=_dAqFWcydqcSzIzBxYtSQ3CHPh7eFHgDBSaehQLdIeA,17292
telethon/tl/types/fragment.py,sha256=k6QT5rKkXPNa7xA2Rh7FH699nKPPrvBBHn6MxpHNw4w,2035
telethon/tl/types/help.py,sha256=mrhmAdovKlZK_91_-h-L1Xv9WaitKvVegOnpVfsvCPA,42098
telethon/tl/types/messages.py,sha256=3_33yKWoGkxCe-JTm-b5ZLawkDjctLQak5rgj92OKa8,128303
telethon/tl/types/payments.py,sha256=g5T4y5zqALIe6y8BwjAh4wVB8IyNQJcMZx_bWc4OWpo,55961
telethon/tl/types/phone.py,sha256=JcI_6NhVDVnwXI0LUghq_swEB1QeXNdz6c96BeC2HUs,11163
telethon/tl/types/photos.py,sha256=ds0vTpT_2yvE19hriVERBgyU52qFZI-RIGO3UEzxIdU,4464
telethon/tl/types/premium.py,sha256=1gWTJ9NR52JBrWpQvqskyJHiVSmK0Jn2EnFFsc5JOvQ,9641
telethon/tl/types/smsjobs.py,sha256=IqPzAvWKM7n0JlDXm_Jt2_JG6r7RSKfzqVus0iTqQ2o,3964
telethon/tl/types/stats.py,sha256=L16-XVs2uep1Tq8W3XWAUBLgaIQoU6_WCYue1WaFZcg,25359
telethon/tl/types/stickers.py,sha256=Qp-n8jEeFlrjCngufKJsqetI-vXmqmYyPk0k8Qk0Lf0,958
telethon/tl/types/storage.py,sha256=cX4kaMHpxCz_lncXaJ9Pjupmgn6Uba1rXksm3ZDEUwk,3741
telethon/tl/types/stories.py,sha256=zTSS7ieG9mTVfzXr28oVaXJt6hIzPffpd-P37InSDJg,18985
telethon/tl/types/updates.py,sha256=bhuIPYHjk7ryn2NoOg1vQ10W-m8DsOjsBSa9QUjoHAI,18123
telethon/tl/types/upload.py,sha256=vSBQ4eCuRP9nXz8KFJ8QW19XjJplYGBDh_KOIhMgErU,6217
telethon/tl/types/users.py,sha256=lBYekmubmQudSeGuua09l9ARiv0K7HUS-owLZ0qILeo,4024
telethon/types.py,sha256=qZkN0R8FO952PZac3xrIya30asfyQqp5q_fCTISHN3I,24
telethon/utils.py,sha256=DKGAKmsmd2UmMvFQ77H8M0j09iQDbJY66b_j1XRoNL8,54319
telethon/version.py,sha256=txxUrFnzZOQ2z5hyM8xlbLs_ldhJ1N2LOJQz87hlj50,96

View File

@ -1,5 +0,0 @@
Wheel-Version: 1.0
Generator: setuptools (75.8.0)
Root-Is-Purelib: true
Tag: py3-none-any

View File

@ -1,49 +0,0 @@
from typing import Any, Optional
from .main import (dotenv_values, find_dotenv, get_key, load_dotenv, set_key,
unset_key)
def load_ipython_extension(ipython: Any) -> None:
from .ipython import load_ipython_extension
load_ipython_extension(ipython)
def get_cli_string(
path: Optional[str] = None,
action: Optional[str] = None,
key: Optional[str] = None,
value: Optional[str] = None,
quote: Optional[str] = None,
):
"""Returns a string suitable for running as a shell script.
Useful for converting a arguments passed to a fabric task
to be passed to a `local` or `run` command.
"""
command = ['dotenv']
if quote:
command.append(f'-q {quote}')
if path:
command.append(f'-f {path}')
if action:
command.append(action)
if key:
command.append(key)
if value:
if ' ' in value:
command.append(f'"{value}"')
else:
command.append(value)
return ' '.join(command).strip()
__all__ = ['get_cli_string',
'load_dotenv',
'dotenv_values',
'get_key',
'set_key',
'unset_key',
'find_dotenv',
'load_ipython_extension']

View File

@ -1,6 +0,0 @@
"""Entry point for cli, enables execution with `python -m dotenv`"""
from .cli import cli
if __name__ == "__main__":
cli()

View File

@ -1,190 +0,0 @@
import json
import os
import shlex
import sys
from contextlib import contextmanager
from typing import Any, Dict, IO, Iterator, List, Optional
try:
import click
except ImportError:
sys.stderr.write('It seems python-dotenv is not installed with cli option. \n'
'Run pip install "python-dotenv[cli]" to fix this.')
sys.exit(1)
from .main import dotenv_values, set_key, unset_key
from .version import __version__
def enumerate_env() -> Optional[str]:
"""
Return a path for the ${pwd}/.env file.
If pwd does not exist, return None.
"""
try:
cwd = os.getcwd()
except FileNotFoundError:
return None
path = os.path.join(cwd, '.env')
return path
@click.group()
@click.option('-f', '--file', default=enumerate_env(),
type=click.Path(file_okay=True),
help="Location of the .env file, defaults to .env file in current working directory.")
@click.option('-q', '--quote', default='always',
type=click.Choice(['always', 'never', 'auto']),
help="Whether to quote or not the variable values. Default mode is always. This does not affect parsing.")
@click.option('-e', '--export', default=False,
type=click.BOOL,
help="Whether to write the dot file as an executable bash script.")
@click.version_option(version=__version__)
@click.pass_context
def cli(ctx: click.Context, file: Any, quote: Any, export: Any) -> None:
"""This script is used to set, get or unset values from a .env file."""
ctx.obj = {'QUOTE': quote, 'EXPORT': export, 'FILE': file}
@contextmanager
def stream_file(path: os.PathLike) -> Iterator[IO[str]]:
"""
Open a file and yield the corresponding (decoded) stream.
Exits with error code 2 if the file cannot be opened.
"""
try:
with open(path) as stream:
yield stream
except OSError as exc:
print(f"Error opening env file: {exc}", file=sys.stderr)
exit(2)
@cli.command()
@click.pass_context
@click.option('--format', default='simple',
type=click.Choice(['simple', 'json', 'shell', 'export']),
help="The format in which to display the list. Default format is simple, "
"which displays name=value without quotes.")
def list(ctx: click.Context, format: bool) -> None:
"""Display all the stored key/value."""
file = ctx.obj['FILE']
with stream_file(file) as stream:
values = dotenv_values(stream=stream)
if format == 'json':
click.echo(json.dumps(values, indent=2, sort_keys=True))
else:
prefix = 'export ' if format == 'export' else ''
for k in sorted(values):
v = values[k]
if v is not None:
if format in ('export', 'shell'):
v = shlex.quote(v)
click.echo(f'{prefix}{k}={v}')
@cli.command()
@click.pass_context
@click.argument('key', required=True)
@click.argument('value', required=True)
def set(ctx: click.Context, key: Any, value: Any) -> None:
"""Store the given key/value."""
file = ctx.obj['FILE']
quote = ctx.obj['QUOTE']
export = ctx.obj['EXPORT']
success, key, value = set_key(file, key, value, quote, export)
if success:
click.echo(f'{key}={value}')
else:
exit(1)
@cli.command()
@click.pass_context
@click.argument('key', required=True)
def get(ctx: click.Context, key: Any) -> None:
"""Retrieve the value for the given key."""
file = ctx.obj['FILE']
with stream_file(file) as stream:
values = dotenv_values(stream=stream)
stored_value = values.get(key)
if stored_value:
click.echo(stored_value)
else:
exit(1)
@cli.command()
@click.pass_context
@click.argument('key', required=True)
def unset(ctx: click.Context, key: Any) -> None:
"""Removes the given key."""
file = ctx.obj['FILE']
quote = ctx.obj['QUOTE']
success, key = unset_key(file, key, quote)
if success:
click.echo(f"Successfully removed {key}")
else:
exit(1)
@cli.command(context_settings={'ignore_unknown_options': True})
@click.pass_context
@click.option(
"--override/--no-override",
default=True,
help="Override variables from the environment file with those from the .env file.",
)
@click.argument('commandline', nargs=-1, type=click.UNPROCESSED)
def run(ctx: click.Context, override: bool, commandline: List[str]) -> None:
"""Run command with environment variables present."""
file = ctx.obj['FILE']
if not os.path.isfile(file):
raise click.BadParameter(
f'Invalid value for \'-f\' "{file}" does not exist.',
ctx=ctx
)
dotenv_as_dict = {
k: v
for (k, v) in dotenv_values(file).items()
if v is not None and (override or k not in os.environ)
}
if not commandline:
click.echo('No command given.')
exit(1)
run_command(commandline, dotenv_as_dict)
def run_command(command: List[str], env: Dict[str, str]) -> None:
"""Replace the current process with the specified command.
Replaces the current process with the specified command and the variables from `env`
added in the current environment variables.
Parameters
----------
command: List[str]
The command and it's parameters
env: Dict
The additional environment variables
Returns
-------
None
This function does not return any value. It replaces the current process with the new one.
"""
# copy the current environment variables and add the vales from
# `env`
cmd_env = os.environ.copy()
cmd_env.update(env)
os.execvpe(command[0], args=command, env=cmd_env)

View File

@ -1,39 +0,0 @@
from IPython.core.magic import Magics, line_magic, magics_class # type: ignore
from IPython.core.magic_arguments import (argument, magic_arguments, # type: ignore
parse_argstring) # type: ignore
from .main import find_dotenv, load_dotenv
@magics_class
class IPythonDotEnv(Magics):
@magic_arguments()
@argument(
'-o', '--override', action='store_true',
help="Indicate to override existing variables"
)
@argument(
'-v', '--verbose', action='store_true',
help="Indicate function calls to be verbose"
)
@argument('dotenv_path', nargs='?', type=str, default='.env',
help='Search in increasingly higher folders for the `dotenv_path`')
@line_magic
def dotenv(self, line):
args = parse_argstring(self.dotenv, line)
# Locate the .env file
dotenv_path = args.dotenv_path
try:
dotenv_path = find_dotenv(dotenv_path, True, True)
except IOError:
print("cannot find .env file")
return
# Load the .env file
load_dotenv(dotenv_path, verbose=args.verbose, override=args.override)
def load_ipython_extension(ipython):
"""Register the %dotenv magic."""
ipython.register_magics(IPythonDotEnv)

View File

@ -1,398 +0,0 @@
import io
import logging
import os
import pathlib
import shutil
import sys
import tempfile
from collections import OrderedDict
from contextlib import contextmanager
from typing import IO, Dict, Iterable, Iterator, Mapping, Optional, Tuple, Union
from .parser import Binding, parse_stream
from .variables import parse_variables
# A type alias for a string path to be used for the paths in this file.
# These paths may flow to `open()` and `shutil.move()`; `shutil.move()`
# only accepts string paths, not byte paths or file descriptors. See
# https://github.com/python/typeshed/pull/6832.
StrPath = Union[str, "os.PathLike[str]"]
logger = logging.getLogger(__name__)
def with_warn_for_invalid_lines(mappings: Iterator[Binding]) -> Iterator[Binding]:
for mapping in mappings:
if mapping.error:
logger.warning(
"python-dotenv could not parse statement starting at line %s",
mapping.original.line,
)
yield mapping
class DotEnv:
def __init__(
self,
dotenv_path: Optional[StrPath],
stream: Optional[IO[str]] = None,
verbose: bool = False,
encoding: Optional[str] = None,
interpolate: bool = True,
override: bool = True,
) -> None:
self.dotenv_path: Optional[StrPath] = dotenv_path
self.stream: Optional[IO[str]] = stream
self._dict: Optional[Dict[str, Optional[str]]] = None
self.verbose: bool = verbose
self.encoding: Optional[str] = encoding
self.interpolate: bool = interpolate
self.override: bool = override
@contextmanager
def _get_stream(self) -> Iterator[IO[str]]:
if self.dotenv_path and os.path.isfile(self.dotenv_path):
with open(self.dotenv_path, encoding=self.encoding) as stream:
yield stream
elif self.stream is not None:
yield self.stream
else:
if self.verbose:
logger.info(
"python-dotenv could not find configuration file %s.",
self.dotenv_path or ".env",
)
yield io.StringIO("")
def dict(self) -> Dict[str, Optional[str]]:
"""Return dotenv as dict"""
if self._dict:
return self._dict
raw_values = self.parse()
if self.interpolate:
self._dict = OrderedDict(
resolve_variables(raw_values, override=self.override)
)
else:
self._dict = OrderedDict(raw_values)
return self._dict
def parse(self) -> Iterator[Tuple[str, Optional[str]]]:
with self._get_stream() as stream:
for mapping in with_warn_for_invalid_lines(parse_stream(stream)):
if mapping.key is not None:
yield mapping.key, mapping.value
def set_as_environment_variables(self) -> bool:
"""
Load the current dotenv as system environment variable.
"""
if not self.dict():
return False
for k, v in self.dict().items():
if k in os.environ and not self.override:
continue
if v is not None:
os.environ[k] = v
return True
def get(self, key: str) -> Optional[str]:
""" """
data = self.dict()
if key in data:
return data[key]
if self.verbose:
logger.warning("Key %s not found in %s.", key, self.dotenv_path)
return None
def get_key(
dotenv_path: StrPath,
key_to_get: str,
encoding: Optional[str] = "utf-8",
) -> Optional[str]:
"""
Get the value of a given key from the given .env.
Returns `None` if the key isn't found or doesn't have a value.
"""
return DotEnv(dotenv_path, verbose=True, encoding=encoding).get(key_to_get)
@contextmanager
def rewrite(
path: StrPath,
encoding: Optional[str],
) -> Iterator[Tuple[IO[str], IO[str]]]:
pathlib.Path(path).touch()
with tempfile.NamedTemporaryFile(mode="w", encoding=encoding, delete=False) as dest:
error = None
try:
with open(path, encoding=encoding) as source:
yield (source, dest)
except BaseException as err:
error = err
if error is None:
shutil.move(dest.name, path)
else:
os.unlink(dest.name)
raise error from None
def set_key(
dotenv_path: StrPath,
key_to_set: str,
value_to_set: str,
quote_mode: str = "always",
export: bool = False,
encoding: Optional[str] = "utf-8",
) -> Tuple[Optional[bool], str, str]:
"""
Adds or Updates a key/value to the given .env
If the .env path given doesn't exist, fails instead of risking creating
an orphan .env somewhere in the filesystem
"""
if quote_mode not in ("always", "auto", "never"):
raise ValueError(f"Unknown quote_mode: {quote_mode}")
quote = quote_mode == "always" or (
quote_mode == "auto" and not value_to_set.isalnum()
)
if quote:
value_out = "'{}'".format(value_to_set.replace("'", "\\'"))
else:
value_out = value_to_set
if export:
line_out = f"export {key_to_set}={value_out}\n"
else:
line_out = f"{key_to_set}={value_out}\n"
with rewrite(dotenv_path, encoding=encoding) as (source, dest):
replaced = False
missing_newline = False
for mapping in with_warn_for_invalid_lines(parse_stream(source)):
if mapping.key == key_to_set:
dest.write(line_out)
replaced = True
else:
dest.write(mapping.original.string)
missing_newline = not mapping.original.string.endswith("\n")
if not replaced:
if missing_newline:
dest.write("\n")
dest.write(line_out)
return True, key_to_set, value_to_set
def unset_key(
dotenv_path: StrPath,
key_to_unset: str,
quote_mode: str = "always",
encoding: Optional[str] = "utf-8",
) -> Tuple[Optional[bool], str]:
"""
Removes a given key from the given `.env` file.
If the .env path given doesn't exist, fails.
If the given key doesn't exist in the .env, fails.
"""
if not os.path.exists(dotenv_path):
logger.warning("Can't delete from %s - it doesn't exist.", dotenv_path)
return None, key_to_unset
removed = False
with rewrite(dotenv_path, encoding=encoding) as (source, dest):
for mapping in with_warn_for_invalid_lines(parse_stream(source)):
if mapping.key == key_to_unset:
removed = True
else:
dest.write(mapping.original.string)
if not removed:
logger.warning(
"Key %s not removed from %s - key doesn't exist.", key_to_unset, dotenv_path
)
return None, key_to_unset
return removed, key_to_unset
def resolve_variables(
values: Iterable[Tuple[str, Optional[str]]],
override: bool,
) -> Mapping[str, Optional[str]]:
new_values: Dict[str, Optional[str]] = {}
for name, value in values:
if value is None:
result = None
else:
atoms = parse_variables(value)
env: Dict[str, Optional[str]] = {}
if override:
env.update(os.environ) # type: ignore
env.update(new_values)
else:
env.update(new_values)
env.update(os.environ) # type: ignore
result = "".join(atom.resolve(env) for atom in atoms)
new_values[name] = result
return new_values
def _walk_to_root(path: str) -> Iterator[str]:
"""
Yield directories starting from the given directory up to the root
"""
if not os.path.exists(path):
raise IOError("Starting path not found")
if os.path.isfile(path):
path = os.path.dirname(path)
last_dir = None
current_dir = os.path.abspath(path)
while last_dir != current_dir:
yield current_dir
parent_dir = os.path.abspath(os.path.join(current_dir, os.path.pardir))
last_dir, current_dir = current_dir, parent_dir
def find_dotenv(
filename: str = ".env",
raise_error_if_not_found: bool = False,
usecwd: bool = False,
) -> str:
"""
Search in increasingly higher folders for the given file
Returns path to the file if found, or an empty string otherwise
"""
def _is_interactive():
"""Decide whether this is running in a REPL or IPython notebook"""
try:
main = __import__("__main__", None, None, fromlist=["__file__"])
except ModuleNotFoundError:
return False
return not hasattr(main, "__file__")
def _is_debugger():
return sys.gettrace() is not None
if usecwd or _is_interactive() or _is_debugger() or getattr(sys, "frozen", False):
# Should work without __file__, e.g. in REPL or IPython notebook.
path = os.getcwd()
else:
# will work for .py files
frame = sys._getframe()
current_file = __file__
while frame.f_code.co_filename == current_file or not os.path.exists(
frame.f_code.co_filename
):
assert frame.f_back is not None
frame = frame.f_back
frame_filename = frame.f_code.co_filename
path = os.path.dirname(os.path.abspath(frame_filename))
for dirname in _walk_to_root(path):
check_path = os.path.join(dirname, filename)
if os.path.isfile(check_path):
return check_path
if raise_error_if_not_found:
raise IOError("File not found")
return ""
def load_dotenv(
dotenv_path: Optional[StrPath] = None,
stream: Optional[IO[str]] = None,
verbose: bool = False,
override: bool = False,
interpolate: bool = True,
encoding: Optional[str] = "utf-8",
) -> bool:
"""Parse a .env file and then load all the variables found as environment variables.
Parameters:
dotenv_path: Absolute or relative path to .env file.
stream: Text stream (such as `io.StringIO`) with .env content, used if
`dotenv_path` is `None`.
verbose: Whether to output a warning the .env file is missing.
override: Whether to override the system environment variables with the variables
from the `.env` file.
encoding: Encoding to be used to read the file.
Returns:
Bool: True if at least one environment variable is set else False
If both `dotenv_path` and `stream` are `None`, `find_dotenv()` is used to find the
.env file with it's default parameters. If you need to change the default parameters
of `find_dotenv()`, you can explicitly call `find_dotenv()` and pass the result
to this function as `dotenv_path`.
"""
if dotenv_path is None and stream is None:
dotenv_path = find_dotenv()
dotenv = DotEnv(
dotenv_path=dotenv_path,
stream=stream,
verbose=verbose,
interpolate=interpolate,
override=override,
encoding=encoding,
)
return dotenv.set_as_environment_variables()
def dotenv_values(
dotenv_path: Optional[StrPath] = None,
stream: Optional[IO[str]] = None,
verbose: bool = False,
interpolate: bool = True,
encoding: Optional[str] = "utf-8",
) -> Dict[str, Optional[str]]:
"""
Parse a .env file and return its content as a dict.
The returned dict will have `None` values for keys without values in the .env file.
For example, `foo=bar` results in `{"foo": "bar"}` whereas `foo` alone results in
`{"foo": None}`
Parameters:
dotenv_path: Absolute or relative path to the .env file.
stream: `StringIO` object with .env content, used if `dotenv_path` is `None`.
verbose: Whether to output a warning if the .env file is missing.
encoding: Encoding to be used to read the file.
If both `dotenv_path` and `stream` are `None`, `find_dotenv()` is used to find the
.env file.
"""
if dotenv_path is None and stream is None:
dotenv_path = find_dotenv()
return DotEnv(
dotenv_path=dotenv_path,
stream=stream,
verbose=verbose,
interpolate=interpolate,
override=True,
encoding=encoding,
).dict()

View File

@ -1,175 +0,0 @@
import codecs
import re
from typing import (IO, Iterator, Match, NamedTuple, Optional, # noqa:F401
Pattern, Sequence, Tuple)
def make_regex(string: str, extra_flags: int = 0) -> Pattern[str]:
return re.compile(string, re.UNICODE | extra_flags)
_newline = make_regex(r"(\r\n|\n|\r)")
_multiline_whitespace = make_regex(r"\s*", extra_flags=re.MULTILINE)
_whitespace = make_regex(r"[^\S\r\n]*")
_export = make_regex(r"(?:export[^\S\r\n]+)?")
_single_quoted_key = make_regex(r"'([^']+)'")
_unquoted_key = make_regex(r"([^=\#\s]+)")
_equal_sign = make_regex(r"(=[^\S\r\n]*)")
_single_quoted_value = make_regex(r"'((?:\\'|[^'])*)'")
_double_quoted_value = make_regex(r'"((?:\\"|[^"])*)"')
_unquoted_value = make_regex(r"([^\r\n]*)")
_comment = make_regex(r"(?:[^\S\r\n]*#[^\r\n]*)?")
_end_of_line = make_regex(r"[^\S\r\n]*(?:\r\n|\n|\r|$)")
_rest_of_line = make_regex(r"[^\r\n]*(?:\r|\n|\r\n)?")
_double_quote_escapes = make_regex(r"\\[\\'\"abfnrtv]")
_single_quote_escapes = make_regex(r"\\[\\']")
class Original(NamedTuple):
string: str
line: int
class Binding(NamedTuple):
key: Optional[str]
value: Optional[str]
original: Original
error: bool
class Position:
def __init__(self, chars: int, line: int) -> None:
self.chars = chars
self.line = line
@classmethod
def start(cls) -> "Position":
return cls(chars=0, line=1)
def set(self, other: "Position") -> None:
self.chars = other.chars
self.line = other.line
def advance(self, string: str) -> None:
self.chars += len(string)
self.line += len(re.findall(_newline, string))
class Error(Exception):
pass
class Reader:
def __init__(self, stream: IO[str]) -> None:
self.string = stream.read()
self.position = Position.start()
self.mark = Position.start()
def has_next(self) -> bool:
return self.position.chars < len(self.string)
def set_mark(self) -> None:
self.mark.set(self.position)
def get_marked(self) -> Original:
return Original(
string=self.string[self.mark.chars:self.position.chars],
line=self.mark.line,
)
def peek(self, count: int) -> str:
return self.string[self.position.chars:self.position.chars + count]
def read(self, count: int) -> str:
result = self.string[self.position.chars:self.position.chars + count]
if len(result) < count:
raise Error("read: End of string")
self.position.advance(result)
return result
def read_regex(self, regex: Pattern[str]) -> Sequence[str]:
match = regex.match(self.string, self.position.chars)
if match is None:
raise Error("read_regex: Pattern not found")
self.position.advance(self.string[match.start():match.end()])
return match.groups()
def decode_escapes(regex: Pattern[str], string: str) -> str:
def decode_match(match: Match[str]) -> str:
return codecs.decode(match.group(0), 'unicode-escape') # type: ignore
return regex.sub(decode_match, string)
def parse_key(reader: Reader) -> Optional[str]:
char = reader.peek(1)
if char == "#":
return None
elif char == "'":
(key,) = reader.read_regex(_single_quoted_key)
else:
(key,) = reader.read_regex(_unquoted_key)
return key
def parse_unquoted_value(reader: Reader) -> str:
(part,) = reader.read_regex(_unquoted_value)
return re.sub(r"\s+#.*", "", part).rstrip()
def parse_value(reader: Reader) -> str:
char = reader.peek(1)
if char == u"'":
(value,) = reader.read_regex(_single_quoted_value)
return decode_escapes(_single_quote_escapes, value)
elif char == u'"':
(value,) = reader.read_regex(_double_quoted_value)
return decode_escapes(_double_quote_escapes, value)
elif char in (u"", u"\n", u"\r"):
return u""
else:
return parse_unquoted_value(reader)
def parse_binding(reader: Reader) -> Binding:
reader.set_mark()
try:
reader.read_regex(_multiline_whitespace)
if not reader.has_next():
return Binding(
key=None,
value=None,
original=reader.get_marked(),
error=False,
)
reader.read_regex(_export)
key = parse_key(reader)
reader.read_regex(_whitespace)
if reader.peek(1) == "=":
reader.read_regex(_equal_sign)
value: Optional[str] = parse_value(reader)
else:
value = None
reader.read_regex(_comment)
reader.read_regex(_end_of_line)
return Binding(
key=key,
value=value,
original=reader.get_marked(),
error=False,
)
except Error:
reader.read_regex(_rest_of_line)
return Binding(
key=None,
value=None,
original=reader.get_marked(),
error=True,
)
def parse_stream(stream: IO[str]) -> Iterator[Binding]:
reader = Reader(stream)
while reader.has_next():
yield parse_binding(reader)

View File

@ -1 +0,0 @@
# Marker file for PEP 561

View File

@ -1,86 +0,0 @@
import re
from abc import ABCMeta, abstractmethod
from typing import Iterator, Mapping, Optional, Pattern
_posix_variable: Pattern[str] = re.compile(
r"""
\$\{
(?P<name>[^\}:]*)
(?::-
(?P<default>[^\}]*)
)?
\}
""",
re.VERBOSE,
)
class Atom(metaclass=ABCMeta):
def __ne__(self, other: object) -> bool:
result = self.__eq__(other)
if result is NotImplemented:
return NotImplemented
return not result
@abstractmethod
def resolve(self, env: Mapping[str, Optional[str]]) -> str: ...
class Literal(Atom):
def __init__(self, value: str) -> None:
self.value = value
def __repr__(self) -> str:
return f"Literal(value={self.value})"
def __eq__(self, other: object) -> bool:
if not isinstance(other, self.__class__):
return NotImplemented
return self.value == other.value
def __hash__(self) -> int:
return hash((self.__class__, self.value))
def resolve(self, env: Mapping[str, Optional[str]]) -> str:
return self.value
class Variable(Atom):
def __init__(self, name: str, default: Optional[str]) -> None:
self.name = name
self.default = default
def __repr__(self) -> str:
return f"Variable(name={self.name}, default={self.default})"
def __eq__(self, other: object) -> bool:
if not isinstance(other, self.__class__):
return NotImplemented
return (self.name, self.default) == (other.name, other.default)
def __hash__(self) -> int:
return hash((self.__class__, self.name, self.default))
def resolve(self, env: Mapping[str, Optional[str]]) -> str:
default = self.default if self.default is not None else ""
result = env.get(self.name, default)
return result if result is not None else ""
def parse_variables(value: str) -> Iterator[Atom]:
cursor = 0
for match in _posix_variable.finditer(value):
(start, end) = match.span()
name = match["name"]
default = match["default"]
if start > cursor:
yield Literal(value=value[cursor:start])
yield Variable(name=name, default=default)
cursor = end
length = len(value)
if cursor < length:
yield Literal(value=value[cursor:length])

View File

@ -1 +0,0 @@
__version__ = "1.1.0"

View File

@ -1,28 +0,0 @@
New BSD License
Copyright (c) 2014-2025, Taehoon Kim, Kevin Wurster
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The names of its contributors may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,202 +0,0 @@
Metadata-Version: 2.2
Name: emoji
Version: 2.14.1
Summary: Emoji for Python
Author-email: Taehoon Kim <carpedm20@gmail.com>, Kevin Wurster <wursterk@gmail.com>
Project-URL: homepage, https://github.com/carpedm20/emoji/
Project-URL: repository, https://github.com/carpedm20/emoji/
Keywords: emoji
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Classifier: Programming Language :: Python
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
Classifier: Topic :: Multimedia :: Graphics :: Presentation
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.7
Description-Content-Type: text/x-rst
License-File: LICENSE.txt
Requires-Dist: typing_extensions>=4.7.0; python_version < "3.9"
Provides-Extra: dev
Requires-Dist: pytest>=7.4.4; extra == "dev"
Requires-Dist: coverage; extra == "dev"
Emoji
=====
Emoji for Python. This project was inspired by `kyokomi <https://github.com/kyokomi/emoji>`__.
Example
-------
The entire set of Emoji codes as defined by the `Unicode consortium <https://unicode.org/emoji/charts/full-emoji-list.html>`__
is supported in addition to a bunch of `aliases <https://www.webfx.com/tools/emoji-cheat-sheet/>`__. By
default, only the official list is enabled but doing ``emoji.emojize(language='alias')`` enables
both the full list and aliases.
.. code-block:: python
>>> import emoji
>>> print(emoji.emojize('Python is :thumbs_up:'))
Python is 👍
>>> print(emoji.emojize('Python is :thumbsup:', language='alias'))
Python is 👍
>>> print(emoji.demojize('Python is 👍'))
Python is :thumbs_up:
>>> print(emoji.emojize("Python is fun :red_heart:"))
Python is fun ❤
>>> print(emoji.emojize("Python is fun :red_heart:", variant="emoji_type"))
Python is fun ❤️ #red heart, not black heart
>>> print(emoji.is_emoji("👍"))
True
..
By default, the language is English (``language='en'``) but also supported languages are:
* Spanish (``'es'``)
* Portuguese (``'pt'``)
* Italian (``'it'``)
* French (``'fr'``)
* German (``'de'``)
* Farsi/Persian (``'fa'``)
* Indonesian (``'id'``)
* Simplified Chinese (``'zh'``)
* Japanese (``'ja'``)
* Korean (``'ko'``)
* Russian (``'ru'``)
* Arabic (``'ar'``)
* Turkish (``'tr'``)
.. code-block:: python
>>> print(emoji.emojize('Python es :pulgar_hacia_arriba:', language='es'))
Python es 👍
>>> print(emoji.demojize('Python es 👍', language='es'))
Python es :pulgar_hacia_arriba:
>>> print(emoji.emojize("Python é :polegar_para_cima:", language='pt'))
Python é 👍
>>> print(emoji.demojize("Python é 👍", language='pt'))
Python é :polegar_para_cima:
..
Installation
------------
Via pip:
.. code-block:: console
$ python -m pip install emoji --upgrade
From master branch:
.. code-block:: console
$ git clone https://github.com/carpedm20/emoji.git
$ cd emoji
$ python -m pip install .
Developing
----------
.. code-block:: console
$ git clone https://github.com/carpedm20/emoji.git
$ cd emoji
$ python -m pip install -e .\[dev\]
$ pytest
$ coverage run -m pytest
$ coverage report
The ``utils/generate_emoji.py`` script is used to generate
``unicode_codes/emoji.json``. Generally speaking it scrapes a table on the
`Unicode Consortium's website <https://www.unicode.org/reports/tr51/#emoji_data>`__
with `BeautifulSoup <http://www.crummy.com/software/BeautifulSoup/>`__
For more information take a look in the `utils/README.md <utils/README.md>`__ file.
Check the code style with:
.. code-block:: console
$ python -m pip install ruff
$ ruff check emoji
Test the type checks with:
.. code-block:: console
$ python -m pip install pyright mypy typeguard
$ pyright emoji
$ pyright tests
$ mypy emoji
$ pytest --typeguard-packages=emoji
Links
-----
**Documentation**
`https://carpedm20.github.io/emoji/docs/ <https://carpedm20.github.io/emoji/docs/>`__
**Overview of all emoji:**
`https://carpedm20.github.io/emoji/ <https://carpedm20.github.io/emoji/>`__
(auto-generated list of the emoji that are supported by the current version of this package)
**For English:**
`Emoji Cheat Sheet <https://www.webfx.com/tools/emoji-cheat-sheet/>`__
`Official Unicode list <http://www.unicode.org/emoji/charts/full-emoji-list.html>`__
**For Spanish:**
`Unicode list <https://emojiterra.com/es/lista-es/>`__
**For Portuguese:**
`Unicode list <https://emojiterra.com/pt/lista/>`__
**For Italian:**
`Unicode list <https://emojiterra.com/it/lista-it/>`__
**For French:**
`Unicode list <https://emojiterra.com/fr/liste-fr/>`__
**For German:**
`Unicode list <https://emojiterra.com/de/liste/>`__
Authors
-------
Taehoon Kim / `@carpedm20 <http://carpedm20.github.io/about/>`__
Kevin Wurster / `@geowurster <http://twitter.com/geowurster/>`__
Maintainer
----------
Tahir Jalilov / `@TahirJalilov <https://github.com/TahirJalilov>`__

View File

@ -1,32 +0,0 @@
emoji-2.14.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
emoji-2.14.1.dist-info/LICENSE.txt,sha256=qr2kOJIUWxqqcdUw68m401hiYjUFScW5KezCFDn8JJI,1483
emoji-2.14.1.dist-info/METADATA,sha256=k2glblfrWWeyulfHulQClgpqJ4Bj-Z4QCerarxuI9zI,5723
emoji-2.14.1.dist-info/RECORD,,
emoji-2.14.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
emoji-2.14.1.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
emoji-2.14.1.dist-info/top_level.txt,sha256=UxKwtYLYBTA8ldfisbxvrXDgSz3eVBOq51i2h2ewato,6
emoji/__init__.py,sha256=QJ7G22kbztdZAY9WJBYyVpdoBrn8_grsWd91OQVePko,2147
emoji/__pycache__/__init__.cpython-312.pyc,,
emoji/__pycache__/core.cpython-312.pyc,,
emoji/__pycache__/tokenizer.cpython-312.pyc,,
emoji/core.py,sha256=CsoLa9OxbtSmrih-JwaSaHaNwtOrpa3Kz8LXjfiTo1Q,15823
emoji/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
emoji/tokenizer.py,sha256=sjXFQY6DdCSGnyFsTPfgUCAcfXCr0tuPMSadfPgP-90,12120
emoji/unicode_codes/__init__.py,sha256=bNNC2OSFypsPI7-zAX-_HQtdOONybZ6a59Hs-Ghq4aw,3314
emoji/unicode_codes/__pycache__/__init__.cpython-312.pyc,,
emoji/unicode_codes/__pycache__/data_dict.cpython-312.pyc,,
emoji/unicode_codes/data_dict.py,sha256=s9Ih4qPYErhLRFYOJGooSmnE8sglU7W-FiN1udJ20VM,9889
emoji/unicode_codes/emoji.json,sha256=4-nXmQR_8n6_CxBNVER6dd_la9UwW4hpCJzYdBCSMrk,507708
emoji/unicode_codes/emoji_ar.json,sha256=xCV8ukdj6mZn8X4FAri6o0QMigFxVBRbks79pdDv9nE,351189
emoji/unicode_codes/emoji_de.json,sha256=mTNKAjkzF2PlJhMxKm-Z4aFheSQhOtfXBBcjGYGK6_U,272093
emoji/unicode_codes/emoji_es.json,sha256=FTgQ-2QFiB2sAcHreTsGEEAYMDAbdLhkpyEwPvfk8XM,293678
emoji/unicode_codes/emoji_fa.json,sha256=ErmVaiIrkAOQddx8S63RI6TtvLnlzYH3OhFvd82btGg,306772
emoji/unicode_codes/emoji_fr.json,sha256=1UqSYKto_pjxJUJL3e1e0nc7wxYFZ0ZE67oz3i_uHHE,271049
emoji/unicode_codes/emoji_id.json,sha256=dONJ7_wFZqDk3U2gz3jUFH6fhOUyxaFf2Dhbw7SC6EI,281653
emoji/unicode_codes/emoji_it.json,sha256=Veozq_lB5wVYHyOt62Lb83QIJlwRI3d6TbpIlc3fPbg,290490
emoji/unicode_codes/emoji_ja.json,sha256=-w_gcrTIkMNYbKMLSmR-HW_XFZ9Vq6Rwl2rTYd5v0C8,267130
emoji/unicode_codes/emoji_ko.json,sha256=P4RjyRyxPnD-PYmFJpjbb_jj-MULB4EJB182SX-tbqA,274557
emoji/unicode_codes/emoji_pt.json,sha256=JryJ7mMXJoS5eL_-gPeB-PxvrGOcrtT6cjM1sLWLO4M,267457
emoji/unicode_codes/emoji_ru.json,sha256=VEkY0_Mqstcbq4Ja9jsTvQhj98E_URr1cfd1r2qE7q4,393755
emoji/unicode_codes/emoji_tr.json,sha256=yYUOMbi1Xbv3zKH1w-WpYRT1VnOYBKU8Zt8ikmjRwyE,271815
emoji/unicode_codes/emoji_zh.json,sha256=lKfssuGBpKs29GrzGkvqaM3Ool1cQttTjoVy4DcFBsQ,232629

View File

@ -1,5 +0,0 @@
Wheel-Version: 1.0
Generator: setuptools (75.8.0)
Root-Is-Purelib: true
Tag: py3-none-any

View File

@ -1,61 +0,0 @@
__all__ = [
# emoji.core
'emojize',
'demojize',
'analyze',
'config',
'emoji_list',
'distinct_emoji_list',
'emoji_count',
'replace_emoji',
'is_emoji',
'purely_emoji',
'version',
'Token',
'EmojiMatch',
'EmojiMatchZWJ',
'EmojiMatchZWJNonRGI',
# emoji.unicode_codes
'EMOJI_DATA',
'STATUS',
'LANGUAGES',
]
__version__ = '2.14.1'
__author__ = 'Taehoon Kim, Kevin Wurster'
__email__ = 'carpedm20@gmail.com'
# and wursterk@gmail.com, tahir.jalilov@gmail.com
__source__ = 'https://github.com/carpedm20/emoji/'
__license__ = """
New BSD License
Copyright (c) 2014-2025, Taehoon Kim, Kevin Wurster
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
* The names of its contributors may not be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
"""
from emoji.core import *
from emoji.unicode_codes import *

View File

@ -1,451 +0,0 @@
"""
emoji.core
~~~~~~~~~~
Core components for emoji.
"""
import re
import unicodedata
import sys
from typing import Any, Callable, Dict, Iterator, List, Optional, Tuple, Union
if sys.version_info < (3, 9):
from typing_extensions import Literal, Match, TypedDict # type: ignore
else:
from typing import Literal, Match, TypedDict
from emoji import unicode_codes
from emoji.tokenizer import (
Token,
EmojiMatch,
EmojiMatchZWJ,
EmojiMatchZWJNonRGI,
tokenize,
filter_tokens,
)
__all__ = [
'emojize',
'demojize',
'analyze',
'config',
'emoji_list',
'distinct_emoji_list',
'emoji_count',
'replace_emoji',
'is_emoji',
'purely_emoji',
'version',
'Token',
'EmojiMatch',
'EmojiMatchZWJ',
'EmojiMatchZWJNonRGI',
]
_DEFAULT_DELIMITER = ':'
# In Arabic language, the unicode character "\u0655" should be kept so we add it to the pattern below
_EMOJI_NAME_PATTERN = '\\w\\-&.’”“()!#*+,/«»\u0300\u0301\u0302\u0303\u0306\u0308\u030a\u0327\u064b\u064e\u064f\u0650\u0653\u0654\u3099\u30fb\u309a\u0655'
class _EmojiListReturn(TypedDict):
emoji: str
match_start: int
match_end: int
class config:
"""Module-wide configuration"""
demojize_keep_zwj = True
"""Change the behavior of :func:`emoji.demojize()` regarding
zero-width-joiners (ZWJ/``\\u200D``) in emoji that are not
"recommended for general interchange" (non-RGI).
It has no effect on RGI emoji.
For example this family emoji with different skin tones "👨‍👩🏿‍👧🏻‍👦🏾" contains four
person emoji that are joined together by three ZWJ characters:
``👨\\u200D👩🏿\\u200D👧🏻\\u200D👦🏾``
If ``True``, the zero-width-joiners will be kept and :func:`emoji.emojize()` can
reverse the :func:`emoji.demojize()` operation:
``emoji.emojize(emoji.demojize(s)) == s``
The example emoji would be converted to
``:man:\\u200d:woman_dark_skin_tone:\\u200d:girl_light_skin_tone:\\u200d:boy_medium-dark_skin_tone:``
If ``False``, the zero-width-joiners will be removed and :func:`emoji.emojize()`
can only reverse the individual emoji: ``emoji.emojize(emoji.demojize(s)) != s``
The example emoji would be converted to
``:man::woman_dark_skin_tone::girl_light_skin_tone::boy_medium-dark_skin_tone:``
"""
replace_emoji_keep_zwj = False
"""Change the behavior of :func:`emoji.replace_emoji()` regarding
zero-width-joiners (ZWJ/``\\u200D``) in emoji that are not
"recommended for general interchange" (non-RGI).
It has no effect on RGI emoji.
See :attr:`config.demojize_keep_zwj` for more information.
"""
@staticmethod
def load_language(language: Union[List[str], str, None] = None):
"""Load one or multiple languages into memory.
If no language is specified, all languages will be loaded.
This makes language data accessible in the :data:`EMOJI_DATA` dict.
For example to access a French emoji name, first load French with
``emoji.config.load_language('fr')``
and then access it with
``emoji.EMOJI_DATA['🏄']['fr']``
Available languages are listed in :data:`LANGUAGES`"""
languages = (
[language]
if isinstance(language, str)
else language
if language
else unicode_codes.LANGUAGES
)
for lang in languages:
unicode_codes.load_from_json(lang)
def emojize(
string: str,
delimiters: Tuple[str, str] = (_DEFAULT_DELIMITER, _DEFAULT_DELIMITER),
variant: Optional[Literal['text_type', 'emoji_type']] = None,
language: str = 'en',
version: Optional[float] = None,
handle_version: Optional[Union[str, Callable[[str, Dict[str, str]], str]]] = None,
) -> str:
"""
Replace emoji names in a string with Unicode codes.
>>> import emoji
>>> print(emoji.emojize("Python is fun :thumbsup:", language='alias'))
Python is fun 👍
>>> print(emoji.emojize("Python is fun :thumbs_up:"))
Python is fun 👍
>>> print(emoji.emojize("Python is fun {thumbs_up}", delimiters = ("{", "}")))
Python is fun 👍
>>> print(emoji.emojize("Python is fun :red_heart:", variant="text_type"))
Python is fun
>>> print(emoji.emojize("Python is fun :red_heart:", variant="emoji_type"))
Python is fun # red heart, not black heart
:param string: String contains emoji names.
:param delimiters: (optional) Use delimiters other than _DEFAULT_DELIMITER. Each delimiter
should contain at least one character that is not part of a-zA-Z0-9 and ``_-&.()!?#*+,``.
See ``emoji.core._EMOJI_NAME_PATTERN`` for the regular expression of unsafe characters.
:param variant: (optional) Choose variation selector between "base"(None), VS-15 ("text_type") and VS-16 ("emoji_type")
:param language: Choose language of emoji name: language code 'es', 'de', etc. or 'alias'
to use English aliases
:param version: (optional) Max version. If set to an Emoji Version,
all emoji above this version will be ignored.
:param handle_version: (optional) Replace the emoji above ``version``
instead of ignoring it. handle_version can be either a string or a
callable; If it is a callable, it's passed the Unicode emoji and the
data dict from :data:`EMOJI_DATA` and must return a replacement string
to be used::
handle_version('\\U0001F6EB', {
'en' : ':airplane_departure:',
'status' : fully_qualified,
'E' : 1,
'alias' : [':flight_departure:'],
'de': ':abflug:',
'es': ':avión_despegando:',
...
})
:raises ValueError: if ``variant`` is neither None, 'text_type' or 'emoji_type'
"""
unicode_codes.load_from_json(language)
pattern = re.compile(
'(%s[%s]+%s)'
% (re.escape(delimiters[0]), _EMOJI_NAME_PATTERN, re.escape(delimiters[1]))
)
def replace(match: Match[str]) -> str:
name = match.group(1)[len(delimiters[0]) : -len(delimiters[1])]
emj = unicode_codes.get_emoji_by_name(
_DEFAULT_DELIMITER
+ unicodedata.normalize('NFKC', name)
+ _DEFAULT_DELIMITER,
language,
)
if emj is None:
return match.group(1)
if version is not None and unicode_codes.EMOJI_DATA[emj]['E'] > version:
if callable(handle_version):
emj_data = unicode_codes.EMOJI_DATA[emj].copy()
emj_data['match_start'] = match.start()
emj_data['match_end'] = match.end()
return handle_version(emj, emj_data)
elif handle_version is not None:
return str(handle_version)
else:
return ''
if variant is None or 'variant' not in unicode_codes.EMOJI_DATA[emj]:
return emj
if emj[-1] == '\ufe0e' or emj[-1] == '\ufe0f':
# Remove an existing variant
emj = emj[0:-1]
if variant == 'text_type':
return emj + '\ufe0e'
elif variant == 'emoji_type':
return emj + '\ufe0f'
else:
raise ValueError(
"Parameter 'variant' must be either None, 'text_type' or 'emoji_type'"
)
return pattern.sub(replace, string)
def analyze(
string: str, non_emoji: bool = False, join_emoji: bool = True
) -> Iterator[Token]:
"""
Find unicode emoji in a string. Yield each emoji as a named tuple
:class:`Token` ``(chars, EmojiMatch)`` or :class:`Token` ``(chars, EmojiMatchZWJNonRGI)``.
If ``non_emoji`` is True, also yield all other characters as
:class:`Token` ``(char, char)`` .
:param string: String to analyze
:param non_emoji: If True also yield all non-emoji characters as Token(char, char)
:param join_emoji: If True, multiple EmojiMatch are merged into a single
EmojiMatchZWJNonRGI if they are separated only by a ZWJ.
"""
return filter_tokens(
tokenize(string, keep_zwj=True), emoji_only=not non_emoji, join_emoji=join_emoji
)
def demojize(
string: str,
delimiters: Tuple[str, str] = (_DEFAULT_DELIMITER, _DEFAULT_DELIMITER),
language: str = 'en',
version: Optional[float] = None,
handle_version: Optional[Union[str, Callable[[str, Dict[str, str]], str]]] = None,
) -> str:
"""
Replace Unicode emoji in a string with emoji shortcodes. Useful for storage.
>>> import emoji
>>> print(emoji.emojize("Python is fun :thumbs_up:"))
Python is fun 👍
>>> print(emoji.demojize("Python is fun 👍"))
Python is fun :thumbs_up:
>>> print(emoji.demojize("icode is tricky 😯", delimiters=("__", "__")))
Unicode is tricky __hushed_face__
:param string: String contains Unicode characters. MUST BE UNICODE.
:param delimiters: (optional) User delimiters other than ``_DEFAULT_DELIMITER``
:param language: Choose language of emoji name: language code 'es', 'de', etc. or 'alias'
to use English aliases
:param version: (optional) Max version. If set to an Emoji Version,
all emoji above this version will be removed.
:param handle_version: (optional) Replace the emoji above ``version``
instead of removing it. handle_version can be either a string or a
callable ``handle_version(emj: str, data: dict) -> str``; If it is
a callable, it's passed the Unicode emoji and the data dict from
:data:`EMOJI_DATA` and must return a replacement string to be used.
The passed data is in the form of::
handle_version('\\U0001F6EB', {
'en' : ':airplane_departure:',
'status' : fully_qualified,
'E' : 1,
'alias' : [':flight_departure:'],
'de': ':abflug:',
'es': ':avión_despegando:',
...
})
"""
if language == 'alias':
language = 'en'
_use_aliases = True
else:
_use_aliases = False
unicode_codes.load_from_json(language)
def handle(emoji_match: EmojiMatch) -> str:
assert emoji_match.data is not None
if version is not None and emoji_match.data['E'] > version:
if callable(handle_version):
return handle_version(emoji_match.emoji, emoji_match.data_copy())
elif handle_version is not None:
return handle_version
else:
return ''
elif language in emoji_match.data:
if _use_aliases and 'alias' in emoji_match.data:
return (
delimiters[0] + emoji_match.data['alias'][0][1:-1] + delimiters[1]
)
else:
return delimiters[0] + emoji_match.data[language][1:-1] + delimiters[1]
else:
# The emoji exists, but it is not translated, so we keep the emoji
return emoji_match.emoji
matches = tokenize(string, keep_zwj=config.demojize_keep_zwj)
return ''.join(
str(handle(token.value)) if isinstance(token.value, EmojiMatch) else token.value
for token in matches
)
def replace_emoji(
string: str,
replace: Union[str, Callable[[str, Dict[str, str]], str]] = '',
version: float = -1,
) -> str:
"""
Replace Unicode emoji in a customizable string.
:param string: String contains Unicode characters. MUST BE UNICODE.
:param replace: (optional) replace can be either a string or a callable;
If it is a callable, it's passed the Unicode emoji and the data dict from
:data:`EMOJI_DATA` and must return a replacement string to be used.
replace(str, dict) -> str
:param version: (optional) Max version. If set to an Emoji Version,
only emoji above this version will be replaced.
"""
def handle(emoji_match: EmojiMatch) -> str:
if version > -1:
assert emoji_match.data is not None
if emoji_match.data['E'] > version:
if callable(replace):
return replace(emoji_match.emoji, emoji_match.data_copy())
else:
return str(replace)
elif callable(replace):
return replace(emoji_match.emoji, emoji_match.data_copy())
elif replace is not None: # type: ignore
return replace
return emoji_match.emoji
matches = tokenize(string, keep_zwj=config.replace_emoji_keep_zwj)
if config.replace_emoji_keep_zwj:
matches = filter_tokens(matches, emoji_only=False, join_emoji=True)
return ''.join(
str(handle(m.value)) if isinstance(m.value, EmojiMatch) else m.value
for m in matches
)
def emoji_list(string: str) -> List[_EmojiListReturn]:
"""
Returns the location and emoji in list of dict format.
>>> emoji.emoji_list("Hi, I am fine. 😁")
[{'match_start': 15, 'match_end': 16, 'emoji': '😁'}]
"""
return [
{
'match_start': m.value.start,
'match_end': m.value.end,
'emoji': m.value.emoji,
}
for m in tokenize(string, keep_zwj=False)
if isinstance(m.value, EmojiMatch)
]
def distinct_emoji_list(string: str) -> List[str]:
"""Returns distinct list of emojis from the string."""
distinct_list = list({e['emoji'] for e in emoji_list(string)})
return distinct_list
def emoji_count(string: str, unique: bool = False) -> int:
"""
Returns the count of emojis in a string.
:param unique: (optional) True if count only unique emojis
"""
if unique:
return len(distinct_emoji_list(string))
return len(emoji_list(string))
def is_emoji(string: str) -> bool:
"""
Returns True if the string is a single emoji, and it is "recommended for
general interchange" by Unicode.org.
"""
return string in unicode_codes.EMOJI_DATA
def purely_emoji(string: str) -> bool:
"""
Returns True if the string contains only emojis.
This might not imply that `is_emoji` for all the characters, for example,
if the string contains variation selectors.
"""
return all(isinstance(m.value, EmojiMatch) for m in analyze(string, non_emoji=True))
def version(string: str) -> float:
"""
Returns the Emoji Version of the emoji.
See https://www.unicode.org/reports/tr51/#Versioning for more information.
>>> emoji.version("😁")
0.6
>>> emoji.version(":butterfly:")
3
:param string: An emoji or a text containing an emoji
:raises ValueError: if ``string`` does not contain an emoji
"""
# Try dictionary lookup
if string in unicode_codes.EMOJI_DATA:
return unicode_codes.EMOJI_DATA[string]['E']
# Try name lookup
emj_code = unicode_codes.get_emoji_by_name(string, 'en')
if emj_code and emj_code in unicode_codes.EMOJI_DATA:
return unicode_codes.EMOJI_DATA[emj_code]['E']
# Try to find first emoji in string
version: List[float] = []
def f(e: str, emoji_data: Dict[str, Any]) -> str:
version.append(emoji_data['E'])
return ''
replace_emoji(string, replace=f, version=-1)
if version:
return version[0]
emojize(string, language='alias', version=-1, handle_version=f)
if version:
return version[0]
for lang_code in unicode_codes.LANGUAGES:
emojize(string, language=lang_code, version=-1, handle_version=f)
if version:
return version[0]
raise ValueError('No emoji found in string')

View File

@ -1,376 +0,0 @@
"""
emoji.tokenizer
~~~~~~~~~~~~~~~
Components for detecting and tokenizing emoji in strings.
"""
from typing import List, NamedTuple, Dict, Union, Iterator, Any
from emoji import unicode_codes
__all__ = [
'EmojiMatch',
'EmojiMatchZWJ',
'EmojiMatchZWJNonRGI',
'Token',
'tokenize',
'filter_tokens',
]
_ZWJ = '\u200d'
_SEARCH_TREE: Dict[str, Any] = {}
class EmojiMatch:
"""
Represents a match of a "recommended for general interchange" (RGI)
emoji in a string.
"""
__slots__ = ('emoji', 'start', 'end', 'data')
def __init__(
self, emoji: str, start: int, end: int, data: Union[Dict[str, Any], None]
):
self.emoji = emoji
"""The emoji substring"""
self.start = start
"""The start index of the match in the string"""
self.end = end
"""The end index of the match in the string"""
self.data = data
"""The entry from :data:`EMOJI_DATA` for this emoji or ``None`` if the emoji is non-RGI"""
def data_copy(self) -> Dict[str, Any]:
"""
Returns a copy of the data from :data:`EMOJI_DATA` for this match
with the additional keys ``match_start`` and ``match_end``.
"""
if self.data:
emj_data = self.data.copy()
emj_data['match_start'] = self.start
emj_data['match_end'] = self.end
return emj_data
else:
return {'match_start': self.start, 'match_end': self.end}
def is_zwj(self) -> bool:
"""
Checks if this is a ZWJ-emoji.
:returns: True if this is a ZWJ-emoji, False otherwise
"""
return _ZWJ in self.emoji
def split(self) -> Union['EmojiMatchZWJ', 'EmojiMatch']:
"""
Splits a ZWJ-emoji into its constituents.
:returns: An :class:`EmojiMatchZWJ` containing the "sub-emoji" if this is a ZWJ-emoji, otherwise self
"""
if self.is_zwj():
return EmojiMatchZWJ(self)
else:
return self
def __repr__(self) -> str:
return f'{self.__class__.__name__}({self.emoji}, {self.start}:{self.end})'
class EmojiMatchZWJ(EmojiMatch):
"""
Represents a match of multiple emoji in a string that were joined by
zero-width-joiners (ZWJ/``\\u200D``)."""
__slots__ = ('emojis',)
def __init__(self, match: EmojiMatch):
super().__init__(match.emoji, match.start, match.end, match.data)
self.emojis: List[EmojiMatch] = []
"""List of sub emoji as EmojiMatch objects"""
i = match.start
for e in match.emoji.split(_ZWJ):
m = EmojiMatch(e, i, i + len(e), unicode_codes.EMOJI_DATA.get(e, None))
self.emojis.append(m)
i += len(e) + 1
def join(self) -> str:
"""
Joins a ZWJ-emoji into a string
"""
return _ZWJ.join(e.emoji for e in self.emojis)
def is_zwj(self) -> bool:
return True
def split(self) -> 'EmojiMatchZWJ':
return self
def __repr__(self) -> str:
return f'{self.__class__.__name__}({self.join()}, {self.start}:{self.end})'
class EmojiMatchZWJNonRGI(EmojiMatchZWJ):
"""
Represents a match of multiple emoji in a string that were joined by
zero-width-joiners (ZWJ/``\\u200D``). This class is only used for emoji
that are not "recommended for general interchange" (non-RGI) by Unicode.org.
The data property of this class is always None.
"""
def __init__(self, first_emoji_match: EmojiMatch, second_emoji_match: EmojiMatch):
self.emojis = [first_emoji_match, second_emoji_match]
"""List of sub emoji as EmojiMatch objects"""
self._update()
def _update(self):
self.emoji = _ZWJ.join(e.emoji for e in self.emojis)
self.start = self.emojis[0].start
self.end = self.emojis[-1].end
self.data = None
def _add(self, next_emoji_match: EmojiMatch):
self.emojis.append(next_emoji_match)
self._update()
class Token(NamedTuple):
"""
A named tuple containing the matched string and its :class:`EmojiMatch` object if it is an emoji
or a single character that is not a unicode emoji.
"""
chars: str
value: Union[str, EmojiMatch]
def tokenize(string: str, keep_zwj: bool) -> Iterator[Token]:
"""
Finds unicode emoji in a string. Yields all normal characters as a named
tuple :class:`Token` ``(char, char)`` and all emoji as :class:`Token` ``(chars, EmojiMatch)``.
:param string: String contains unicode characters. MUST BE UNICODE.
:param keep_zwj: Should ZWJ-characters (``\\u200D``) that join non-RGI emoji be
skipped or should be yielded as normal characters
:return: An iterable of tuples :class:`Token` ``(char, char)`` or :class:`Token` ``(chars, EmojiMatch)``
"""
tree = get_search_tree()
EMOJI_DATA = unicode_codes.EMOJI_DATA
# result: [ Token(oldsubstring0, EmojiMatch), Token(char1, char1), ... ]
result: List[Token] = []
i = 0
length = len(string)
ignore: List[
int
] = [] # index of chars in string that are skipped, i.e. the ZWJ-char in non-RGI-ZWJ-sequences
while i < length:
consumed = False
char = string[i]
if i in ignore:
i += 1
if char == _ZWJ and keep_zwj:
result.append(Token(char, char))
continue
elif char in tree:
j = i + 1
sub_tree = tree[char]
while j < length and string[j] in sub_tree:
if j in ignore:
break
sub_tree = sub_tree[string[j]]
j += 1
if 'data' in sub_tree:
emj_data = sub_tree['data']
code_points = string[i:j]
# We cannot yield the result here, we need to defer
# the call until we are sure that the emoji is finished
# i.e. we're not inside an ongoing ZWJ-sequence
match_obj = EmojiMatch(code_points, i, j, emj_data)
i = j - 1
consumed = True
result.append(Token(code_points, match_obj))
elif (
char == _ZWJ
and result
and result[-1].chars in EMOJI_DATA
and i > 0
and string[i - 1] in tree
):
# the current char is ZWJ and the last match was an emoji
ignore.append(i)
if (
EMOJI_DATA[result[-1].chars]['status']
== unicode_codes.STATUS['component']
):
# last match was a component, it could be ZWJ+EMOJI+COMPONENT
# or ZWJ+COMPONENT
i = i - sum(len(t.chars) for t in result[-2:])
if string[i] == _ZWJ:
# It's ZWJ+COMPONENT, move one back
i += 1
del result[-1]
else:
# It's ZWJ+EMOJI+COMPONENT, move two back
del result[-2:]
else:
# last match result[-1] was a normal emoji, move cursor
# before the emoji
i = i - len(result[-1].chars)
del result[-1]
continue
elif result:
yield from result
result = []
if not consumed and char != '\ufe0e' and char != '\ufe0f':
result.append(Token(char, char))
i += 1
yield from result
def filter_tokens(
matches: Iterator[Token], emoji_only: bool, join_emoji: bool
) -> Iterator[Token]:
"""
Filters the output of `tokenize()`
:param matches: An iterable of tuples of the form ``(match_str, result)``
where ``result`` is either an EmojiMatch or a string.
:param emoji_only: If True, only EmojiMatch are returned in the output.
If False all characters are returned
:param join_emoji: If True, multiple EmojiMatch are merged into
a single :class:`EmojiMatchZWJNonRGI` if they are separated only by a ZWJ.
:return: An iterable of tuples :class:`Token` ``(char, char)``,
:class:`Token` ``(chars, EmojiMatch)`` or :class:`Token` ``(chars, EmojiMatchZWJNonRGI)``
"""
if not join_emoji and not emoji_only:
yield from matches
return
if not join_emoji:
for token in matches:
if token.chars != _ZWJ:
yield token
return
# Combine multiple EmojiMatch that are separated by ZWJs into
# a single EmojiMatchZWJNonRGI
previous_is_emoji = False
previous_is_zwj = False
pre_previous_is_emoji = False
accumulator: List[Token] = []
for token in matches:
pre_previous_is_emoji = previous_is_emoji
if previous_is_emoji and token.value == _ZWJ:
previous_is_zwj = True
elif isinstance(token.value, EmojiMatch):
if pre_previous_is_emoji and previous_is_zwj:
if isinstance(accumulator[-1].value, EmojiMatchZWJNonRGI):
accumulator[-1].value._add(token.value) # pyright: ignore [reportPrivateUsage]
accumulator[-1] = Token(
accumulator[-1].chars + _ZWJ + token.chars,
accumulator[-1].value,
)
else:
prev = accumulator.pop()
assert isinstance(prev.value, EmojiMatch)
accumulator.append(
Token(
prev.chars + _ZWJ + token.chars,
EmojiMatchZWJNonRGI(prev.value, token.value),
)
)
else:
accumulator.append(token)
previous_is_emoji = True
previous_is_zwj = False
else:
# Other character, not an emoji
previous_is_emoji = False
previous_is_zwj = False
yield from accumulator
if not emoji_only:
yield token
accumulator = []
yield from accumulator
def get_search_tree() -> Dict[str, Any]:
"""
Generate a search tree for demojize().
Example of a search tree::
EMOJI_DATA =
{'a': {'en': ':Apple:'},
'b': {'en': ':Bus:'},
'ba': {'en': ':Bat:'},
'band': {'en': ':Beatles:'},
'bandit': {'en': ':Outlaw:'},
'bank': {'en': ':BankOfEngland:'},
'bb': {'en': ':BB-gun:'},
'c': {'en': ':Car:'}}
_SEARCH_TREE =
{'a': {'data': {'en': ':Apple:'}},
'b': {'a': {'data': {'en': ':Bat:'},
'n': {'d': {'data': {'en': ':Beatles:'},
'i': {'t': {'data': {'en': ':Outlaw:'}}}},
'k': {'data': {'en': ':BankOfEngland:'}}}},
'b': {'data': {'en': ':BB-gun:'}},
'data': {'en': ':Bus:'}},
'c': {'data': {'en': ':Car:'}}}
_SEARCH_TREE
/ |
/ |
a b c
| / | |
| / | |
:Apple: ba :Bus: bb :Car:
/ |
/ |
:Bat: ban :BB-gun:
/
/
band bank
/ |
/ |
bandi :Beatles: :BankOfEngland:
|
bandit
|
:Outlaw:
"""
if not _SEARCH_TREE:
for emj in unicode_codes.EMOJI_DATA:
sub_tree = _SEARCH_TREE
lastidx = len(emj) - 1
for i, char in enumerate(emj):
if char not in sub_tree:
sub_tree[char] = {}
sub_tree = sub_tree[char]
if i == lastidx:
sub_tree['data'] = unicode_codes.EMOJI_DATA[emj]
return _SEARCH_TREE

View File

@ -1,111 +0,0 @@
import sys
import importlib.resources
import json
from functools import lru_cache
from warnings import warn
from typing import Any, BinaryIO, Dict, List, Optional
from emoji.unicode_codes.data_dict import STATUS, LANGUAGES
__all__ = [
'get_emoji_by_name',
'load_from_json',
'EMOJI_DATA',
'STATUS',
'LANGUAGES',
]
_DEFAULT_KEYS = ('en', 'alias', 'E', 'status') # The keys in emoji.json
_loaded_keys: List[str] = list(
_DEFAULT_KEYS
) # Keep track of keys already loaded from json files to avoid loading them twice
@lru_cache(maxsize=4000)
def get_emoji_by_name(name: str, language: str) -> Optional[str]:
"""
Find emoji by short-name in a specific language.
Returns None if not found
:param name: emoji short code e.g. ":banana:"
:param language: language-code e.g. 'es', 'de', etc. or 'alias'
"""
fully_qualified = STATUS['fully_qualified']
if language == 'alias':
for emj, data in EMOJI_DATA.items():
if name in data.get('alias', []) and data['status'] <= fully_qualified:
return emj
language = 'en'
for emj, data in EMOJI_DATA.items():
if data.get(language) == name and data['status'] <= fully_qualified:
return emj
return None
class EmojiDataDict(Dict[str, Any]):
"""Replaces built-in-dict in the values of the EMOJI_DATA dict.
Auto loads language data when accessing language data via
key-access without prior loading of the language:
e.g. EMOJI_DATA['👌']['fr'] will auto load French language and not throw
a KeyError.
Shows a deprecation warning explainging that `emoji.config.load_language()`
should be used."""
def __missing__(self, key: str) -> str:
"""Auto load language `key`, raises KeyError if language is no supported."""
if key in LANGUAGES and key not in _loaded_keys:
load_from_json(key)
if key in self:
warn(
f"""Use emoji.config.load_language('{key}') before accesing EMOJI_DATA[emj]['{key}'].
Accessing EMOJI_DATA[emj]['{key}'] without loading the language is deprecated.""",
DeprecationWarning,
stacklevel=3,
)
return self[key] # type: ignore
raise KeyError(key)
EMOJI_DATA: Dict[str, Dict[str, Any]]
def _open_file(name: str) -> BinaryIO:
if sys.version_info >= (3, 9):
return importlib.resources.files('emoji.unicode_codes').joinpath(name).open('rb')
else:
return importlib.resources.open_binary('emoji.unicode_codes', name)
def _load_default_from_json():
global EMOJI_DATA
global _loaded_keys
with _open_file('emoji.json') as f:
EMOJI_DATA = dict(json.load(f, object_pairs_hook=EmojiDataDict)) # type: ignore
_loaded_keys = list(_DEFAULT_KEYS)
def load_from_json(key: str):
"""Load values from the file 'emoji_{key}.json' into EMOJI_DATA"""
if key in _loaded_keys:
return
if key not in LANGUAGES:
raise NotImplementedError('Language not supported', key)
with _open_file(f'emoji_{key}.json') as f:
for emj, value in json.load(f).items():
EMOJI_DATA[emj][key] = value # type: ignore
_loaded_keys.append(key)
_load_default_from_json()

View File

@ -1,276 +0,0 @@
"""Data containing all current emoji
Extracted from https://unicode.org/Public/emoji/latest/emoji-test.txt
and https://www.unicode.org/Public/UCD/latest/ucd/emoji/emoji-variation-sequences.txt
See utils/generate_emoji.py
+----------------+-------------+------------------+-------------------+
| Emoji Version | Date | Unicode Version | Data File Comment |
+----------------+-------------+------------------+-------------------+
| N/A | 2010-10-11 | Unicode 6.0 | E0.6 |
| N/A | 2014-06-16 | Unicode 7.0 | E0.7 |
| Emoji 1.0 | 2015-06-09 | Unicode 8.0 | E1.0 |
| Emoji 2.0 | 2015-11-12 | Unicode 8.0 | E2.0 |
| Emoji 3.0 | 2016-06-03 | Unicode 9.0 | E3.0 |
| Emoji 4.0 | 2016-11-22 | Unicode 9.0 | E4.0 |
| Emoji 5.0 | 2017-06-20 | Unicode 10.0 | E5.0 |
| Emoji 11.0 | 2018-05-21 | Unicode 11.0 | E11.0 |
| Emoji 12.0 | 2019-03-05 | Unicode 12.0 | E12.0 |
| Emoji 12.1 | 2019-10-21 | Unicode 12.1 | E12.1 |
| Emoji 13.0 | 2020-03-10 | Unicode 13.0 | E13.0 |
| Emoji 13.1 | 2020-09-15 | Unicode 13.0 | E13.1 |
| Emoji 14.0 | 2021-09-14 | Unicode 14.0 | E14.0 |
| Emoji 15.0 | 2022-09-13 | Unicode 15.0 | E15.0 |
| Emoji 15.1 | 2023-09-12 | Unicode 15.1 | E15.1 |
| Emoji 16.0 | 2024-09-10 | Unicode 16.0 | E16.0 |
http://www.unicode.org/reports/tr51/#Versioning
"""
__all__ = ['STATUS', 'LANGUAGES']
from typing import Any, Dict, List
component = 1
fully_qualified = 2
minimally_qualified = 3
unqualified = 4
STATUS: Dict[str, int] = {
'component': component,
'fully_qualified': fully_qualified,
'minimally_qualified': minimally_qualified,
'unqualified': unqualified,
}
LANGUAGES: List[str] = [
'en',
'es',
'ja',
'ko',
'pt',
'it',
'fr',
'de',
'fa',
'id',
'zh',
'ru',
'tr',
'ar',
]
# The following is only an example of how the EMOJI_DATA dict is structured.
# The real data is loaded from the json files at runtime, see unicode_codes/__init__.py
EMOJI_DATA: Dict[str, Dict[str, Any]] = {
'\U0001f947': { # 🥇
'en': ':1st_place_medal:',
'status': fully_qualified,
'E': 3,
'de': ':goldmedaille:',
'es': ':medalla_de_oro:',
'fr': ':médaille_dor:',
'ja': ':金メダル:',
'ko': ':금메달:',
'pt': ':medalha_de_ouro:',
'it': ':medaglia_doro:',
'fa': ':مدال_طلا:',
'id': ':medali_emas:',
'zh': ':金牌:',
'ru': 'олотая_медаль:',
'tr': ':birincilik_madalyası:',
'ar': ':ميدالية_مركز_أول:',
},
'\U0001f948': { # 🥈
'en': ':2nd_place_medal:',
'status': fully_qualified,
'E': 3,
'de': ':silbermedaille:',
'es': ':medalla_de_plata:',
'fr': ':médaille_dargent:',
'ja': ':銀メダル:',
'ko': ':은메달:',
'pt': ':medalha_de_prata:',
'it': ':medaglia_dargento:',
'fa': ':مدال_نقره:',
'id': ':medali_perak:',
'zh': ':银牌:',
'ru': ':серебряная_медаль:',
'tr': ':ikincilik_madalyası:',
'ar': ':ميدالية_مركز_ثان:',
},
'\U0001f949': { # 🥉
'en': ':3rd_place_medal:',
'status': fully_qualified,
'E': 3,
'de': ':bronzemedaille:',
'es': ':medalla_de_bronce:',
'fr': ':médaille_de_bronze:',
'ja': ':銅メダル:',
'ko': ':동메달:',
'pt': ':medalha_de_bronze:',
'it': ':medaglia_di_bronzo:',
'fa': ':مدال_برنز:',
'id': ':medali_perunggu:',
'zh': ':铜牌:',
'ru': ':бронзовая_медаль:',
'tr': ':üçüncülük_madalyası:',
'ar': ':ميدالية_مركز_ثالث:',
},
'\U0001f18e': { # 🆎
'en': ':AB_button_(blood_type):',
'status': fully_qualified,
'E': 0.6,
'alias': [':ab:', ':ab_button_blood_type:'],
'de': ':großbuchstaben_ab_in_rotem_quadrat:',
'es': ':grupo_sanguíneo_ab:',
'fr': ':groupe_sanguin_ab:',
'ja': ':血液型ab型:',
'ko': ':에이비형:',
'pt': ':botão_ab_(tipo_sanguíneo):',
'it': ':gruppo_sanguigno_ab:',
'fa': ':دکمه_آ_ب_(گروه_خونی):',
'id': ':tombol_ab_(golongan_darah):',
'zh': ':AB型血:',
'ru': ':IV_группарови:',
'tr': ':ab_düğmesi_(kan_grubu):',
'ar': ':زر_ab_(فئة_الدم):',
},
'\U0001f3e7': { # 🏧
'en': ':ATM_sign:',
'status': fully_qualified,
'E': 0.6,
'alias': [':atm:', ':atm_sign:'],
'de': ':symbol_geldautomat:',
'es': ':señal_de_cajero_automático:',
'fr': ':distributeur_de_billets:',
'ja': ':atm:',
'ko': ':에이티엠:',
'pt': ':símbolo_de_caixa_automático:',
'it': ':simbolo_dello_sportello_bancomat:',
'fa': ':نشان_عابربانک:',
'id': ':tanda_atm:',
'zh': ':取款机:',
'ru': ':значок_банкомата:',
'tr': ':atm_işareti:',
'ar': ':علامة_ماكينة_صرف_آلي:',
},
'\U0001f170\U0000fe0f': { # 🅰️
'en': ':A_button_(blood_type):',
'status': fully_qualified,
'E': 0.6,
'alias': [':a:', ':a_button_blood_type:'],
'variant': True,
'de': ':großbuchstabe_a_in_rotem_quadrat:',
'es': ':grupo_sanguíneo_a:',
'fr': ':groupe_sanguin_a:',
'ja': ':血液型a型:',
'ko': ':에이형:',
'pt': ':botão_a_(tipo_sanguíneo):',
'it': ':gruppo_sanguigno_a:',
'fa': ':دکمه_آ_(گروه_خونی):',
'id': ':tombol_a_(golongan_darah):',
'zh': ':A型血:',
'ru': ':ii_группарови:',
'tr': ':a_düğmesi_(kan_grubu):',
'ar': ':زر_a:',
},
'\U0001f170': { # 🅰
'en': ':A_button_(blood_type):',
'status': unqualified,
'E': 0.6,
'alias': [':a:', ':a_button_blood_type:'],
'variant': True,
'de': ':großbuchstabe_a_in_rotem_quadrat:',
'es': ':grupo_sanguíneo_a:',
'fr': ':groupe_sanguin_a:',
'ja': ':血液型a型:',
'ko': ':에이형:',
'pt': ':botão_a_(tipo_sanguíneo):',
'it': ':gruppo_sanguigno_a:',
'fa': ':دکمه_آ_(گروه_خونی):',
'id': ':tombol_a_(golongan_darah):',
'zh': ':A型血:',
'ru': ':II_группарови:',
'tr': ':a_düğmesi_(kan_grubu):',
'ar': ':زر_a:',
},
'\U0001f1e6\U0001f1eb': { # 🇦🇫
'en': ':Afghanistan:',
'status': fully_qualified,
'E': 2,
'alias': [':flag_for_Afghanistan:', ':afghanistan:'],
'de': ':flagge_afghanistan:',
'es': ':bandera_afganistán:',
'fr': ':drapeau_afghanistan:',
'ja': ':旗_アフガニスタン:',
'ko': ':깃발_아프가니스탄:',
'pt': ':bandeira_afeganistão:',
'it': ':bandiera_afghanistan:',
'fa': ':پرچم_افغانستان:',
'id': ':bendera_afganistan:',
'zh': ':阿富汗:',
'ru': ':флаг_Афганистан:',
'tr': ':bayrak_afganistan:',
'ar': ':علم_أفغانستان:',
},
'\U0001f1e6\U0001f1f1': { # 🇦🇱
'en': ':Albania:',
'status': fully_qualified,
'E': 2,
'alias': [':flag_for_Albania:', ':albania:'],
'de': ':flagge_albanien:',
'es': ':bandera_albania:',
'fr': ':drapeau_albanie:',
'ja': ':旗_アルバニア:',
'ko': ':깃발_알바니아:',
'pt': ':bandeira_albânia:',
'it': ':bandiera_albania:',
'fa': ':پرچم_آلبانی:',
'id': ':bendera_albania:',
'zh': ':阿尔巴尼亚:',
'ru': ':флаг_Албания:',
'tr': ':bayrak_arnavutluk:',
'ar': ':علم_ألبانيا:',
},
'\U0001f1e9\U0001f1ff': { # 🇩🇿
'en': ':Algeria:',
'status': fully_qualified,
'E': 2,
'alias': [':flag_for_Algeria:', ':algeria:'],
'de': ':flagge_algerien:',
'es': ':bandera_argelia:',
'fr': ':drapeau_algérie:',
'ja': ':旗_アルジェリア:',
'ko': ':깃발_알제리:',
'pt': ':bandeira_argélia:',
'it': ':bandiera_algeria:',
'fa': ':پرچم_الجزایر:',
'id': ':bendera_aljazair:',
'zh': ':阿尔及利亚:',
'ru': ':флаг_Алжир:',
'tr': ':bayrak_cezayir:',
'ar': ':علم_الجزائر:',
},
'\U0001f1e6\U0001f1f8': { # 🇦🇸
'en': ':American_Samoa:',
'status': fully_qualified,
'E': 2,
'alias': [':flag_for_American_Samoa:', ':american_samoa:'],
'de': ':flagge_amerikanisch-samoa:',
'es': ':bandera_samoa_americana:',
'fr': ':drapeau_samoa_américaines:',
'ja': ':旗_米領サモア:',
'ko': ':깃발_아메리칸_사모아:',
'pt': ':bandeira_samoa_americana:',
'it': ':bandiera_samoa_americane:',
'fa': ':پرچم_ساموآی_امریکا:',
'id': ':bendera_samoa_amerika:',
'zh': ':美属萨摩亚:',
'ru': ':флаг_Американское_Самоа:',
'tr': ':bayrak_amerikan_samoası:',
'ar': ':علم_ساموا_الأمريكية:',
},
}

File diff suppressed because it is too large Load Diff

View File

@ -1,25 +0,0 @@
BSD 2-Clause License
Copyright (c) 2018-2020, Ewald de Wit
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,87 +0,0 @@
Metadata-Version: 2.1
Name: nest-asyncio
Version: 1.6.0
Summary: Patch asyncio to allow nested event loops
Home-page: https://github.com/erdewit/nest_asyncio
Author: Ewald R. de Wit
Author-email: ewald.de.wit@gmail.com
License: BSD
Keywords: asyncio,nested,eventloop
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Programming Language :: Python :: 3.5
Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Framework :: AsyncIO
Requires-Python: >=3.5
Description-Content-Type: text/x-rst
License-File: LICENSE
|Build| |Status| |PyPiVersion| |License| |Downloads|
Introduction
------------
By design asyncio `does not allow <https://github.com/python/cpython/issues/66435>`_
its event loop to be nested. This presents a practical problem:
When in an environment where the event loop is
already running it's impossible to run tasks and wait
for the result. Trying to do so will give the error
"``RuntimeError: This event loop is already running``".
The issue pops up in various environments, such as web servers,
GUI applications and in Jupyter notebooks.
This module patches asyncio to allow nested use of ``asyncio.run`` and
``loop.run_until_complete``.
Installation
------------
.. code-block::
pip3 install nest_asyncio
Python 3.5 or higher is required.
Usage
-----
.. code-block:: python
import nest_asyncio
nest_asyncio.apply()
Optionally the specific loop that needs patching can be given
as argument to ``apply``, otherwise the current event loop is used.
An event loop can be patched whether it is already running
or not. Only event loops from asyncio can be patched;
Loops from other projects, such as uvloop or quamash,
generally can't be patched.
.. |Build| image:: https://github.com/erdewit/nest_asyncio/actions/workflows/test.yml/badge.svg?branche=master
:alt: Build
:target: https://github.com/erdewit/nest_asyncio/actions
.. |PyPiVersion| image:: https://img.shields.io/pypi/v/nest_asyncio.svg
:alt: PyPi
:target: https://pypi.python.org/pypi/nest_asyncio
.. |Status| image:: https://img.shields.io/badge/status-stable-green.svg
:alt:
.. |License| image:: https://img.shields.io/badge/license-BSD-blue.svg
:alt:
.. |Downloads| image:: https://static.pepy.tech/badge/nest-asyncio/month
:alt: Number of downloads
:target: https://pepy.tech/project/nest-asyncio

View File

@ -1,9 +0,0 @@
__pycache__/nest_asyncio.cpython-312.pyc,,
nest_asyncio-1.6.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
nest_asyncio-1.6.0.dist-info/LICENSE,sha256=vs6faGVf8jt3QTJGwGUDhrh9p8NoIwPdDujj6nYw6Fs,1322
nest_asyncio-1.6.0.dist-info/METADATA,sha256=f3uY-eGiipWX1w35FYF1oi0FRGzksyiQjZIOcpPTW9I,2812
nest_asyncio-1.6.0.dist-info/RECORD,,
nest_asyncio-1.6.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
nest_asyncio-1.6.0.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
nest_asyncio-1.6.0.dist-info/top_level.txt,sha256=cQFBM_fPbDdhVVihWwS-29WiW17LZ3r4lSXyvwFzNzs,13
nest_asyncio.py,sha256=KkW14bq07D5BoOTpkjlwv8dFX5uRw9Z84TR_u5wR7_o,7490

View File

@ -1,5 +0,0 @@
Wheel-Version: 1.0
Generator: bdist_wheel (0.40.0)
Root-Is-Purelib: true
Tag: py3-none-any

View File

@ -1,219 +0,0 @@
"""Patch asyncio to allow nested event loops."""
import asyncio
import asyncio.events as events
import os
import sys
import threading
from contextlib import contextmanager, suppress
from heapq import heappop
def apply(loop=None):
"""Patch asyncio to make its event loop reentrant."""
_patch_asyncio()
_patch_policy()
_patch_tornado()
loop = loop or asyncio.get_event_loop()
_patch_loop(loop)
def _patch_asyncio():
"""Patch asyncio module to use pure Python tasks and futures."""
def run(main, *, debug=False):
loop = asyncio.get_event_loop()
loop.set_debug(debug)
task = asyncio.ensure_future(main)
try:
return loop.run_until_complete(task)
finally:
if not task.done():
task.cancel()
with suppress(asyncio.CancelledError):
loop.run_until_complete(task)
def _get_event_loop(stacklevel=3):
loop = events._get_running_loop()
if loop is None:
loop = events.get_event_loop_policy().get_event_loop()
return loop
# Use module level _current_tasks, all_tasks and patch run method.
if hasattr(asyncio, '_nest_patched'):
return
if sys.version_info >= (3, 6, 0):
asyncio.Task = asyncio.tasks._CTask = asyncio.tasks.Task = \
asyncio.tasks._PyTask
asyncio.Future = asyncio.futures._CFuture = asyncio.futures.Future = \
asyncio.futures._PyFuture
if sys.version_info < (3, 7, 0):
asyncio.tasks._current_tasks = asyncio.tasks.Task._current_tasks
asyncio.all_tasks = asyncio.tasks.Task.all_tasks
if sys.version_info >= (3, 9, 0):
events._get_event_loop = events.get_event_loop = \
asyncio.get_event_loop = _get_event_loop
asyncio.run = run
asyncio._nest_patched = True
def _patch_policy():
"""Patch the policy to always return a patched loop."""
def get_event_loop(self):
if self._local._loop is None:
loop = self.new_event_loop()
_patch_loop(loop)
self.set_event_loop(loop)
return self._local._loop
policy = events.get_event_loop_policy()
policy.__class__.get_event_loop = get_event_loop
def _patch_loop(loop):
"""Patch loop to make it reentrant."""
def run_forever(self):
with manage_run(self), manage_asyncgens(self):
while True:
self._run_once()
if self._stopping:
break
self._stopping = False
def run_until_complete(self, future):
with manage_run(self):
f = asyncio.ensure_future(future, loop=self)
if f is not future:
f._log_destroy_pending = False
while not f.done():
self._run_once()
if self._stopping:
break
if not f.done():
raise RuntimeError(
'Event loop stopped before Future completed.')
return f.result()
def _run_once(self):
"""
Simplified re-implementation of asyncio's _run_once that
runs handles as they become ready.
"""
ready = self._ready
scheduled = self._scheduled
while scheduled and scheduled[0]._cancelled:
heappop(scheduled)
timeout = (
0 if ready or self._stopping
else min(max(
scheduled[0]._when - self.time(), 0), 86400) if scheduled
else None)
event_list = self._selector.select(timeout)
self._process_events(event_list)
end_time = self.time() + self._clock_resolution
while scheduled and scheduled[0]._when < end_time:
handle = heappop(scheduled)
ready.append(handle)
for _ in range(len(ready)):
if not ready:
break
handle = ready.popleft()
if not handle._cancelled:
# preempt the current task so that that checks in
# Task.__step do not raise
curr_task = curr_tasks.pop(self, None)
try:
handle._run()
finally:
# restore the current task
if curr_task is not None:
curr_tasks[self] = curr_task
handle = None
@contextmanager
def manage_run(self):
"""Set up the loop for running."""
self._check_closed()
old_thread_id = self._thread_id
old_running_loop = events._get_running_loop()
try:
self._thread_id = threading.get_ident()
events._set_running_loop(self)
self._num_runs_pending += 1
if self._is_proactorloop:
if self._self_reading_future is None:
self.call_soon(self._loop_self_reading)
yield
finally:
self._thread_id = old_thread_id
events._set_running_loop(old_running_loop)
self._num_runs_pending -= 1
if self._is_proactorloop:
if (self._num_runs_pending == 0
and self._self_reading_future is not None):
ov = self._self_reading_future._ov
self._self_reading_future.cancel()
if ov is not None:
self._proactor._unregister(ov)
self._self_reading_future = None
@contextmanager
def manage_asyncgens(self):
if not hasattr(sys, 'get_asyncgen_hooks'):
# Python version is too old.
return
old_agen_hooks = sys.get_asyncgen_hooks()
try:
self._set_coroutine_origin_tracking(self._debug)
if self._asyncgens is not None:
sys.set_asyncgen_hooks(
firstiter=self._asyncgen_firstiter_hook,
finalizer=self._asyncgen_finalizer_hook)
yield
finally:
self._set_coroutine_origin_tracking(False)
if self._asyncgens is not None:
sys.set_asyncgen_hooks(*old_agen_hooks)
def _check_running(self):
"""Do not throw exception if loop is already running."""
pass
if hasattr(loop, '_nest_patched'):
return
if not isinstance(loop, asyncio.BaseEventLoop):
raise ValueError('Can\'t patch loop of type %s' % type(loop))
cls = loop.__class__
cls.run_forever = run_forever
cls.run_until_complete = run_until_complete
cls._run_once = _run_once
cls._check_running = _check_running
cls._check_runnung = _check_running # typo in Python 3.7 source
cls._num_runs_pending = 1 if loop.is_running() else 0
cls._is_proactorloop = (
os.name == 'nt' and issubclass(cls, asyncio.ProactorEventLoop))
if sys.version_info < (3, 7, 0):
cls._set_coroutine_origin_tracking = cls._set_coroutine_wrapper
curr_tasks = asyncio.tasks._current_tasks \
if sys.version_info >= (3, 7, 0) else asyncio.Task._current_tasks
cls._nest_patched = True
def _patch_tornado():
"""
If tornado is imported before nest_asyncio, make tornado aware of
the pure-Python asyncio Future.
"""
if 'tornado' in sys.modules:
import tornado.concurrent as tc # type: ignore
tc.Future = asyncio.Future
if asyncio.Future not in tc.FUTURES:
tc.FUTURES += (asyncio.Future,)

View File

@ -1,806 +0,0 @@
@Switch01
A_Rog
Aakanksha Agrawal
Abhinav Sagar
ABHYUDAY PRATAP SINGH
abs51295
AceGentile
Adam Chainz
Adam Tse
Adam Wentz
admin
Adolfo Ochagavía
Adrien Morison
Agus
ahayrapetyan
Ahilya
AinsworthK
Akash Srivastava
Alan Yee
Albert Tugushev
Albert-Guan
albertg
Alberto Sottile
Aleks Bunin
Ales Erjavec
Alethea Flowers
Alex Gaynor
Alex Grönholm
Alex Hedges
Alex Loosley
Alex Morega
Alex Stachowiak
Alexander Shtyrov
Alexandre Conrad
Alexey Popravka
Aleš Erjavec
Alli
Ami Fischman
Ananya Maiti
Anatoly Techtonik
Anders Kaseorg
Andre Aguiar
Andreas Lutro
Andrei Geacar
Andrew Gaul
Andrew Shymanel
Andrey Bienkowski
Andrey Bulgakov
Andrés Delfino
Andy Freeland
Andy Kluger
Ani Hayrapetyan
Aniruddha Basak
Anish Tambe
Anrs Hu
Anthony Sottile
Antoine Musso
Anton Ovchinnikov
Anton Patrushev
Anton Zelenov
Antonio Alvarado Hernandez
Antony Lee
Antti Kaihola
Anubhav Patel
Anudit Nagar
Anuj Godase
AQNOUCH Mohammed
AraHaan
arena
arenasys
Arindam Choudhury
Armin Ronacher
Arnon Yaari
Artem
Arun Babu Neelicattu
Ashley Manton
Ashwin Ramaswami
atse
Atsushi Odagiri
Avinash Karhana
Avner Cohen
Awit (Ah-Wit) Ghirmai
Baptiste Mispelon
Barney Gale
barneygale
Bartek Ogryczak
Bastian Venthur
Ben Bodenmiller
Ben Darnell
Ben Hoyt
Ben Mares
Ben Rosser
Bence Nagy
Benjamin Peterson
Benjamin VanEvery
Benoit Pierre
Berker Peksag
Bernard
Bernard Tyers
Bernardo B. Marques
Bernhard M. Wiedemann
Bertil Hatt
Bhavam Vidyarthi
Blazej Michalik
Bogdan Opanchuk
BorisZZZ
Brad Erickson
Bradley Ayers
Branch Vincent
Brandon L. Reiss
Brandt Bucher
Brannon Dorsey
Brett Randall
Brett Rosen
Brian Cristante
Brian Rosner
briantracy
BrownTruck
Bruno Oliveira
Bruno Renié
Bruno S
Bstrdsmkr
Buck Golemon
burrows
Bussonnier Matthias
bwoodsend
c22
Caleb Brown
Caleb Martinez
Calvin Smith
Carl Meyer
Carlos Liam
Carol Willing
Carter Thayer
Cass
Chandrasekhar Atina
Charlie Marsh
charwick
Chih-Hsuan Yen
Chris Brinker
Chris Hunt
Chris Jerdonek
Chris Kuehl
Chris Markiewicz
Chris McDonough
Chris Pawley
Chris Pryer
Chris Wolfe
Christian Clauss
Christian Heimes
Christian Oudard
Christoph Reiter
Christopher Hunt
Christopher Snyder
chrysle
cjc7373
Clark Boylan
Claudio Jolowicz
Clay McClure
Cody
Cody Soyland
Colin Watson
Collin Anderson
Connor Osborn
Cooper Lees
Cooper Ry Lees
Cory Benfield
Cory Wright
Craig Kerstiens
Cristian Sorinel
Cristina
Cristina Muñoz
ctg123
Curtis Doty
cytolentino
Daan De Meyer
Dale
Damian
Damian Quiroga
Damian Shaw
Dan Black
Dan Savilonis
Dan Sully
Dane Hillard
daniel
Daniel Collins
Daniel Hahler
Daniel Holth
Daniel Jost
Daniel Katz
Daniel Shaulov
Daniele Esposti
Daniele Nicolodi
Daniele Procida
Daniil Konovalenko
Danny Hermes
Danny McClanahan
Darren Kavanagh
Dav Clark
Dave Abrahams
Dave Jones
David Aguilar
David Black
David Bordeynik
David Caro
David D Lowe
David Evans
David Hewitt
David Linke
David Poggi
David Poznik
David Pursehouse
David Runge
David Tucker
David Wales
Davidovich
ddelange
Deepak Sharma
Deepyaman Datta
Denise Yu
dependabot[bot]
derwolfe
Desetude
Devesh Kumar Singh
devsagul
Diego Caraballo
Diego Ramirez
DiegoCaraballo
Dimitri Merejkowsky
Dimitri Papadopoulos
Dimitri Papadopoulos Orfanos
Dirk Stolle
Dmitry Gladkov
Dmitry Volodin
Domen Kožar
Dominic Davis-Foster
Donald Stufft
Dongweiming
doron zarhi
Dos Moonen
Douglas Thor
DrFeathers
Dustin Ingram
Dustin Rodrigues
Dwayne Bailey
Ed Morley
Edgar Ramírez
Edgar Ramírez Mondragón
Ee Durbin
Efflam Lemaillet
efflamlemaillet
Eitan Adler
ekristina
elainechan
Eli Schwartz
Elisha Hollander
Ellen Marie Dash
Emil Burzo
Emil Styrke
Emmanuel Arias
Endoh Takanao
enoch
Erdinc Mutlu
Eric Cousineau
Eric Gillingham
Eric Hanchrow
Eric Hopper
Erik M. Bray
Erik Rose
Erwin Janssen
Eugene Vereshchagin
everdimension
Federico
Felipe Peter
Felix Yan
fiber-space
Filip Kokosiński
Filipe Laíns
Finn Womack
finnagin
Flavio Amurrio
Florian Briand
Florian Rathgeber
Francesco
Francesco Montesano
Fredrik Orderud
Frost Ming
Gabriel Curio
Gabriel de Perthuis
Garry Polley
gavin
gdanielson
Geoffrey Sneddon
George Song
Georgi Valkov
Georgy Pchelkin
ghost
Giftlin Rajaiah
gizmoguy1
gkdoc
Godefroid Chapelle
Gopinath M
GOTO Hayato
gousaiyang
gpiks
Greg Roodt
Greg Ward
Guilherme Espada
Guillaume Seguin
gutsytechster
Guy Rozendorn
Guy Tuval
gzpan123
Hanjun Kim
Hari Charan
Harsh Vardhan
harupy
Harutaka Kawamura
hauntsaninja
Henrich Hartzer
Henry Schreiner
Herbert Pfennig
Holly Stotelmyer
Honnix
Hsiaoming Yang
Hugo Lopes Tavares
Hugo van Kemenade
Hugues Bruant
Hynek Schlawack
Ian Bicking
Ian Cordasco
Ian Lee
Ian Stapleton Cordasco
Ian Wienand
Igor Kuzmitshov
Igor Sobreira
Ikko Ashimine
Ilan Schnell
Illia Volochii
Ilya Baryshev
Inada Naoki
Ionel Cristian Mărieș
Ionel Maries Cristian
Itamar Turner-Trauring
Ivan Pozdeev
J. Nick Koston
Jacob Kim
Jacob Walls
Jaime Sanz
jakirkham
Jakub Kuczys
Jakub Stasiak
Jakub Vysoky
Jakub Wilk
James Cleveland
James Curtin
James Firth
James Gerity
James Polley
Jan Pokorný
Jannis Leidel
Jarek Potiuk
jarondl
Jason Curtis
Jason R. Coombs
JasonMo
JasonMo1
Jay Graves
Jean Abou Samra
Jean-Christophe Fillion-Robin
Jeff Barber
Jeff Dairiki
Jeff Widman
Jelmer Vernooij
jenix21
Jeremy Fleischman
Jeremy Stanley
Jeremy Zafran
Jesse Rittner
Jiashuo Li
Jim Fisher
Jim Garrison
Jinzhe Zeng
Jiun Bae
Jivan Amara
Joe Bylund
Joe Michelini
John Paton
John Sirois
John T. Wodder II
John-Scott Atlakson
johnthagen
Jon Banafato
Jon Dufresne
Jon Parise
Jonas Nockert
Jonathan Herbert
Joonatan Partanen
Joost Molenaar
Jorge Niedbalski
Joseph Bylund
Joseph Long
Josh Bronson
Josh Cannon
Josh Hansen
Josh Schneier
Joshua
JoshuaPerdue
Juan Luis Cano Rodríguez
Juanjo Bazán
Judah Rand
Julian Berman
Julian Gethmann
Julien Demoor
July Tikhonov
Jussi Kukkonen
Justin van Heek
jwg4
Jyrki Pulliainen
Kai Chen
Kai Mueller
Kamal Bin Mustafa
Karolina Surma
kasium
kaustav haldar
keanemind
Keith Maxwell
Kelsey Hightower
Kenneth Belitzky
Kenneth Reitz
Kevin Burke
Kevin Carter
Kevin Frommelt
Kevin R Patterson
Kexuan Sun
Kit Randel
Klaas van Schelven
KOLANICH
konstin
kpinc
Krishna Oza
Kumar McMillan
Kuntal Majumder
Kurt McKee
Kyle Persohn
lakshmanaram
Laszlo Kiss-Kollar
Laurent Bristiel
Laurent LAPORTE
Laurie O
Laurie Opperman
layday
Leon Sasson
Lev Givon
Lincoln de Sousa
Lipis
lorddavidiii
Loren Carvalho
Lucas Cimon
Ludovic Gasc
Luis Medel
Lukas Geiger
Lukas Juhrich
Luke Macken
Luo Jiebin
luojiebin
luz.paz
László Kiss Kollár
M00nL1ght
Marc Abramowitz
Marc Tamlyn
Marcus Smith
Mariatta
Mark Kohler
Mark McLoughlin
Mark Williams
Markus Hametner
Martey Dodoo
Martin Fischer
Martin Häcker
Martin Pavlasek
Masaki
Masklinn
Matej Stuchlik
Mathew Jennings
Mathieu Bridon
Mathieu Kniewallner
Matt Bacchi
Matt Good
Matt Maker
Matt Robenolt
Matt Wozniski
matthew
Matthew Einhorn
Matthew Feickert
Matthew Gilliard
Matthew Hughes
Matthew Iversen
Matthew Treinish
Matthew Trumbell
Matthew Willson
Matthias Bussonnier
mattip
Maurits van Rees
Max W Chase
Maxim Kurnikov
Maxime Rouyrre
mayeut
mbaluna
mdebi
memoselyk
meowmeowcat
Michael
Michael Aquilina
Michael E. Karpeles
Michael Klich
Michael Mintz
Michael Williamson
michaelpacer
Michał Górny
Mickaël Schoentgen
Miguel Araujo Perez
Mihir Singh
Mike
Mike Hendricks
Min RK
MinRK
Miro Hrončok
Monica Baluna
montefra
Monty Taylor
morotti
mrKazzila
Muha Ajjan
Nadav Wexler
Nahuel Ambrosini
Nate Coraor
Nate Prewitt
Nathan Houghton
Nathaniel J. Smith
Nehal J Wani
Neil Botelho
Nguyễn Gia Phong
Nicholas Serra
Nick Coghlan
Nick Stenning
Nick Timkovich
Nicolas Bock
Nicole Harris
Nikhil Benesch
Nikhil Ladha
Nikita Chepanov
Nikolay Korolev
Nipunn Koorapati
Nitesh Sharma
Niyas Sait
Noah
Noah Gorny
Nowell Strite
NtaleGrey
nvdv
OBITORASU
Ofek Lev
ofrinevo
Oliver Freund
Oliver Jeeves
Oliver Mannion
Oliver Tonnhofer
Olivier Girardot
Olivier Grisel
Ollie Rutherfurd
OMOTO Kenji
Omry Yadan
onlinejudge95
Oren Held
Oscar Benjamin
Oz N Tiram
Pachwenko
Patrick Dubroy
Patrick Jenkins
Patrick Lawson
patricktokeeffe
Patrik Kopkan
Paul Ganssle
Paul Kehrer
Paul Moore
Paul Nasrat
Paul Oswald
Paul van der Linden
Paulus Schoutsen
Pavel Safronov
Pavithra Eswaramoorthy
Pawel Jasinski
Paweł Szramowski
Pekka Klärck
Peter Gessler
Peter Lisák
Peter Shen
Peter Waller
Petr Viktorin
petr-tik
Phaneendra Chiruvella
Phil Elson
Phil Freo
Phil Pennock
Phil Whelan
Philip Jägenstedt
Philip Molloy
Philippe Ombredanne
Pi Delport
Pierre-Yves Rofes
Pieter Degroote
pip
Prabakaran Kumaresshan
Prabhjyotsing Surjit Singh Sodhi
Prabhu Marappan
Pradyun Gedam
Prashant Sharma
Pratik Mallya
pre-commit-ci[bot]
Preet Thakkar
Preston Holmes
Przemek Wrzos
Pulkit Goyal
q0w
Qiangning Hong
Qiming Xu
Quentin Lee
Quentin Pradet
R. David Murray
Rafael Caricio
Ralf Schmitt
Ran Benita
Randy Döring
Razzi Abuissa
rdb
Reece Dunham
Remi Rampin
Rene Dudfield
Riccardo Magliocchetti
Riccardo Schirone
Richard Jones
Richard Si
Ricky Ng-Adam
Rishi
rmorotti
RobberPhex
Robert Collins
Robert McGibbon
Robert Pollak
Robert T. McGibbon
robin elisha robinson
Roey Berman
Rohan Jain
Roman Bogorodskiy
Roman Donchenko
Romuald Brunet
ronaudinho
Ronny Pfannschmidt
Rory McCann
Ross Brattain
Roy Wellington Ⅳ
Ruairidh MacLeod
Russell Keith-Magee
Ryan Shepherd
Ryan Wooden
ryneeverett
S. Guliaev
Sachi King
Salvatore Rinchiera
sandeepkiran-js
Sander Van Balen
Savio Jomton
schlamar
Scott Kitterman
Sean
seanj
Sebastian Jordan
Sebastian Schaetz
Segev Finer
SeongSoo Cho
Sergey Vasilyev
Seth Michael Larson
Seth Woodworth
Shahar Epstein
Shantanu
shenxianpeng
shireenrao
Shivansh-007
Shixian Sheng
Shlomi Fish
Shovan Maity
Simeon Visser
Simon Cross
Simon Pichugin
sinoroc
sinscary
snook92
socketubs
Sorin Sbarnea
Srinivas Nyayapati
Srishti Hegde
Stavros Korokithakis
Stefan Scherfke
Stefano Rivera
Stephan Erb
Stephen Rosen
stepshal
Steve (Gadget) Barnes
Steve Barnes
Steve Dower
Steve Kowalik
Steven Myint
Steven Silvester
stonebig
studioj
Stéphane Bidoul
Stéphane Bidoul (ACSONE)
Stéphane Klein
Sumana Harihareswara
Surbhi Sharma
Sviatoslav Sydorenko
Sviatoslav Sydorenko (Святослав Сидоренко)
Swat009
Sylvain
Takayuki SHIMIZUKAWA
Taneli Hukkinen
tbeswick
Thiago
Thijs Triemstra
Thomas Fenzl
Thomas Grainger
Thomas Guettler
Thomas Johansson
Thomas Kluyver
Thomas Smith
Thomas VINCENT
Tim D. Smith
Tim Gates
Tim Harder
Tim Heap
tim smith
tinruufu
Tobias Hermann
Tom Forbes
Tom Freudenheim
Tom V
Tomas Hrnciar
Tomas Orsava
Tomer Chachamu
Tommi Enenkel | AnB
Tomáš Hrnčiar
Tony Beswick
Tony Narlock
Tony Zhaocheng Tan
TonyBeswick
toonarmycaptain
Toshio Kuratomi
toxinu
Travis Swicegood
Tushar Sadhwani
Tzu-ping Chung
Valentin Haenel
Victor Stinner
victorvpaulo
Vikram - Google
Viktor Szépe
Ville Skyttä
Vinay Sajip
Vincent Philippon
Vinicyus Macedo
Vipul Kumar
Vitaly Babiy
Vladimir Fokow
Vladimir Rutsky
W. Trevor King
Wil Tan
Wilfred Hughes
William Edwards
William ML Leslie
William T Olson
William Woodruff
Wilson Mo
wim glenn
Winson Luk
Wolfgang Maier
Wu Zhenyu
XAMES3
Xavier Fernandez
Xianpeng Shen
xoviat
xtreak
YAMAMOTO Takashi
Yen Chi Hsuan
Yeray Diaz Diaz
Yoval P
Yu Jian
Yuan Jing Vincent Yan
Yusuke Hayashi
Zearin
Zhiping Deng
ziebam
Zvezdan Petkovic
Łukasz Langa
Роман Донченко
Семён Марьясин

View File

@ -1,20 +0,0 @@
Copyright (c) 2008-present The pip developers (see AUTHORS.txt file)
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.

View File

@ -1,90 +0,0 @@
Metadata-Version: 2.2
Name: pip
Version: 25.0
Summary: The PyPA recommended tool for installing Python packages.
Author-email: The pip developers <distutils-sig@python.org>
License: MIT
Project-URL: Homepage, https://pip.pypa.io/
Project-URL: Documentation, https://pip.pypa.io
Project-URL: Source, https://github.com/pypa/pip
Project-URL: Changelog, https://pip.pypa.io/en/stable/news/
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Topic :: Software Development :: Build Tools
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
Requires-Python: >=3.8
Description-Content-Type: text/x-rst
License-File: LICENSE.txt
License-File: AUTHORS.txt
pip - The Python Package Installer
==================================
.. |pypi-version| image:: https://img.shields.io/pypi/v/pip.svg
:target: https://pypi.org/project/pip/
:alt: PyPI
.. |python-versions| image:: https://img.shields.io/pypi/pyversions/pip
:target: https://pypi.org/project/pip
:alt: PyPI - Python Version
.. |docs-badge| image:: https://readthedocs.org/projects/pip/badge/?version=latest
:target: https://pip.pypa.io/en/latest
:alt: Documentation
|pypi-version| |python-versions| |docs-badge|
pip is the `package installer`_ for Python. You can use pip to install packages from the `Python Package Index`_ and other indexes.
Please take a look at our documentation for how to install and use pip:
* `Installation`_
* `Usage`_
We release updates regularly, with a new version every 3 months. Find more details in our documentation:
* `Release notes`_
* `Release process`_
If you find bugs, need help, or want to talk to the developers, please use our mailing lists or chat rooms:
* `Issue tracking`_
* `Discourse channel`_
* `User IRC`_
If you want to get involved head over to GitHub to get the source code, look at our development documentation and feel free to jump on the developer mailing lists and chat rooms:
* `GitHub page`_
* `Development documentation`_
* `Development IRC`_
Code of Conduct
---------------
Everyone interacting in the pip project's codebases, issue trackers, chat
rooms, and mailing lists is expected to follow the `PSF Code of Conduct`_.
.. _package installer: https://packaging.python.org/guides/tool-recommendations/
.. _Python Package Index: https://pypi.org
.. _Installation: https://pip.pypa.io/en/stable/installation/
.. _Usage: https://pip.pypa.io/en/stable/
.. _Release notes: https://pip.pypa.io/en/stable/news.html
.. _Release process: https://pip.pypa.io/en/latest/development/release-process/
.. _GitHub page: https://github.com/pypa/pip
.. _Development documentation: https://pip.pypa.io/en/latest/development
.. _Issue tracking: https://github.com/pypa/pip/issues
.. _Discourse channel: https://discuss.python.org/c/packaging
.. _User IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa
.. _Development IRC: https://kiwiirc.com/nextclient/#ircs://irc.libera.chat:+6697/pypa-dev
.. _PSF Code of Conduct: https://github.com/pypa/.github/blob/main/CODE_OF_CONDUCT.md

View File

@ -1,854 +0,0 @@
../../../bin/pip,sha256=7iQ_YKWjZ2jxUlJ6NAt3ABi-f_cxrh9NpXpao4b1-jM,248
../../../bin/pip3,sha256=7iQ_YKWjZ2jxUlJ6NAt3ABi-f_cxrh9NpXpao4b1-jM,248
../../../bin/pip3.12,sha256=7iQ_YKWjZ2jxUlJ6NAt3ABi-f_cxrh9NpXpao4b1-jM,248
pip-25.0.dist-info/AUTHORS.txt,sha256=HqzpBVLfT1lBthqQfiDlVeFkg65hJ7ZQvvWhoq-BAsA,11018
pip-25.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pip-25.0.dist-info/LICENSE.txt,sha256=Y0MApmnUmurmWxLGxIySTFGkzfPR_whtw0VtyLyqIQQ,1093
pip-25.0.dist-info/METADATA,sha256=0zqSx1A3yJWb9n2TnoVwcP_2VnrD9kKT5yhgDQlbxvA,3675
pip-25.0.dist-info/RECORD,,
pip-25.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip-25.0.dist-info/WHEEL,sha256=In9FTNxeP60KnTkGw7wk6mJPYd_dQSjEZmXdBdMCI-8,91
pip-25.0.dist-info/entry_points.txt,sha256=eeIjuzfnfR2PrhbjnbzFU6MnSS70kZLxwaHHq6M-bD0,87
pip-25.0.dist-info/top_level.txt,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pip/__init__.py,sha256=_N_hFrsElYkcpo13D9NxLwDzPF3WgkSXpv4FjKoSa_8,355
pip/__main__.py,sha256=WzbhHXTbSE6gBY19mNN9m4s5o_365LOvTYSgqgbdBhE,854
pip/__pip-runner__.py,sha256=cPPWuJ6NK_k-GzfvlejLFgwzmYUROmpAR6QC3Q-vkXQ,1450
pip/__pycache__/__init__.cpython-312.pyc,,
pip/__pycache__/__main__.cpython-312.pyc,,
pip/__pycache__/__pip-runner__.cpython-312.pyc,,
pip/_internal/__init__.py,sha256=MfcoOluDZ8QMCFYal04IqOJ9q6m2V7a0aOsnI-WOxUo,513
pip/_internal/__pycache__/__init__.cpython-312.pyc,,
pip/_internal/__pycache__/build_env.cpython-312.pyc,,
pip/_internal/__pycache__/cache.cpython-312.pyc,,
pip/_internal/__pycache__/configuration.cpython-312.pyc,,
pip/_internal/__pycache__/exceptions.cpython-312.pyc,,
pip/_internal/__pycache__/main.cpython-312.pyc,,
pip/_internal/__pycache__/pyproject.cpython-312.pyc,,
pip/_internal/__pycache__/self_outdated_check.cpython-312.pyc,,
pip/_internal/__pycache__/wheel_builder.cpython-312.pyc,,
pip/_internal/build_env.py,sha256=FBnRPwsUlI05I1SXoYsq_Zbe1dskPpCSbS4smuVI_Oo,10716
pip/_internal/cache.py,sha256=Jb698p5PNigRtpW5o26wQNkkUv4MnQ94mc471wL63A0,10369
pip/_internal/cli/__init__.py,sha256=FkHBgpxxb-_gd6r1FjnNhfMOzAUYyXoXKJ6abijfcFU,132
pip/_internal/cli/__pycache__/__init__.cpython-312.pyc,,
pip/_internal/cli/__pycache__/autocompletion.cpython-312.pyc,,
pip/_internal/cli/__pycache__/base_command.cpython-312.pyc,,
pip/_internal/cli/__pycache__/cmdoptions.cpython-312.pyc,,
pip/_internal/cli/__pycache__/command_context.cpython-312.pyc,,
pip/_internal/cli/__pycache__/index_command.cpython-312.pyc,,
pip/_internal/cli/__pycache__/main.cpython-312.pyc,,
pip/_internal/cli/__pycache__/main_parser.cpython-312.pyc,,
pip/_internal/cli/__pycache__/parser.cpython-312.pyc,,
pip/_internal/cli/__pycache__/progress_bars.cpython-312.pyc,,
pip/_internal/cli/__pycache__/req_command.cpython-312.pyc,,
pip/_internal/cli/__pycache__/spinners.cpython-312.pyc,,
pip/_internal/cli/__pycache__/status_codes.cpython-312.pyc,,
pip/_internal/cli/autocompletion.py,sha256=Lli3Mr6aDNu7ZkJJFFvwD2-hFxNI6Avz8OwMyS5TVrs,6865
pip/_internal/cli/base_command.py,sha256=NZin6KMzW9NSYzKk4Tc8isb_TQYKR4CKd5j9mSm46PI,8625
pip/_internal/cli/cmdoptions.py,sha256=V3BB22F4_v_RkHaZ5onWnszhbBtjYZvNhbn9M0NO0HI,30116
pip/_internal/cli/command_context.py,sha256=RHgIPwtObh5KhMrd3YZTkl8zbVG-6Okml7YbFX4Ehg0,774
pip/_internal/cli/index_command.py,sha256=i_sgNlPmXC5iHUaY-dmmrHKKTgc5O4hWzisr5Al1rr0,5677
pip/_internal/cli/main.py,sha256=BDZef-bWe9g9Jpr4OVs4dDf-845HJsKw835T7AqEnAc,2817
pip/_internal/cli/main_parser.py,sha256=laDpsuBDl6kyfywp9eMMA9s84jfH2TJJn-vmL0GG90w,4338
pip/_internal/cli/parser.py,sha256=VCMtduzECUV87KaHNu-xJ-wLNL82yT3x16V4XBxOAqI,10825
pip/_internal/cli/progress_bars.py,sha256=9GcgusWtwfqou2zhAQp1XNbQHIDslqyyz9UwLzw7Jgc,2717
pip/_internal/cli/req_command.py,sha256=DqeFhmUMs6o6Ev8qawAcOoYNdAZsfyKS0MZI5jsJYwQ,12250
pip/_internal/cli/spinners.py,sha256=hIJ83GerdFgFCdobIA23Jggetegl_uC4Sp586nzFbPE,5118
pip/_internal/cli/status_codes.py,sha256=sEFHUaUJbqv8iArL3HAtcztWZmGOFX01hTesSytDEh0,116
pip/_internal/commands/__init__.py,sha256=5oRO9O3dM2vGuh0bFw4HOVletryrz5HHMmmPWwJrH9U,3882
pip/_internal/commands/__pycache__/__init__.cpython-312.pyc,,
pip/_internal/commands/__pycache__/cache.cpython-312.pyc,,
pip/_internal/commands/__pycache__/check.cpython-312.pyc,,
pip/_internal/commands/__pycache__/completion.cpython-312.pyc,,
pip/_internal/commands/__pycache__/configuration.cpython-312.pyc,,
pip/_internal/commands/__pycache__/debug.cpython-312.pyc,,
pip/_internal/commands/__pycache__/download.cpython-312.pyc,,
pip/_internal/commands/__pycache__/freeze.cpython-312.pyc,,
pip/_internal/commands/__pycache__/hash.cpython-312.pyc,,
pip/_internal/commands/__pycache__/help.cpython-312.pyc,,
pip/_internal/commands/__pycache__/index.cpython-312.pyc,,
pip/_internal/commands/__pycache__/inspect.cpython-312.pyc,,
pip/_internal/commands/__pycache__/install.cpython-312.pyc,,
pip/_internal/commands/__pycache__/list.cpython-312.pyc,,
pip/_internal/commands/__pycache__/search.cpython-312.pyc,,
pip/_internal/commands/__pycache__/show.cpython-312.pyc,,
pip/_internal/commands/__pycache__/uninstall.cpython-312.pyc,,
pip/_internal/commands/__pycache__/wheel.cpython-312.pyc,,
pip/_internal/commands/cache.py,sha256=IOezTicHjGE5sWdBx2nwPVgbjuJHM3s-BZEkpZLemuY,8107
pip/_internal/commands/check.py,sha256=Hr_4eiMd9cgVDgEvjtIdw915NmL7ROIWW8enkr8slPQ,2268
pip/_internal/commands/completion.py,sha256=HT4lD0bgsflHq2IDgYfiEdp7IGGtE7s6MgI3xn0VQEw,4287
pip/_internal/commands/configuration.py,sha256=n98enwp6y0b5G6fiRQjaZo43FlJKYve_daMhN-4BRNc,9766
pip/_internal/commands/debug.py,sha256=DNDRgE9YsKrbYzU0s3VKi8rHtKF4X13CJ_br_8PUXO0,6797
pip/_internal/commands/download.py,sha256=0qB0nys6ZEPsog451lDsjL5Bx7Z97t-B80oFZKhpzKM,5273
pip/_internal/commands/freeze.py,sha256=2Vt72BYTSm9rzue6d8dNzt8idxWK4Db6Hd-anq7GQ80,3203
pip/_internal/commands/hash.py,sha256=EVVOuvGtoPEdFi8SNnmdqlCQrhCxV-kJsdwtdcCnXGQ,1703
pip/_internal/commands/help.py,sha256=gcc6QDkcgHMOuAn5UxaZwAStsRBrnGSn_yxjS57JIoM,1132
pip/_internal/commands/index.py,sha256=RAXxmJwFhVb5S1BYzb5ifX3sn9Na8v2CCVYwSMP8pao,4731
pip/_internal/commands/inspect.py,sha256=PGrY9TRTRCM3y5Ml8Bdk8DEOXquWRfscr4DRo1LOTPc,3189
pip/_internal/commands/install.py,sha256=r3yHQUxvxt7gD5j9n6zRDslAvtx9CT_whLuQJcktp6M,29390
pip/_internal/commands/list.py,sha256=oiIzSjLP6__d7dIS3q0Xb5ywsaOThBWRqMyjjKzkPdM,12769
pip/_internal/commands/search.py,sha256=fWkUQVx_gm8ebbFAlCgqtxKXT9rNahpJ-BI__3HNZpg,5626
pip/_internal/commands/show.py,sha256=0YBhCga3PAd81vT3l7UWflktSpB5-aYqQcJxBVPazVM,7857
pip/_internal/commands/uninstall.py,sha256=7pOR7enK76gimyxQbzxcG1OsyLXL3DvX939xmM8Fvtg,3892
pip/_internal/commands/wheel.py,sha256=eJRhr_qoNNxWAkkdJCNiQM7CXd4E1_YyQhsqJnBPGGg,6414
pip/_internal/configuration.py,sha256=-KOok6jh3hFzXMPQFPJ1_EFjBpAsge-RSreQuLHLmzo,14005
pip/_internal/distributions/__init__.py,sha256=Hq6kt6gXBgjNit5hTTWLAzeCNOKoB-N0pGYSqehrli8,858
pip/_internal/distributions/__pycache__/__init__.cpython-312.pyc,,
pip/_internal/distributions/__pycache__/base.cpython-312.pyc,,
pip/_internal/distributions/__pycache__/installed.cpython-312.pyc,,
pip/_internal/distributions/__pycache__/sdist.cpython-312.pyc,,
pip/_internal/distributions/__pycache__/wheel.cpython-312.pyc,,
pip/_internal/distributions/base.py,sha256=QeB9qvKXDIjLdPBDE5fMgpfGqMMCr-govnuoQnGuiF8,1783
pip/_internal/distributions/installed.py,sha256=QinHFbWAQ8oE0pbD8MFZWkwlnfU1QYTccA1vnhrlYOU,842
pip/_internal/distributions/sdist.py,sha256=PlcP4a6-R6c98XnOM-b6Lkb3rsvh9iG4ok8shaanrzs,6751
pip/_internal/distributions/wheel.py,sha256=THBYfnv7VVt8mYhMYUtH13S1E7FDwtDyDfmUcl8ai0E,1317
pip/_internal/exceptions.py,sha256=2_byISIv3kSnI_9T-Esfxrt0LnTRgcUHyxu0twsHjQY,26481
pip/_internal/index/__init__.py,sha256=vpt-JeTZefh8a-FC22ZeBSXFVbuBcXSGiILhQZJaNpQ,30
pip/_internal/index/__pycache__/__init__.cpython-312.pyc,,
pip/_internal/index/__pycache__/collector.cpython-312.pyc,,
pip/_internal/index/__pycache__/package_finder.cpython-312.pyc,,
pip/_internal/index/__pycache__/sources.cpython-312.pyc,,
pip/_internal/index/collector.py,sha256=RdPO0JLAlmyBWPAWYHPyRoGjz3GNAeTngCNkbGey_mE,16265
pip/_internal/index/package_finder.py,sha256=mJHAljlHeHuclyuxtjvBZO6DtovKjsZjF_tCh_wux5E,38076
pip/_internal/index/sources.py,sha256=lPBLK5Xiy8Q6IQMio26Wl7ocfZOKkgGklIBNyUJ23fI,8632
pip/_internal/locations/__init__.py,sha256=UaAxeZ_f93FyouuFf4p7SXYF-4WstXuEvd3LbmPCAno,14925
pip/_internal/locations/__pycache__/__init__.cpython-312.pyc,,
pip/_internal/locations/__pycache__/_distutils.cpython-312.pyc,,
pip/_internal/locations/__pycache__/_sysconfig.cpython-312.pyc,,
pip/_internal/locations/__pycache__/base.cpython-312.pyc,,
pip/_internal/locations/_distutils.py,sha256=x6nyVLj7X11Y4khIdf-mFlxMl2FWadtVEgeb8upc_WI,6013
pip/_internal/locations/_sysconfig.py,sha256=IGzds60qsFneRogC-oeBaY7bEh3lPt_v47kMJChQXsU,7724
pip/_internal/locations/base.py,sha256=RQiPi1d4FVM2Bxk04dQhXZ2PqkeljEL2fZZ9SYqIQ78,2556
pip/_internal/main.py,sha256=r-UnUe8HLo5XFJz8inTcOOTiu_sxNhgHb6VwlGUllOI,340
pip/_internal/metadata/__init__.py,sha256=CU8jK1TZso7jOLdr0sX9xDjrcs5iy8d7IRK-hvaIO5Y,4337
pip/_internal/metadata/__pycache__/__init__.cpython-312.pyc,,
pip/_internal/metadata/__pycache__/_json.cpython-312.pyc,,
pip/_internal/metadata/__pycache__/base.cpython-312.pyc,,
pip/_internal/metadata/__pycache__/pkg_resources.cpython-312.pyc,,
pip/_internal/metadata/_json.py,sha256=ezrIYazHCINM2QUk1eA9wEAMj3aeGWeDVgGalgUzKpc,2707
pip/_internal/metadata/base.py,sha256=ft0K5XNgI4ETqZnRv2-CtvgYiMOMAeGMAzxT-f6VLJA,25298
pip/_internal/metadata/importlib/__init__.py,sha256=jUUidoxnHcfITHHaAWG1G2i5fdBYklv_uJcjo2x7VYE,135
pip/_internal/metadata/importlib/__pycache__/__init__.cpython-312.pyc,,
pip/_internal/metadata/importlib/__pycache__/_compat.cpython-312.pyc,,
pip/_internal/metadata/importlib/__pycache__/_dists.cpython-312.pyc,,
pip/_internal/metadata/importlib/__pycache__/_envs.cpython-312.pyc,,
pip/_internal/metadata/importlib/_compat.py,sha256=c6av8sP8BBjAZuFSJow1iWfygUXNM3xRTCn5nqw6B9M,2796
pip/_internal/metadata/importlib/_dists.py,sha256=oAYCd-ZyY-aZgDXo06qk-BOd6vXyg75g47WaLlAqdH0,8260
pip/_internal/metadata/importlib/_envs.py,sha256=UUB980XSrDWrMpQ1_G45i0r8Hqlg_tg3IPQ63mEqbNc,7431
pip/_internal/metadata/pkg_resources.py,sha256=U07ETAINSGeSRBfWUG93E4tZZbaW_f7PGzEqZN0hulc,10542
pip/_internal/models/__init__.py,sha256=3DHUd_qxpPozfzouoqa9g9ts1Czr5qaHfFxbnxriepM,63
pip/_internal/models/__pycache__/__init__.cpython-312.pyc,,
pip/_internal/models/__pycache__/candidate.cpython-312.pyc,,
pip/_internal/models/__pycache__/direct_url.cpython-312.pyc,,
pip/_internal/models/__pycache__/format_control.cpython-312.pyc,,
pip/_internal/models/__pycache__/index.cpython-312.pyc,,
pip/_internal/models/__pycache__/installation_report.cpython-312.pyc,,
pip/_internal/models/__pycache__/link.cpython-312.pyc,,
pip/_internal/models/__pycache__/scheme.cpython-312.pyc,,
pip/_internal/models/__pycache__/search_scope.cpython-312.pyc,,
pip/_internal/models/__pycache__/selection_prefs.cpython-312.pyc,,
pip/_internal/models/__pycache__/target_python.cpython-312.pyc,,
pip/_internal/models/__pycache__/wheel.cpython-312.pyc,,
pip/_internal/models/candidate.py,sha256=zzgFRuw_kWPjKpGw7LC0ZUMD2CQ2EberUIYs8izjdCA,753
pip/_internal/models/direct_url.py,sha256=uBtY2HHd3TO9cKQJWh0ThvE5FRr-MWRYChRU4IG9HZE,6578
pip/_internal/models/format_control.py,sha256=wtsQqSK9HaUiNxQEuB-C62eVimw6G4_VQFxV9-_KDBE,2486
pip/_internal/models/index.py,sha256=tYnL8oxGi4aSNWur0mG8DAP7rC6yuha_MwJO8xw0crI,1030
pip/_internal/models/installation_report.py,sha256=zRVZoaz-2vsrezj_H3hLOhMZCK9c7TbzWgC-jOalD00,2818
pip/_internal/models/link.py,sha256=GQ8hq7x-FDFPv25Nbn2veIM-MlBrGZDGLd7aZeF4Xrg,21448
pip/_internal/models/scheme.py,sha256=PakmHJM3e8OOWSZFtfz1Az7f1meONJnkGuQxFlt3wBE,575
pip/_internal/models/search_scope.py,sha256=67NEnsYY84784S-MM7ekQuo9KXLH-7MzFntXjapvAo0,4531
pip/_internal/models/selection_prefs.py,sha256=qaFfDs3ciqoXPg6xx45N1jPLqccLJw4N0s4P0PyHTQ8,2015
pip/_internal/models/target_python.py,sha256=2XaH2rZ5ZF-K5wcJbEMGEl7SqrTToDDNkrtQ2v_v_-Q,4271
pip/_internal/models/wheel.py,sha256=G7dND_s4ebPkEL7RJ1qCY0QhUUWIIK6AnjWgRATF5no,4539
pip/_internal/network/__init__.py,sha256=jf6Tt5nV_7zkARBrKojIXItgejvoegVJVKUbhAa5Ioc,50
pip/_internal/network/__pycache__/__init__.cpython-312.pyc,,
pip/_internal/network/__pycache__/auth.cpython-312.pyc,,
pip/_internal/network/__pycache__/cache.cpython-312.pyc,,
pip/_internal/network/__pycache__/download.cpython-312.pyc,,
pip/_internal/network/__pycache__/lazy_wheel.cpython-312.pyc,,
pip/_internal/network/__pycache__/session.cpython-312.pyc,,
pip/_internal/network/__pycache__/utils.cpython-312.pyc,,
pip/_internal/network/__pycache__/xmlrpc.cpython-312.pyc,,
pip/_internal/network/auth.py,sha256=D4gASjUrqoDFlSt6gQ767KAAjv6PUyJU0puDlhXNVRE,20809
pip/_internal/network/cache.py,sha256=0yGMA3Eet59xBSLtbPAenvI53dl29oUOeqZ2c0QL2Ss,4614
pip/_internal/network/download.py,sha256=FLOP29dPYECBiAi7eEjvAbNkyzaKNqbyjOT2m8HPW8U,6048
pip/_internal/network/lazy_wheel.py,sha256=PBdoMoNQQIA84Fhgne38jWF52W4x_KtsHjxgv4dkRKA,7622
pip/_internal/network/session.py,sha256=msM4es16LmmNEYNkrYyg8fTc7gAHbKFltawfKP27LOI,18771
pip/_internal/network/utils.py,sha256=Inaxel-NxBu4PQWkjyErdnfewsFCcgHph7dzR1-FboY,4088
pip/_internal/network/xmlrpc.py,sha256=sAxzOacJ-N1NXGPvap9jC3zuYWSnnv3GXtgR2-E2APA,1838
pip/_internal/operations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_internal/operations/__pycache__/__init__.cpython-312.pyc,,
pip/_internal/operations/__pycache__/check.cpython-312.pyc,,
pip/_internal/operations/__pycache__/freeze.cpython-312.pyc,,
pip/_internal/operations/__pycache__/prepare.cpython-312.pyc,,
pip/_internal/operations/build/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_internal/operations/build/__pycache__/__init__.cpython-312.pyc,,
pip/_internal/operations/build/__pycache__/build_tracker.cpython-312.pyc,,
pip/_internal/operations/build/__pycache__/metadata.cpython-312.pyc,,
pip/_internal/operations/build/__pycache__/metadata_editable.cpython-312.pyc,,
pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-312.pyc,,
pip/_internal/operations/build/__pycache__/wheel.cpython-312.pyc,,
pip/_internal/operations/build/__pycache__/wheel_editable.cpython-312.pyc,,
pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-312.pyc,,
pip/_internal/operations/build/build_tracker.py,sha256=-ARW_TcjHCOX7D2NUOGntB4Fgc6b4aolsXkAK6BWL7w,4774
pip/_internal/operations/build/metadata.py,sha256=9S0CUD8U3QqZeXp-Zyt8HxwU90lE4QrnYDgrqZDzBnc,1422
pip/_internal/operations/build/metadata_editable.py,sha256=xlAwcP9q_8_fmv_3I39w9EZ7SQV9hnJZr9VuTsq2Y68,1510
pip/_internal/operations/build/metadata_legacy.py,sha256=8i6i1QZX9m_lKPStEFsHKM0MT4a-CD408JOw99daLmo,2190
pip/_internal/operations/build/wheel.py,sha256=sT12FBLAxDC6wyrDorh8kvcZ1jG5qInCRWzzP-UkJiQ,1075
pip/_internal/operations/build/wheel_editable.py,sha256=yOtoH6zpAkoKYEUtr8FhzrYnkNHQaQBjWQ2HYae1MQg,1417
pip/_internal/operations/build/wheel_legacy.py,sha256=K-6kNhmj-1xDF45ny1yheMerF0ui4EoQCLzEoHh6-tc,3045
pip/_internal/operations/check.py,sha256=L24vRL8VWbyywdoeAhM89WCd8zLTnjIbULlKelUgIec,5912
pip/_internal/operations/freeze.py,sha256=1_M79jAQKnCxWr-KCCmHuVXOVFGaUJHmoWLfFzgh7K4,9843
pip/_internal/operations/install/__init__.py,sha256=mX7hyD2GNBO2mFGokDQ30r_GXv7Y_PLdtxcUv144e-s,51
pip/_internal/operations/install/__pycache__/__init__.cpython-312.pyc,,
pip/_internal/operations/install/__pycache__/editable_legacy.cpython-312.pyc,,
pip/_internal/operations/install/__pycache__/wheel.cpython-312.pyc,,
pip/_internal/operations/install/editable_legacy.py,sha256=PoEsNEPGbIZ2yQphPsmYTKLOCMs4gv5OcCdzW124NcA,1283
pip/_internal/operations/install/wheel.py,sha256=X5Iz9yUg5LlK5VNQ9g2ikc6dcRu8EPi_SUi5iuEDRgo,27615
pip/_internal/operations/prepare.py,sha256=joWJwPkuqGscQgVNImLK71e9hRapwKvRCM8HclysmvU,28118
pip/_internal/pyproject.py,sha256=GLJ6rWRS5_2noKdajohoLyDty57Z7QXhcUAYghmTnWc,7286
pip/_internal/req/__init__.py,sha256=HxBFtZy_BbCclLgr26waMtpzYdO5T3vxePvpGAXSt5s,2653
pip/_internal/req/__pycache__/__init__.cpython-312.pyc,,
pip/_internal/req/__pycache__/constructors.cpython-312.pyc,,
pip/_internal/req/__pycache__/req_file.cpython-312.pyc,,
pip/_internal/req/__pycache__/req_install.cpython-312.pyc,,
pip/_internal/req/__pycache__/req_set.cpython-312.pyc,,
pip/_internal/req/__pycache__/req_uninstall.cpython-312.pyc,,
pip/_internal/req/constructors.py,sha256=v1qzCN1mIldwx-nCrPc8JO4lxkm3Fv8M5RWvt8LISjc,18430
pip/_internal/req/req_file.py,sha256=eys82McgaICOGic2UZRHjD720piKJPwmeSYdXlWwl6w,20234
pip/_internal/req/req_install.py,sha256=BMptxHYg2uG_b-7HFEULPb3nuw0FMAbuea8zTq2rE7w,35786
pip/_internal/req/req_set.py,sha256=j3esG0s6SzoVReX9rWn4rpYNtyET_fwxbwJPRimvRxo,2858
pip/_internal/req/req_uninstall.py,sha256=qzDIxJo-OETWqGais7tSMCDcWbATYABT-Tid3ityF0s,23853
pip/_internal/resolution/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_internal/resolution/__pycache__/__init__.cpython-312.pyc,,
pip/_internal/resolution/__pycache__/base.cpython-312.pyc,,
pip/_internal/resolution/base.py,sha256=qlmh325SBVfvG6Me9gc5Nsh5sdwHBwzHBq6aEXtKsLA,583
pip/_internal/resolution/legacy/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_internal/resolution/legacy/__pycache__/__init__.cpython-312.pyc,,
pip/_internal/resolution/legacy/__pycache__/resolver.cpython-312.pyc,,
pip/_internal/resolution/legacy/resolver.py,sha256=3HZiJBRd1FTN6jQpI4qRO8-TbLYeIbUTS6PFvXnXs2w,24068
pip/_internal/resolution/resolvelib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-312.pyc,,
pip/_internal/resolution/resolvelib/__pycache__/base.cpython-312.pyc,,
pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-312.pyc,,
pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-312.pyc,,
pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-312.pyc,,
pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-312.pyc,,
pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-312.pyc,,
pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-312.pyc,,
pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-312.pyc,,
pip/_internal/resolution/resolvelib/base.py,sha256=DCf669FsqyQY5uqXeePDHQY1e4QO-pBzWH8O0s9-K94,5023
pip/_internal/resolution/resolvelib/candidates.py,sha256=5UZ1upNnmqsP-nmEZaDYxaBgCoejw_e2WVGmmAvBxXc,20001
pip/_internal/resolution/resolvelib/factory.py,sha256=MJOLSZJY8_28PPdcutoQ6gjJ_1eBDt6Z1edtfTJyR4E,32659
pip/_internal/resolution/resolvelib/found_candidates.py,sha256=9hrTyQqFvl9I7Tji79F1AxHv39Qh1rkJ_7deSHSMfQc,6383
pip/_internal/resolution/resolvelib/provider.py,sha256=bcsFnYvlmtB80cwVdW1fIwgol8ZNr1f1VHyRTkz47SM,9935
pip/_internal/resolution/resolvelib/reporter.py,sha256=00JtoXEkTlw0-rl_sl54d71avwOsJHt9GGHcrj5Sza0,3168
pip/_internal/resolution/resolvelib/requirements.py,sha256=7JG4Z72e5Yk4vU0S5ulGvbqTy4FMQGYhY5zQhX9zTtY,8065
pip/_internal/resolution/resolvelib/resolver.py,sha256=nLJOsVMEVi2gQUVJoUFKMZAeu2f7GRMjGMvNSWyz0Bc,12592
pip/_internal/self_outdated_check.py,sha256=1PFtttvLAeyCVR3tPoBq2sOlPD0IJ-KSqU6bc1HUk9c,8318
pip/_internal/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_internal/utils/__pycache__/__init__.cpython-312.pyc,,
pip/_internal/utils/__pycache__/_jaraco_text.cpython-312.pyc,,
pip/_internal/utils/__pycache__/_log.cpython-312.pyc,,
pip/_internal/utils/__pycache__/appdirs.cpython-312.pyc,,
pip/_internal/utils/__pycache__/compat.cpython-312.pyc,,
pip/_internal/utils/__pycache__/compatibility_tags.cpython-312.pyc,,
pip/_internal/utils/__pycache__/datetime.cpython-312.pyc,,
pip/_internal/utils/__pycache__/deprecation.cpython-312.pyc,,
pip/_internal/utils/__pycache__/direct_url_helpers.cpython-312.pyc,,
pip/_internal/utils/__pycache__/egg_link.cpython-312.pyc,,
pip/_internal/utils/__pycache__/entrypoints.cpython-312.pyc,,
pip/_internal/utils/__pycache__/filesystem.cpython-312.pyc,,
pip/_internal/utils/__pycache__/filetypes.cpython-312.pyc,,
pip/_internal/utils/__pycache__/glibc.cpython-312.pyc,,
pip/_internal/utils/__pycache__/hashes.cpython-312.pyc,,
pip/_internal/utils/__pycache__/logging.cpython-312.pyc,,
pip/_internal/utils/__pycache__/misc.cpython-312.pyc,,
pip/_internal/utils/__pycache__/packaging.cpython-312.pyc,,
pip/_internal/utils/__pycache__/retry.cpython-312.pyc,,
pip/_internal/utils/__pycache__/setuptools_build.cpython-312.pyc,,
pip/_internal/utils/__pycache__/subprocess.cpython-312.pyc,,
pip/_internal/utils/__pycache__/temp_dir.cpython-312.pyc,,
pip/_internal/utils/__pycache__/unpacking.cpython-312.pyc,,
pip/_internal/utils/__pycache__/urls.cpython-312.pyc,,
pip/_internal/utils/__pycache__/virtualenv.cpython-312.pyc,,
pip/_internal/utils/__pycache__/wheel.cpython-312.pyc,,
pip/_internal/utils/_jaraco_text.py,sha256=M15uUPIh5NpP1tdUGBxRau6q1ZAEtI8-XyLEETscFfE,3350
pip/_internal/utils/_log.py,sha256=-jHLOE_THaZz5BFcCnoSL9EYAtJ0nXem49s9of4jvKw,1015
pip/_internal/utils/appdirs.py,sha256=swgcTKOm3daLeXTW6v5BUS2Ti2RvEnGRQYH_yDXklAo,1665
pip/_internal/utils/compat.py,sha256=ckkFveBiYQjRWjkNsajt_oWPS57tJvE8XxoC4OIYgCY,2399
pip/_internal/utils/compatibility_tags.py,sha256=OWq5axHpW-MEEPztGdvgADrgJPAcV9a88Rxm4Z8VBs8,6272
pip/_internal/utils/datetime.py,sha256=m21Y3wAtQc-ji6Veb6k_M5g6A0ZyFI4egchTdnwh-pQ,242
pip/_internal/utils/deprecation.py,sha256=k7Qg_UBAaaTdyq82YVARA6D7RmcGTXGv7fnfcgigj4Q,3707
pip/_internal/utils/direct_url_helpers.py,sha256=r2MRtkVDACv9AGqYODBUC9CjwgtsUU1s68hmgfCJMtA,3196
pip/_internal/utils/egg_link.py,sha256=0FePZoUYKv4RGQ2t6x7w5Z427wbA_Uo3WZnAkrgsuqo,2463
pip/_internal/utils/entrypoints.py,sha256=YlhLTRl2oHBAuqhc-zmL7USS67TPWVHImjeAQHreZTQ,3064
pip/_internal/utils/filesystem.py,sha256=ajvA-q4ocliW9kPp8Yquh-4vssXbu-UKbo5FV9V4X64,4950
pip/_internal/utils/filetypes.py,sha256=i8XAQ0eFCog26Fw9yV0Yb1ygAqKYB1w9Cz9n0fj8gZU,716
pip/_internal/utils/glibc.py,sha256=vUkWq_1pJuzcYNcGKLlQmABoUiisK8noYY1yc8Wq4w4,3734
pip/_internal/utils/hashes.py,sha256=XGGLL0AG8-RhWnyz87xF6MFZ--BKadHU35D47eApCKI,4972
pip/_internal/utils/logging.py,sha256=ONfbrhaD248akkosK79if97n20EABxwjOxp5dE5RCRY,11845
pip/_internal/utils/misc.py,sha256=DWnYxBUItjRp7hhxEg4ih6P6YpKrykM86dbi_EcU8SQ,23450
pip/_internal/utils/packaging.py,sha256=cm-X_0HVHV_jRwUVZh6AuEWqSitzf8EpaJ7Uv2UGu6A,2142
pip/_internal/utils/retry.py,sha256=mhFbykXjhTnZfgzeuy-vl9c8nECnYn_CMtwNJX2tYzQ,1392
pip/_internal/utils/setuptools_build.py,sha256=ouXpud-jeS8xPyTPsXJ-m34NPvK5os45otAzdSV_IJE,4435
pip/_internal/utils/subprocess.py,sha256=EsvqSRiSMHF98T8Txmu6NLU3U--MpTTQjtNgKP0P--M,8988
pip/_internal/utils/temp_dir.py,sha256=5qOXe8M4JeY6vaFQM867d5zkp1bSwMZ-KT5jymmP0Zg,9310
pip/_internal/utils/unpacking.py,sha256=_gVdyzTRDMYktpnYljn4OoxrZTtMCf4xknSm4rK0WaA,11967
pip/_internal/utils/urls.py,sha256=qceSOZb5lbNDrHNsv7_S4L4Ytszja5NwPKUMnZHbYnM,1599
pip/_internal/utils/virtualenv.py,sha256=S6f7csYorRpiD6cvn3jISZYc3I8PJC43H5iMFpRAEDU,3456
pip/_internal/utils/wheel.py,sha256=b442jkydFHjXzDy6cMR7MpzWBJ1Q82hR5F33cmcHV3g,4494
pip/_internal/vcs/__init__.py,sha256=UAqvzpbi0VbZo3Ub6skEeZAw-ooIZR-zX_WpCbxyCoU,596
pip/_internal/vcs/__pycache__/__init__.cpython-312.pyc,,
pip/_internal/vcs/__pycache__/bazaar.cpython-312.pyc,,
pip/_internal/vcs/__pycache__/git.cpython-312.pyc,,
pip/_internal/vcs/__pycache__/mercurial.cpython-312.pyc,,
pip/_internal/vcs/__pycache__/subversion.cpython-312.pyc,,
pip/_internal/vcs/__pycache__/versioncontrol.cpython-312.pyc,,
pip/_internal/vcs/bazaar.py,sha256=EKStcQaKpNu0NK4p5Q10Oc4xb3DUxFw024XrJy40bFQ,3528
pip/_internal/vcs/git.py,sha256=3tpc9LQA_J4IVW5r5NvWaaSeDzcmJOrSFZN0J8vIKfU,18177
pip/_internal/vcs/mercurial.py,sha256=oULOhzJ2Uie-06d1omkL-_Gc6meGaUkyogvqG9ZCyPs,5249
pip/_internal/vcs/subversion.py,sha256=ddTugHBqHzV3ebKlU5QXHPN4gUqlyXbOx8q8NgXKvs8,11735
pip/_internal/vcs/versioncontrol.py,sha256=cvf_-hnTAjQLXJ3d17FMNhQfcO1AcKWUF10tfrYyP-c,22440
pip/_internal/wheel_builder.py,sha256=DL3A8LKeRj_ACp11WS5wSgASgPFqeyAeXJKdXfmaWXU,11799
pip/_vendor/__init__.py,sha256=JYuAXvClhInxIrA2FTp5p-uuWVL7WV6-vEpTs46-Qh4,4873
pip/_vendor/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/__pycache__/typing_extensions.cpython-312.pyc,,
pip/_vendor/cachecontrol/__init__.py,sha256=LMC5CBe94ZRL5xhlzwyPDmHXvBD0p7lT4R3Z73D6a_I,677
pip/_vendor/cachecontrol/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-312.pyc,,
pip/_vendor/cachecontrol/__pycache__/adapter.cpython-312.pyc,,
pip/_vendor/cachecontrol/__pycache__/cache.cpython-312.pyc,,
pip/_vendor/cachecontrol/__pycache__/controller.cpython-312.pyc,,
pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-312.pyc,,
pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-312.pyc,,
pip/_vendor/cachecontrol/__pycache__/serialize.cpython-312.pyc,,
pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-312.pyc,,
pip/_vendor/cachecontrol/_cmd.py,sha256=iist2EpzJvDVIhMAxXq8iFnTBsiZAd6iplxfmNboNyk,1737
pip/_vendor/cachecontrol/adapter.py,sha256=febjY4LV87iiCIK3jcl8iH58iaSA7b9WkovsByIDK0Y,6348
pip/_vendor/cachecontrol/cache.py,sha256=OXwv7Fn2AwnKNiahJHnjtvaKLndvVLv_-zO-ltlV9qI,1953
pip/_vendor/cachecontrol/caches/__init__.py,sha256=dtrrroK5BnADR1GWjCZ19aZ0tFsMfvFBtLQQU1sp_ag,303
pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-312.pyc,,
pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-312.pyc,,
pip/_vendor/cachecontrol/caches/file_cache.py,sha256=b7oMgsRSqPmEsonVJw6uFEYUlFgD6GF8TyacOGG1x3M,5399
pip/_vendor/cachecontrol/caches/redis_cache.py,sha256=9rmqwtYu_ljVkW6_oLqbC7EaX_a8YT_yLuna-eS0dgo,1386
pip/_vendor/cachecontrol/controller.py,sha256=glbPj2iZlGqdBg8z09D2DtQOzoOGXnWvy7K2LEyBsEQ,18576
pip/_vendor/cachecontrol/filewrapper.py,sha256=2ktXNPE0KqnyzF24aOsKCA58HQq1xeC6l2g6_zwjghc,4291
pip/_vendor/cachecontrol/heuristics.py,sha256=gqMXU8w0gQuEQiSdu3Yg-0vd9kW7nrWKbLca75rheGE,4881
pip/_vendor/cachecontrol/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_vendor/cachecontrol/serialize.py,sha256=HQd2IllQ05HzPkVLMXTF2uX5mjEQjDBkxCqUJUODpZk,5163
pip/_vendor/cachecontrol/wrapper.py,sha256=hsGc7g8QGQTT-4f8tgz3AM5qwScg6FO0BSdLSRdEvpU,1417
pip/_vendor/certifi/__init__.py,sha256=p_GYZrjUwPBUhpLlCZoGb0miKBKSqDAyZC5DvIuqbHQ,94
pip/_vendor/certifi/__main__.py,sha256=1k3Cr95vCxxGRGDljrW3wMdpZdL3Nhf0u1n-k2qdsCY,255
pip/_vendor/certifi/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/certifi/__pycache__/__main__.cpython-312.pyc,,
pip/_vendor/certifi/__pycache__/core.cpython-312.pyc,,
pip/_vendor/certifi/cacert.pem,sha256=lO3rZukXdPyuk6BWUJFOKQliWaXH6HGh9l1GGrUgG0c,299427
pip/_vendor/certifi/core.py,sha256=2SRT5rIcQChFDbe37BQa-kULxAgJ8qN6l1jfqTp4HIs,4486
pip/_vendor/certifi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_vendor/distlib/__init__.py,sha256=dcwgYGYGQqAEawBXPDtIx80DO_3cOmFv8HTc8JMzknQ,625
pip/_vendor/distlib/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/distlib/__pycache__/compat.cpython-312.pyc,,
pip/_vendor/distlib/__pycache__/database.cpython-312.pyc,,
pip/_vendor/distlib/__pycache__/index.cpython-312.pyc,,
pip/_vendor/distlib/__pycache__/locators.cpython-312.pyc,,
pip/_vendor/distlib/__pycache__/manifest.cpython-312.pyc,,
pip/_vendor/distlib/__pycache__/markers.cpython-312.pyc,,
pip/_vendor/distlib/__pycache__/metadata.cpython-312.pyc,,
pip/_vendor/distlib/__pycache__/resources.cpython-312.pyc,,
pip/_vendor/distlib/__pycache__/scripts.cpython-312.pyc,,
pip/_vendor/distlib/__pycache__/util.cpython-312.pyc,,
pip/_vendor/distlib/__pycache__/version.cpython-312.pyc,,
pip/_vendor/distlib/__pycache__/wheel.cpython-312.pyc,,
pip/_vendor/distlib/compat.py,sha256=2jRSjRI4o-vlXeTK2BCGIUhkc6e9ZGhSsacRM5oseTw,41467
pip/_vendor/distlib/database.py,sha256=mHy_LxiXIsIVRb-T0-idBrVLw3Ffij5teHCpbjmJ9YU,51160
pip/_vendor/distlib/index.py,sha256=lTbw268rRhj8dw1sib3VZ_0EhSGgoJO3FKJzSFMOaeA,20797
pip/_vendor/distlib/locators.py,sha256=oBeAZpFuPQSY09MgNnLfQGGAXXvVO96BFpZyKMuK4tM,51026
pip/_vendor/distlib/manifest.py,sha256=3qfmAmVwxRqU1o23AlfXrQGZzh6g_GGzTAP_Hb9C5zQ,14168
pip/_vendor/distlib/markers.py,sha256=X6sDvkFGcYS8gUW8hfsWuKEKAqhQZAJ7iXOMLxRYjYk,5164
pip/_vendor/distlib/metadata.py,sha256=zil3sg2EUfLXVigljY2d_03IJt-JSs7nX-73fECMX2s,38724
pip/_vendor/distlib/resources.py,sha256=LwbPksc0A1JMbi6XnuPdMBUn83X7BPuFNWqPGEKI698,10820
pip/_vendor/distlib/scripts.py,sha256=BJliaDAZaVB7WAkwokgC3HXwLD2iWiHaVI50H7C6eG8,18608
pip/_vendor/distlib/t32.exe,sha256=a0GV5kCoWsMutvliiCKmIgV98eRZ33wXoS-XrqvJQVs,97792
pip/_vendor/distlib/t64-arm.exe,sha256=68TAa32V504xVBnufojh0PcenpR3U4wAqTqf-MZqbPw,182784
pip/_vendor/distlib/t64.exe,sha256=gaYY8hy4fbkHYTTnA4i26ct8IQZzkBG2pRdy0iyuBrc,108032
pip/_vendor/distlib/util.py,sha256=vMPGvsS4j9hF6Y9k3Tyom1aaHLb0rFmZAEyzeAdel9w,66682
pip/_vendor/distlib/version.py,sha256=s5VIs8wBn0fxzGxWM_aA2ZZyx525HcZbMvcTlTyZ3Rg,23727
pip/_vendor/distlib/w32.exe,sha256=R4csx3-OGM9kL4aPIzQKRo5TfmRSHZo6QWyLhDhNBks,91648
pip/_vendor/distlib/w64-arm.exe,sha256=xdyYhKj0WDcVUOCb05blQYvzdYIKMbmJn2SZvzkcey4,168448
pip/_vendor/distlib/w64.exe,sha256=ejGf-rojoBfXseGLpya6bFTFPWRG21X5KvU8J5iU-K0,101888
pip/_vendor/distlib/wheel.py,sha256=DFIVguEQHCdxnSdAO0dfFsgMcvVZitg7bCOuLwZ7A_s,43979
pip/_vendor/distro/__init__.py,sha256=2fHjF-SfgPvjyNZ1iHh_wjqWdR_Yo5ODHwZC0jLBPhc,981
pip/_vendor/distro/__main__.py,sha256=bu9d3TifoKciZFcqRBuygV3GSuThnVD_m2IK4cz96Vs,64
pip/_vendor/distro/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/distro/__pycache__/__main__.cpython-312.pyc,,
pip/_vendor/distro/__pycache__/distro.cpython-312.pyc,,
pip/_vendor/distro/distro.py,sha256=XqbefacAhDT4zr_trnbA15eY8vdK4GTghgmvUGrEM_4,49430
pip/_vendor/distro/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_vendor/idna/__init__.py,sha256=MPqNDLZbXqGaNdXxAFhiqFPKEQXju2jNQhCey6-5eJM,868
pip/_vendor/idna/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/idna/__pycache__/codec.cpython-312.pyc,,
pip/_vendor/idna/__pycache__/compat.cpython-312.pyc,,
pip/_vendor/idna/__pycache__/core.cpython-312.pyc,,
pip/_vendor/idna/__pycache__/idnadata.cpython-312.pyc,,
pip/_vendor/idna/__pycache__/intranges.cpython-312.pyc,,
pip/_vendor/idna/__pycache__/package_data.cpython-312.pyc,,
pip/_vendor/idna/__pycache__/uts46data.cpython-312.pyc,,
pip/_vendor/idna/codec.py,sha256=PEew3ItwzjW4hymbasnty2N2OXvNcgHB-JjrBuxHPYY,3422
pip/_vendor/idna/compat.py,sha256=RzLy6QQCdl9784aFhb2EX9EKGCJjg0P3PilGdeXXcx8,316
pip/_vendor/idna/core.py,sha256=YJYyAMnwiQEPjVC4-Fqu_p4CJ6yKKuDGmppBNQNQpFs,13239
pip/_vendor/idna/idnadata.py,sha256=W30GcIGvtOWYwAjZj4ZjuouUutC6ffgNuyjJy7fZ-lo,78306
pip/_vendor/idna/intranges.py,sha256=amUtkdhYcQG8Zr-CoMM_kVRacxkivC1WgxN1b63KKdU,1898
pip/_vendor/idna/package_data.py,sha256=q59S3OXsc5VI8j6vSD0sGBMyk6zZ4vWFREE88yCJYKs,21
pip/_vendor/idna/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_vendor/idna/uts46data.py,sha256=rt90K9J40gUSwppDPCrhjgi5AA6pWM65dEGRSf6rIhM,239289
pip/_vendor/msgpack/__init__.py,sha256=reRaiOtEzSjPnr7TpxjgIvbfln5pV66FhricAs2eC-g,1109
pip/_vendor/msgpack/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/msgpack/__pycache__/exceptions.cpython-312.pyc,,
pip/_vendor/msgpack/__pycache__/ext.cpython-312.pyc,,
pip/_vendor/msgpack/__pycache__/fallback.cpython-312.pyc,,
pip/_vendor/msgpack/exceptions.py,sha256=dCTWei8dpkrMsQDcjQk74ATl9HsIBH0ybt8zOPNqMYc,1081
pip/_vendor/msgpack/ext.py,sha256=kteJv03n9tYzd5oo3xYopVTo4vRaAxonBQQJhXohZZo,5726
pip/_vendor/msgpack/fallback.py,sha256=0g1Pzp0vtmBEmJ5w9F3s_-JMVURP8RS4G1cc5TRaAsI,32390
pip/_vendor/packaging/__init__.py,sha256=dk4Ta_vmdVJxYHDcfyhvQNw8V3PgSBomKNXqg-D2JDY,494
pip/_vendor/packaging/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/packaging/__pycache__/_elffile.cpython-312.pyc,,
pip/_vendor/packaging/__pycache__/_manylinux.cpython-312.pyc,,
pip/_vendor/packaging/__pycache__/_musllinux.cpython-312.pyc,,
pip/_vendor/packaging/__pycache__/_parser.cpython-312.pyc,,
pip/_vendor/packaging/__pycache__/_structures.cpython-312.pyc,,
pip/_vendor/packaging/__pycache__/_tokenizer.cpython-312.pyc,,
pip/_vendor/packaging/__pycache__/markers.cpython-312.pyc,,
pip/_vendor/packaging/__pycache__/metadata.cpython-312.pyc,,
pip/_vendor/packaging/__pycache__/requirements.cpython-312.pyc,,
pip/_vendor/packaging/__pycache__/specifiers.cpython-312.pyc,,
pip/_vendor/packaging/__pycache__/tags.cpython-312.pyc,,
pip/_vendor/packaging/__pycache__/utils.cpython-312.pyc,,
pip/_vendor/packaging/__pycache__/version.cpython-312.pyc,,
pip/_vendor/packaging/_elffile.py,sha256=cflAQAkE25tzhYmq_aCi72QfbT_tn891tPzfpbeHOwE,3306
pip/_vendor/packaging/_manylinux.py,sha256=vl5OCoz4kx80H5rwXKeXWjl9WNISGmr4ZgTpTP9lU9c,9612
pip/_vendor/packaging/_musllinux.py,sha256=p9ZqNYiOItGee8KcZFeHF_YcdhVwGHdK6r-8lgixvGQ,2694
pip/_vendor/packaging/_parser.py,sha256=s_TvTvDNK0NrM2QB3VKThdWFM4Nc0P6JnkObkl3MjpM,10236
pip/_vendor/packaging/_structures.py,sha256=q3eVNmbWJGG_S0Dit_S3Ao8qQqz_5PYTXFAKBZe5yr4,1431
pip/_vendor/packaging/_tokenizer.py,sha256=J6v5H7Jzvb-g81xp_2QACKwO7LxHQA6ikryMU7zXwN8,5273
pip/_vendor/packaging/licenses/__init__.py,sha256=A116-FU49_Dz4162M4y1uAiZN4Rgdc83FxNd8EjlfqI,5727
pip/_vendor/packaging/licenses/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/packaging/licenses/__pycache__/_spdx.cpython-312.pyc,,
pip/_vendor/packaging/licenses/_spdx.py,sha256=oAm1ztPFwlsmCKe7lAAsv_OIOfS1cWDu9bNBkeu-2ns,48398
pip/_vendor/packaging/markers.py,sha256=c89TNzB7ZdGYhkovm6PYmqGyHxXlYVaLW591PHUNKD8,10561
pip/_vendor/packaging/metadata.py,sha256=YJibM7GYe4re8-0a3OlXmGS-XDgTEoO4tlBt2q25Bng,34762
pip/_vendor/packaging/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_vendor/packaging/requirements.py,sha256=gYyRSAdbrIyKDY66ugIDUQjRMvxkH2ALioTmX3tnL6o,2947
pip/_vendor/packaging/specifiers.py,sha256=hGU6kuCd77bL-msIL6yLCp6MNT75RSMUKZDuju26c8U,40098
pip/_vendor/packaging/tags.py,sha256=CFqrJzAzc2XNGexerH__T-Y5Iwq7WbsYXsiLERLWxY0,21014
pip/_vendor/packaging/utils.py,sha256=0F3Hh9OFuRgrhTgGZUl5K22Fv1YP2tZl1z_2gO6kJiA,5050
pip/_vendor/packaging/version.py,sha256=oiHqzTUv_p12hpjgsLDVcaF5hT7pDaSOViUNMD4GTW0,16688
pip/_vendor/pkg_resources/__init__.py,sha256=jrhDRbOubP74QuPXxd7U7Po42PH2l-LZ2XfcO7llpZ4,124463
pip/_vendor/pkg_resources/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/platformdirs/__init__.py,sha256=JueR2cRLkxY7iwik-qNWJCwKOrAlBgVgcZ_IHQzqGLE,22344
pip/_vendor/platformdirs/__main__.py,sha256=jBJ8zb7Mpx5ebcqF83xrpO94MaeCpNGHVf9cvDN2JLg,1505
pip/_vendor/platformdirs/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/platformdirs/__pycache__/__main__.cpython-312.pyc,,
pip/_vendor/platformdirs/__pycache__/android.cpython-312.pyc,,
pip/_vendor/platformdirs/__pycache__/api.cpython-312.pyc,,
pip/_vendor/platformdirs/__pycache__/macos.cpython-312.pyc,,
pip/_vendor/platformdirs/__pycache__/unix.cpython-312.pyc,,
pip/_vendor/platformdirs/__pycache__/version.cpython-312.pyc,,
pip/_vendor/platformdirs/__pycache__/windows.cpython-312.pyc,,
pip/_vendor/platformdirs/android.py,sha256=kV5oL3V3DZ6WZKu9yFiQupv18yp_jlSV2ChH1TmPcds,9007
pip/_vendor/platformdirs/api.py,sha256=2dfUDNbEXeDhDKarqtR5NY7oUikUZ4RZhs3ozstmhBQ,9246
pip/_vendor/platformdirs/macos.py,sha256=UlbyFZ8Rzu3xndCqQEHrfsYTeHwYdFap1Ioz-yxveT4,6154
pip/_vendor/platformdirs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_vendor/platformdirs/unix.py,sha256=uRPJWRyQEtv7yOSvU94rUmsblo5XKDLA1SzFg55kbK0,10393
pip/_vendor/platformdirs/version.py,sha256=oH4KgTfK4AklbTYVcV_yynvJ9JLI3pyvDVay0hRsLCs,411
pip/_vendor/platformdirs/windows.py,sha256=IFpiohUBwxPtCzlyKwNtxyW4Jk8haa6W8o59mfrDXVo,10125
pip/_vendor/pygments/__init__.py,sha256=7N1oiaWulw_nCsTY4EEixYLz15pWY5u4uPAFFi-ielU,2983
pip/_vendor/pygments/__main__.py,sha256=isIhBxLg65nLlXukG4VkMuPfNdd7gFzTZ_R_z3Q8diY,353
pip/_vendor/pygments/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/pygments/__pycache__/__main__.cpython-312.pyc,,
pip/_vendor/pygments/__pycache__/cmdline.cpython-312.pyc,,
pip/_vendor/pygments/__pycache__/console.cpython-312.pyc,,
pip/_vendor/pygments/__pycache__/filter.cpython-312.pyc,,
pip/_vendor/pygments/__pycache__/formatter.cpython-312.pyc,,
pip/_vendor/pygments/__pycache__/lexer.cpython-312.pyc,,
pip/_vendor/pygments/__pycache__/modeline.cpython-312.pyc,,
pip/_vendor/pygments/__pycache__/plugin.cpython-312.pyc,,
pip/_vendor/pygments/__pycache__/regexopt.cpython-312.pyc,,
pip/_vendor/pygments/__pycache__/scanner.cpython-312.pyc,,
pip/_vendor/pygments/__pycache__/sphinxext.cpython-312.pyc,,
pip/_vendor/pygments/__pycache__/style.cpython-312.pyc,,
pip/_vendor/pygments/__pycache__/token.cpython-312.pyc,,
pip/_vendor/pygments/__pycache__/unistring.cpython-312.pyc,,
pip/_vendor/pygments/__pycache__/util.cpython-312.pyc,,
pip/_vendor/pygments/cmdline.py,sha256=LIVzmAunlk9sRJJp54O4KRy9GDIN4Wu13v9p9QzfGPM,23656
pip/_vendor/pygments/console.py,sha256=yhP9UsLAVmWKVQf2446JJewkA7AiXeeTf4Ieg3Oi2fU,1718
pip/_vendor/pygments/filter.py,sha256=_ADNPCskD8_GmodHi6_LoVgPU3Zh336aBCT5cOeTMs0,1910
pip/_vendor/pygments/filters/__init__.py,sha256=RdedK2KWKXlKwR7cvkfr3NUj9YiZQgMgilRMFUg2jPA,40392
pip/_vendor/pygments/filters/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/pygments/formatter.py,sha256=jDWBTndlBH2Z5IYZFVDnP0qn1CaTQjTWt7iAGtCnJEg,4390
pip/_vendor/pygments/formatters/__init__.py,sha256=8No-NUs8rBTSSBJIv4hSEQt2M0cFB4hwAT0snVc2QGE,5385
pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-312.pyc,,
pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-312.pyc,,
pip/_vendor/pygments/formatters/__pycache__/groff.cpython-312.pyc,,
pip/_vendor/pygments/formatters/__pycache__/html.cpython-312.pyc,,
pip/_vendor/pygments/formatters/__pycache__/img.cpython-312.pyc,,
pip/_vendor/pygments/formatters/__pycache__/irc.cpython-312.pyc,,
pip/_vendor/pygments/formatters/__pycache__/latex.cpython-312.pyc,,
pip/_vendor/pygments/formatters/__pycache__/other.cpython-312.pyc,,
pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-312.pyc,,
pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-312.pyc,,
pip/_vendor/pygments/formatters/__pycache__/svg.cpython-312.pyc,,
pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-312.pyc,,
pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-312.pyc,,
pip/_vendor/pygments/formatters/_mapping.py,sha256=1Cw37FuQlNacnxRKmtlPX4nyLoX9_ttko5ZwscNUZZ4,4176
pip/_vendor/pygments/formatters/bbcode.py,sha256=3JQLI45tcrQ_kRUMjuab6C7Hb0XUsbVWqqbSn9cMjkI,3320
pip/_vendor/pygments/formatters/groff.py,sha256=M39k0PaSSZRnxWjqBSVPkF0mu1-Vr7bm6RsFvs-CNN4,5106
pip/_vendor/pygments/formatters/html.py,sha256=SE2jc3YCqbMS3rZW9EAmDlAUhdVxJ52gA4dileEvCGU,35669
pip/_vendor/pygments/formatters/img.py,sha256=MwA4xWPLOwh6j7Yc6oHzjuqSPt0M1fh5r-5BTIIUfsU,23287
pip/_vendor/pygments/formatters/irc.py,sha256=dp1Z0l_ObJ5NFh9MhqLGg5ptG5hgJqedT2Vkutt9v0M,4981
pip/_vendor/pygments/formatters/latex.py,sha256=XMmhOCqUKDBQtG5mGJNAFYxApqaC5puo5cMmPfK3944,19306
pip/_vendor/pygments/formatters/other.py,sha256=56PMJOliin-rAUdnRM0i1wsV1GdUPd_dvQq0_UPfF9c,5034
pip/_vendor/pygments/formatters/pangomarkup.py,sha256=y16U00aVYYEFpeCfGXlYBSMacG425CbfoG8oKbKegIg,2218
pip/_vendor/pygments/formatters/rtf.py,sha256=ZT90dmcKyJboIB0mArhL7IhE467GXRN0G7QAUgG03To,11957
pip/_vendor/pygments/formatters/svg.py,sha256=KKsiophPupHuxm0So-MsbQEWOT54IAiSF7hZPmxtKXE,7174
pip/_vendor/pygments/formatters/terminal.py,sha256=AojNG4MlKq2L6IsC_VnXHu4AbHCBn9Otog6u45XvxeI,4674
pip/_vendor/pygments/formatters/terminal256.py,sha256=kGkNUVo3FpwjytIDS0if79EuUoroAprcWt3igrcIqT0,11753
pip/_vendor/pygments/lexer.py,sha256=TYHDt___gNW4axTl2zvPZff-VQi8fPaIh5OKRcVSjUM,35349
pip/_vendor/pygments/lexers/__init__.py,sha256=pIlxyQJuu_syh9lE080cq8ceVbEVcKp0osAFU5fawJU,12115
pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-312.pyc,,
pip/_vendor/pygments/lexers/__pycache__/python.cpython-312.pyc,,
pip/_vendor/pygments/lexers/_mapping.py,sha256=61-h3zr103m01OS5BUq_AfUiL9YI06Ves9ipQ7k4vr4,76097
pip/_vendor/pygments/lexers/python.py,sha256=2J_YJrPTr_A6fJY_qKiKv0GpgPwHMrlMSeo59qN3fe4,53687
pip/_vendor/pygments/modeline.py,sha256=gtRYZBS-CKOCDXHhGZqApboHBaZwGH8gznN3O6nuxj4,1005
pip/_vendor/pygments/plugin.py,sha256=ioeJ3QeoJ-UQhZpY9JL7vbxsTVuwwM7BCu-Jb8nN0AU,1891
pip/_vendor/pygments/regexopt.py,sha256=Hky4EB13rIXEHQUNkwmCrYqtIlnXDehNR3MztafZ43w,3072
pip/_vendor/pygments/scanner.py,sha256=NDy3ofK_fHRFK4hIDvxpamG871aewqcsIb6sgTi7Fhk,3092
pip/_vendor/pygments/sphinxext.py,sha256=iOptJBcqOGPwMEJ2p70PvwpZPIGdvdZ8dxvq6kzxDgA,7981
pip/_vendor/pygments/style.py,sha256=rSCZWFpg1_DwFMXDU0nEVmAcBHpuQGf9RxvOPPQvKLQ,6420
pip/_vendor/pygments/styles/__init__.py,sha256=qUk6_1z5KmT8EdJFZYgESmG6P_HJF_2vVrDD7HSCGYY,2042
pip/_vendor/pygments/styles/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/pygments/styles/__pycache__/_mapping.cpython-312.pyc,,
pip/_vendor/pygments/styles/_mapping.py,sha256=6lovFUE29tz6EsV3XYY4hgozJ7q1JL7cfO3UOlgnS8w,3312
pip/_vendor/pygments/token.py,sha256=qZwT7LSPy5YBY3JgDjut642CCy7JdQzAfmqD9NmT5j0,6226
pip/_vendor/pygments/unistring.py,sha256=p5c1i-HhoIhWemy9CUsaN9o39oomYHNxXll0Xfw6tEA,63208
pip/_vendor/pygments/util.py,sha256=2tj2nS1X9_OpcuSjf8dOET2bDVZhs8cEKd_uT6-Fgg8,10031
pip/_vendor/pyproject_hooks/__init__.py,sha256=cPB_a9LXz5xvsRbX1o2qyAdjLatZJdQ_Lc5McNX-X7Y,691
pip/_vendor/pyproject_hooks/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/pyproject_hooks/__pycache__/_impl.cpython-312.pyc,,
pip/_vendor/pyproject_hooks/_impl.py,sha256=jY-raxnmyRyB57ruAitrJRUzEexuAhGTpgMygqx67Z4,14936
pip/_vendor/pyproject_hooks/_in_process/__init__.py,sha256=MJNPpfIxcO-FghxpBbxkG1rFiQf6HOUbV4U5mq0HFns,557
pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-312.pyc,,
pip/_vendor/pyproject_hooks/_in_process/_in_process.py,sha256=qcXMhmx__MIJq10gGHW3mA4Tl8dy8YzHMccwnNoKlw0,12216
pip/_vendor/pyproject_hooks/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_vendor/requests/__init__.py,sha256=HlB_HzhrzGtfD_aaYUwUh1zWXLZ75_YCLyit75d0Vz8,5057
pip/_vendor/requests/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/requests/__pycache__/__version__.cpython-312.pyc,,
pip/_vendor/requests/__pycache__/_internal_utils.cpython-312.pyc,,
pip/_vendor/requests/__pycache__/adapters.cpython-312.pyc,,
pip/_vendor/requests/__pycache__/api.cpython-312.pyc,,
pip/_vendor/requests/__pycache__/auth.cpython-312.pyc,,
pip/_vendor/requests/__pycache__/certs.cpython-312.pyc,,
pip/_vendor/requests/__pycache__/compat.cpython-312.pyc,,
pip/_vendor/requests/__pycache__/cookies.cpython-312.pyc,,
pip/_vendor/requests/__pycache__/exceptions.cpython-312.pyc,,
pip/_vendor/requests/__pycache__/help.cpython-312.pyc,,
pip/_vendor/requests/__pycache__/hooks.cpython-312.pyc,,
pip/_vendor/requests/__pycache__/models.cpython-312.pyc,,
pip/_vendor/requests/__pycache__/packages.cpython-312.pyc,,
pip/_vendor/requests/__pycache__/sessions.cpython-312.pyc,,
pip/_vendor/requests/__pycache__/status_codes.cpython-312.pyc,,
pip/_vendor/requests/__pycache__/structures.cpython-312.pyc,,
pip/_vendor/requests/__pycache__/utils.cpython-312.pyc,,
pip/_vendor/requests/__version__.py,sha256=FVfglgZmNQnmYPXpOohDU58F5EUb_-VnSTaAesS187g,435
pip/_vendor/requests/_internal_utils.py,sha256=nMQymr4hs32TqVo5AbCrmcJEhvPUh7xXlluyqwslLiQ,1495
pip/_vendor/requests/adapters.py,sha256=J7VeVxKBvawbtlX2DERVo05J9BXTcWYLMHNd1Baa-bk,27607
pip/_vendor/requests/api.py,sha256=_Zb9Oa7tzVIizTKwFrPjDEY9ejtm_OnSRERnADxGsQs,6449
pip/_vendor/requests/auth.py,sha256=kF75tqnLctZ9Mf_hm9TZIj4cQWnN5uxRz8oWsx5wmR0,10186
pip/_vendor/requests/certs.py,sha256=kHDlkK_beuHXeMPc5jta2wgl8gdKeUWt5f2nTDVrvt8,441
pip/_vendor/requests/compat.py,sha256=Mo9f9xZpefod8Zm-n9_StJcVTmwSukXR2p3IQyyVXvU,1485
pip/_vendor/requests/cookies.py,sha256=bNi-iqEj4NPZ00-ob-rHvzkvObzN3lEpgw3g6paS3Xw,18590
pip/_vendor/requests/exceptions.py,sha256=D1wqzYWne1mS2rU43tP9CeN1G7QAy7eqL9o1god6Ejw,4272
pip/_vendor/requests/help.py,sha256=hRKaf9u0G7fdwrqMHtF3oG16RKktRf6KiwtSq2Fo1_0,3813
pip/_vendor/requests/hooks.py,sha256=CiuysiHA39V5UfcCBXFIx83IrDpuwfN9RcTUgv28ftQ,733
pip/_vendor/requests/models.py,sha256=x4K4CmH-lC0l2Kb-iPfMN4dRXxHEcbOaEWBL_i09AwI,35483
pip/_vendor/requests/packages.py,sha256=_ZQDCJTJ8SP3kVWunSqBsRZNPzj2c1WFVqbdr08pz3U,1057
pip/_vendor/requests/sessions.py,sha256=ykTI8UWGSltOfH07HKollH7kTBGw4WhiBVaQGmckTw4,30495
pip/_vendor/requests/status_codes.py,sha256=iJUAeA25baTdw-6PfD0eF4qhpINDJRJI-yaMqxs4LEI,4322
pip/_vendor/requests/structures.py,sha256=-IbmhVz06S-5aPSZuUthZ6-6D9XOjRuTXHOabY041XM,2912
pip/_vendor/requests/utils.py,sha256=L79vnFbzJ3SFLKtJwpoWe41Tozi3RlZv94pY1TFIyow,33631
pip/_vendor/resolvelib/__init__.py,sha256=h509TdEcpb5-44JonaU3ex2TM15GVBLjM9CNCPwnTTs,537
pip/_vendor/resolvelib/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/resolvelib/__pycache__/providers.cpython-312.pyc,,
pip/_vendor/resolvelib/__pycache__/reporters.cpython-312.pyc,,
pip/_vendor/resolvelib/__pycache__/resolvers.cpython-312.pyc,,
pip/_vendor/resolvelib/__pycache__/structs.cpython-312.pyc,,
pip/_vendor/resolvelib/compat/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-312.pyc,,
pip/_vendor/resolvelib/compat/collections_abc.py,sha256=uy8xUZ-NDEw916tugUXm8HgwCGiMO0f-RcdnpkfXfOs,156
pip/_vendor/resolvelib/providers.py,sha256=fuuvVrCetu5gsxPB43ERyjfO8aReS3rFQHpDgiItbs4,5871
pip/_vendor/resolvelib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_vendor/resolvelib/reporters.py,sha256=TSbRmWzTc26w0ggsV1bxVpeWDB8QNIre6twYl7GIZBE,1601
pip/_vendor/resolvelib/resolvers.py,sha256=G8rsLZSq64g5VmIq-lB7UcIJ1gjAxIQJmTF4REZleQ0,20511
pip/_vendor/resolvelib/structs.py,sha256=0_1_XO8z_CLhegP3Vpf9VJ3zJcfLm0NOHRM-i0Ykz3o,4963
pip/_vendor/rich/__init__.py,sha256=dRxjIL-SbFVY0q3IjSMrfgBTHrm1LZDgLOygVBwiYZc,6090
pip/_vendor/rich/__main__.py,sha256=eO7Cq8JnrgG8zVoeImiAs92q3hXNMIfp0w5lMsO7Q2Y,8477
pip/_vendor/rich/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/__main__.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_cell_widths.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_emoji_codes.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_emoji_replace.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_export_format.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_extension.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_fileno.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_inspect.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_log_render.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_loop.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_null_file.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_palettes.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_pick.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_ratio.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_spinners.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_stack.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_timer.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_win32_console.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_windows.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_windows_renderer.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/_wrap.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/abc.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/align.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/ansi.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/bar.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/box.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/cells.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/color.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/color_triplet.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/columns.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/console.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/constrain.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/containers.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/control.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/default_styles.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/diagnose.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/emoji.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/errors.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/file_proxy.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/filesize.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/highlighter.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/json.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/jupyter.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/layout.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/live.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/live_render.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/logging.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/markup.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/measure.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/padding.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/pager.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/palette.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/panel.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/pretty.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/progress.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/progress_bar.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/prompt.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/protocol.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/region.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/repr.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/rule.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/scope.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/screen.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/segment.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/spinner.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/status.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/style.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/styled.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/syntax.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/table.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/terminal_theme.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/text.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/theme.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/themes.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/traceback.cpython-312.pyc,,
pip/_vendor/rich/__pycache__/tree.cpython-312.pyc,,
pip/_vendor/rich/_cell_widths.py,sha256=fbmeyetEdHjzE_Vx2l1uK7tnPOhMs2X1lJfO3vsKDpA,10209
pip/_vendor/rich/_emoji_codes.py,sha256=hu1VL9nbVdppJrVoijVshRlcRRe_v3dju3Mmd2sKZdY,140235
pip/_vendor/rich/_emoji_replace.py,sha256=n-kcetsEUx2ZUmhQrfeMNc-teeGhpuSQ5F8VPBsyvDo,1064
pip/_vendor/rich/_export_format.py,sha256=RI08pSrm5tBSzPMvnbTqbD9WIalaOoN5d4M1RTmLq1Y,2128
pip/_vendor/rich/_extension.py,sha256=Xt47QacCKwYruzjDi-gOBq724JReDj9Cm9xUi5fr-34,265
pip/_vendor/rich/_fileno.py,sha256=HWZxP5C2ajMbHryvAQZseflVfQoGzsKOHzKGsLD8ynQ,799
pip/_vendor/rich/_inspect.py,sha256=QM05lEFnFoTaFqpnbx-zBEI6k8oIKrD3cvjEOQNhKig,9655
pip/_vendor/rich/_log_render.py,sha256=1ByI0PA1ZpxZY3CGJOK54hjlq4X-Bz_boIjIqCd8Kns,3225
pip/_vendor/rich/_loop.py,sha256=hV_6CLdoPm0va22Wpw4zKqM0RYsz3TZxXj0PoS-9eDQ,1236
pip/_vendor/rich/_null_file.py,sha256=ADGKp1yt-k70FMKV6tnqCqecB-rSJzp-WQsD7LPL-kg,1394
pip/_vendor/rich/_palettes.py,sha256=cdev1JQKZ0JvlguV9ipHgznTdnvlIzUFDBb0It2PzjI,7063
pip/_vendor/rich/_pick.py,sha256=evDt8QN4lF5CiwrUIXlOJCntitBCOsI3ZLPEIAVRLJU,423
pip/_vendor/rich/_ratio.py,sha256=Zt58apszI6hAAcXPpgdWKpu3c31UBWebOeR4mbyptvU,5471
pip/_vendor/rich/_spinners.py,sha256=U2r1_g_1zSjsjiUdAESc2iAMc3i4ri_S8PYP6kQ5z1I,19919
pip/_vendor/rich/_stack.py,sha256=-C8OK7rxn3sIUdVwxZBBpeHhIzX0eI-VM3MemYfaXm0,351
pip/_vendor/rich/_timer.py,sha256=zelxbT6oPFZnNrwWPpc1ktUeAT-Vc4fuFcRZLQGLtMI,417
pip/_vendor/rich/_win32_console.py,sha256=BSaDRIMwBLITn_m0mTRLPqME5q-quGdSMuYMpYeYJwc,22755
pip/_vendor/rich/_windows.py,sha256=aBwaD_S56SbgopIvayVmpk0Y28uwY2C5Bab1wl3Bp-I,1925
pip/_vendor/rich/_windows_renderer.py,sha256=t74ZL3xuDCP3nmTp9pH1L5LiI2cakJuQRQleHCJerlk,2783
pip/_vendor/rich/_wrap.py,sha256=FlSsom5EX0LVkA3KWy34yHnCfLtqX-ZIepXKh-70rpc,3404
pip/_vendor/rich/abc.py,sha256=ON-E-ZqSSheZ88VrKX2M3PXpFbGEUUZPMa_Af0l-4f0,890
pip/_vendor/rich/align.py,sha256=Rh-3adnDaN1Ao07EjR2PhgE62PGLPgO8SMwJBku1urQ,10469
pip/_vendor/rich/ansi.py,sha256=Avs1LHbSdcyOvDOdpELZUoULcBiYewY76eNBp6uFBhs,6921
pip/_vendor/rich/bar.py,sha256=ldbVHOzKJOnflVNuv1xS7g6dLX2E3wMnXkdPbpzJTcs,3263
pip/_vendor/rich/box.py,sha256=nr5fYIUghB_iUCEq6y0Z3LlCT8gFPDrzN9u2kn7tJl4,10831
pip/_vendor/rich/cells.py,sha256=KrQkj5-LghCCpJLSNQIyAZjndc4bnEqOEmi5YuZ9UCY,5130
pip/_vendor/rich/color.py,sha256=3HSULVDj7qQkXUdFWv78JOiSZzfy5y1nkcYhna296V0,18211
pip/_vendor/rich/color_triplet.py,sha256=3lhQkdJbvWPoLDO-AnYImAWmJvV5dlgYNCVZ97ORaN4,1054
pip/_vendor/rich/columns.py,sha256=HUX0KcMm9dsKNi11fTbiM_h2iDtl8ySCaVcxlalEzq8,7131
pip/_vendor/rich/console.py,sha256=nKjrEx_7xy8KGmDVT-BgNII0R5hm1cexhAHDwdwNVqg,100156
pip/_vendor/rich/constrain.py,sha256=1VIPuC8AgtKWrcncQrjBdYqA3JVWysu6jZo1rrh7c7Q,1288
pip/_vendor/rich/containers.py,sha256=c_56TxcedGYqDepHBMTuZdUIijitAQgnox-Qde0Z1qo,5502
pip/_vendor/rich/control.py,sha256=DSkHTUQLorfSERAKE_oTAEUFefZnZp4bQb4q8rHbKws,6630
pip/_vendor/rich/default_styles.py,sha256=dZxgaSD9VUy7SXQShO33aLYiAWspCr2sCQZFX_JK1j4,8159
pip/_vendor/rich/diagnose.py,sha256=an6uouwhKPAlvQhYpNNpGq9EJysfMIOvvCbO3oSoR24,972
pip/_vendor/rich/emoji.py,sha256=omTF9asaAnsM4yLY94eR_9dgRRSm1lHUszX20D1yYCQ,2501
pip/_vendor/rich/errors.py,sha256=5pP3Kc5d4QJ_c0KFsxrfyhjiPVe7J1zOqSFbFAzcV-Y,642
pip/_vendor/rich/file_proxy.py,sha256=Tl9THMDZ-Pk5Wm8sI1gGg_U5DhusmxD-FZ0fUbcU0W0,1683
pip/_vendor/rich/filesize.py,sha256=_iz9lIpRgvW7MNSeCZnLg-HwzbP4GETg543WqD8SFs0,2484
pip/_vendor/rich/highlighter.py,sha256=G_sn-8DKjM1sEjLG_oc4ovkWmiUpWvj8bXi0yed2LnY,9586
pip/_vendor/rich/json.py,sha256=vVEoKdawoJRjAFayPwXkMBPLy7RSTs-f44wSQDR2nJ0,5031
pip/_vendor/rich/jupyter.py,sha256=QyoKoE_8IdCbrtiSHp9TsTSNyTHY0FO5whE7jOTd9UE,3252
pip/_vendor/rich/layout.py,sha256=ajkSFAtEVv9EFTcFs-w4uZfft7nEXhNzL7ZVdgrT5rI,14004
pip/_vendor/rich/live.py,sha256=DhzAPEnjTxQuq9_0Y2xh2MUwQcP_aGPkenLfKETslwM,14270
pip/_vendor/rich/live_render.py,sha256=zJtB471jGziBtEwxc54x12wEQtH4BuQr1SA8v9kU82w,3666
pip/_vendor/rich/logging.py,sha256=ZgpKMMBY_BuMAI_BYzo-UtXak6t5oH9VK8m9Q2Lm0f4,12458
pip/_vendor/rich/markup.py,sha256=3euGKP5s41NCQwaSjTnJxus5iZMHjxpIM0W6fCxra38,8451
pip/_vendor/rich/measure.py,sha256=HmrIJX8sWRTHbgh8MxEay_83VkqNW_70s8aKP5ZcYI8,5305
pip/_vendor/rich/padding.py,sha256=KVEI3tOwo9sgK1YNSuH__M1_jUWmLZwRVV_KmOtVzyM,4908
pip/_vendor/rich/pager.py,sha256=SO_ETBFKbg3n_AgOzXm41Sv36YxXAyI3_R-KOY2_uSc,828
pip/_vendor/rich/palette.py,sha256=lInvR1ODDT2f3UZMfL1grq7dY_pDdKHw4bdUgOGaM4Y,3396
pip/_vendor/rich/panel.py,sha256=fFRHcviXvWhk3V3zx5Zwmsb_RL9KJ3esD-sU0NYEVyw,11235
pip/_vendor/rich/pretty.py,sha256=gy3S72u4FRg2ytoo7N1ZDWDIvB4unbzd5iUGdgm-8fc,36391
pip/_vendor/rich/progress.py,sha256=MtmCjTk5zYU_XtRHxRHTAEHG6hF9PeF7EMWbEPleIC0,60357
pip/_vendor/rich/progress_bar.py,sha256=mZTPpJUwcfcdgQCTTz3kyY-fc79ddLwtx6Ghhxfo064,8162
pip/_vendor/rich/prompt.py,sha256=l0RhQU-0UVTV9e08xW1BbIj0Jq2IXyChX4lC0lFNzt4,12447
pip/_vendor/rich/protocol.py,sha256=5hHHDDNHckdk8iWH5zEbi-zuIVSF5hbU2jIo47R7lTE,1391
pip/_vendor/rich/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_vendor/rich/region.py,sha256=rNT9xZrVZTYIXZC0NYn41CJQwYNbR-KecPOxTgQvB8Y,166
pip/_vendor/rich/repr.py,sha256=5MZJZmONgC6kud-QW-_m1okXwL2aR6u6y-pUcUCJz28,4431
pip/_vendor/rich/rule.py,sha256=0fNaS_aERa3UMRc3T5WMpN_sumtDxfaor2y3of1ftBk,4602
pip/_vendor/rich/scope.py,sha256=TMUU8qo17thyqQCPqjDLYpg_UU1k5qVd-WwiJvnJVas,2843
pip/_vendor/rich/screen.py,sha256=YoeReESUhx74grqb0mSSb9lghhysWmFHYhsbMVQjXO8,1591
pip/_vendor/rich/segment.py,sha256=otnKeKGEV-WRlQVosfJVeFDcDxAKHpvJ_hLzSu5lumM,24743
pip/_vendor/rich/spinner.py,sha256=PT5qgXPG3ZpqRj7n3EZQ6NW56mx3ldZqZCU7gEMyZk4,4364
pip/_vendor/rich/status.py,sha256=kkPph3YeAZBo-X-4wPp8gTqZyU466NLwZBA4PZTTewo,4424
pip/_vendor/rich/style.py,sha256=aSoUNbVgfP1PAnduAqgbbl4AMQy668qs2S1FEwr3Oqs,27067
pip/_vendor/rich/styled.py,sha256=eZNnzGrI4ki_54pgY3Oj0T-x3lxdXTYh4_ryDB24wBU,1258
pip/_vendor/rich/syntax.py,sha256=qqAnEUZ4K57Po81_5RBxnsuU4KRzSdvDPAhKw8ma_3E,35763
pip/_vendor/rich/table.py,sha256=yXYUr0YsPpG466N50HCAw2bpb5ZUuuzdc-G66Zk-oTc,40103
pip/_vendor/rich/terminal_theme.py,sha256=1j5-ufJfnvlAo5Qsi_ACZiXDmwMXzqgmFByObT9-yJY,3370
pip/_vendor/rich/text.py,sha256=AO7JPCz6-gaN1thVLXMBntEmDPVYFgFNG1oM61_sanU,47552
pip/_vendor/rich/theme.py,sha256=oNyhXhGagtDlbDye3tVu3esWOWk0vNkuxFw-_unlaK0,3771
pip/_vendor/rich/themes.py,sha256=0xgTLozfabebYtcJtDdC5QkX5IVUEaviqDUJJh4YVFk,102
pip/_vendor/rich/traceback.py,sha256=z8UoN7NbTQKW6YDDUVwOh7F8snZf6gYnUWtOrKsLE1w,31797
pip/_vendor/rich/tree.py,sha256=yWnQ6rAvRGJ3qZGqBrxS2SW2TKBTNrP0SdY8QxOFPuw,9451
pip/_vendor/tomli/__init__.py,sha256=PhNw_eyLgdn7McJ6nrAN8yIm3dXC75vr1sVGVVwDSpA,314
pip/_vendor/tomli/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/tomli/__pycache__/_parser.cpython-312.pyc,,
pip/_vendor/tomli/__pycache__/_re.cpython-312.pyc,,
pip/_vendor/tomli/__pycache__/_types.cpython-312.pyc,,
pip/_vendor/tomli/_parser.py,sha256=9w8LG0jB7fwmZZWB0vVXbeejDHcl4ANIJxB2scEnDlA,25591
pip/_vendor/tomli/_re.py,sha256=sh4sBDRgO94KJZwNIrgdcyV_qQast50YvzOAUGpRDKA,3171
pip/_vendor/tomli/_types.py,sha256=-GTG2VUqkpxwMqzmVO4F7ybKddIbAnuAHXfmWQcTi3Q,254
pip/_vendor/tomli/py.typed,sha256=8PjyZ1aVoQpRVvt71muvuq5qE-jTFZkK-GLHkhdebmc,26
pip/_vendor/truststore/__init__.py,sha256=WIDeyzWm7EVX44g354M25vpRXbeY1lsPH6EmUJUcq4o,1264
pip/_vendor/truststore/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/truststore/__pycache__/_api.cpython-312.pyc,,
pip/_vendor/truststore/__pycache__/_macos.cpython-312.pyc,,
pip/_vendor/truststore/__pycache__/_openssl.cpython-312.pyc,,
pip/_vendor/truststore/__pycache__/_ssl_constants.cpython-312.pyc,,
pip/_vendor/truststore/__pycache__/_windows.cpython-312.pyc,,
pip/_vendor/truststore/_api.py,sha256=GeXRNTlxPZ3kif4kNoh6JY0oE4QRzTGcgXr6l_X_Gk0,10555
pip/_vendor/truststore/_macos.py,sha256=nZlLkOmszUE0g6ryRwBVGY5COzPyudcsiJtDWarM5LQ,20503
pip/_vendor/truststore/_openssl.py,sha256=LLUZ7ZGaio-i5dpKKjKCSeSufmn6T8pi9lDcFnvSyq0,2324
pip/_vendor/truststore/_ssl_constants.py,sha256=NUD4fVKdSD02ri7-db0tnO0VqLP9aHuzmStcW7tAl08,1130
pip/_vendor/truststore/_windows.py,sha256=rAHyKYD8M7t-bXfG8VgOVa3TpfhVhbt4rZQlO45YuP8,17993
pip/_vendor/truststore/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_vendor/typing_extensions.py,sha256=78hFl0HpDY-ylHUVCnWdU5nTHxUP2-S-3wEZk6CQmLk,134499
pip/_vendor/urllib3/__init__.py,sha256=iXLcYiJySn0GNbWOOZDDApgBL1JgP44EZ8i1760S8Mc,3333
pip/_vendor/urllib3/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/urllib3/__pycache__/_collections.cpython-312.pyc,,
pip/_vendor/urllib3/__pycache__/_version.cpython-312.pyc,,
pip/_vendor/urllib3/__pycache__/connection.cpython-312.pyc,,
pip/_vendor/urllib3/__pycache__/connectionpool.cpython-312.pyc,,
pip/_vendor/urllib3/__pycache__/exceptions.cpython-312.pyc,,
pip/_vendor/urllib3/__pycache__/fields.cpython-312.pyc,,
pip/_vendor/urllib3/__pycache__/filepost.cpython-312.pyc,,
pip/_vendor/urllib3/__pycache__/poolmanager.cpython-312.pyc,,
pip/_vendor/urllib3/__pycache__/request.cpython-312.pyc,,
pip/_vendor/urllib3/__pycache__/response.cpython-312.pyc,,
pip/_vendor/urllib3/_collections.py,sha256=pyASJJhW7wdOpqJj9QJA8FyGRfr8E8uUUhqUvhF0728,11372
pip/_vendor/urllib3/_version.py,sha256=t9wGB6ooOTXXgiY66K1m6BZS1CJyXHAU8EoWDTe6Shk,64
pip/_vendor/urllib3/connection.py,sha256=ttIA909BrbTUzwkqEe_TzZVh4JOOj7g61Ysei2mrwGg,20314
pip/_vendor/urllib3/connectionpool.py,sha256=e2eiAwNbFNCKxj4bwDKNK-w7HIdSz3OmMxU_TIt-evQ,40408
pip/_vendor/urllib3/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-312.pyc,,
pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-312.pyc,,
pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-312.pyc,,
pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc,,
pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-312.pyc,,
pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-312.pyc,,
pip/_vendor/urllib3/contrib/_appengine_environ.py,sha256=bDbyOEhW2CKLJcQqAKAyrEHN-aklsyHFKq6vF8ZFsmk,957
pip/_vendor/urllib3/contrib/_securetransport/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-312.pyc,,
pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-312.pyc,,
pip/_vendor/urllib3/contrib/_securetransport/bindings.py,sha256=4Xk64qIkPBt09A5q-RIFUuDhNc9mXilVapm7WnYnzRw,17632
pip/_vendor/urllib3/contrib/_securetransport/low_level.py,sha256=B2JBB2_NRP02xK6DCa1Pa9IuxrPwxzDzZbixQkb7U9M,13922
pip/_vendor/urllib3/contrib/appengine.py,sha256=VR68eAVE137lxTgjBDwCna5UiBZTOKa01Aj_-5BaCz4,11036
pip/_vendor/urllib3/contrib/ntlmpool.py,sha256=NlfkW7WMdW8ziqudopjHoW299og1BTWi0IeIibquFwk,4528
pip/_vendor/urllib3/contrib/pyopenssl.py,sha256=hDJh4MhyY_p-oKlFcYcQaVQRDv6GMmBGuW9yjxyeejM,17081
pip/_vendor/urllib3/contrib/securetransport.py,sha256=Fef1IIUUFHqpevzXiDPbIGkDKchY2FVKeVeLGR1Qq3g,34446
pip/_vendor/urllib3/contrib/socks.py,sha256=aRi9eWXo9ZEb95XUxef4Z21CFlnnjbEiAo9HOseoMt4,7097
pip/_vendor/urllib3/exceptions.py,sha256=0Mnno3KHTNfXRfY7638NufOPkUb6mXOm-Lqj-4x2w8A,8217
pip/_vendor/urllib3/fields.py,sha256=kvLDCg_JmH1lLjUUEY_FLS8UhY7hBvDPuVETbY8mdrM,8579
pip/_vendor/urllib3/filepost.py,sha256=5b_qqgRHVlL7uLtdAYBzBh-GHmU5AfJVt_2N0XS3PeY,2440
pip/_vendor/urllib3/packages/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/urllib3/packages/__pycache__/six.cpython-312.pyc,,
pip/_vendor/urllib3/packages/backports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-312.pyc,,
pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-312.pyc,,
pip/_vendor/urllib3/packages/backports/makefile.py,sha256=nbzt3i0agPVP07jqqgjhaYjMmuAi_W5E0EywZivVO8E,1417
pip/_vendor/urllib3/packages/backports/weakref_finalize.py,sha256=tRCal5OAhNSRyb0DhHp-38AtIlCsRP8BxF3NX-6rqIA,5343
pip/_vendor/urllib3/packages/six.py,sha256=b9LM0wBXv7E7SrbCjAm4wwN-hrH-iNxv18LgWNMMKPo,34665
pip/_vendor/urllib3/poolmanager.py,sha256=aWyhXRtNO4JUnCSVVqKTKQd8EXTvUm1VN9pgs2bcONo,19990
pip/_vendor/urllib3/request.py,sha256=YTWFNr7QIwh7E1W9dde9LM77v2VWTJ5V78XuTTw7D1A,6691
pip/_vendor/urllib3/response.py,sha256=fmDJAFkG71uFTn-sVSTh2Iw0WmcXQYqkbRjihvwBjU8,30641
pip/_vendor/urllib3/util/__init__.py,sha256=JEmSmmqqLyaw8P51gUImZh8Gwg9i1zSe-DoqAitn2nc,1155
pip/_vendor/urllib3/util/__pycache__/__init__.cpython-312.pyc,,
pip/_vendor/urllib3/util/__pycache__/connection.cpython-312.pyc,,
pip/_vendor/urllib3/util/__pycache__/proxy.cpython-312.pyc,,
pip/_vendor/urllib3/util/__pycache__/queue.cpython-312.pyc,,
pip/_vendor/urllib3/util/__pycache__/request.cpython-312.pyc,,
pip/_vendor/urllib3/util/__pycache__/response.cpython-312.pyc,,
pip/_vendor/urllib3/util/__pycache__/retry.cpython-312.pyc,,
pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-312.pyc,,
pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc,,
pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-312.pyc,,
pip/_vendor/urllib3/util/__pycache__/timeout.cpython-312.pyc,,
pip/_vendor/urllib3/util/__pycache__/url.cpython-312.pyc,,
pip/_vendor/urllib3/util/__pycache__/wait.cpython-312.pyc,,
pip/_vendor/urllib3/util/connection.py,sha256=5Lx2B1PW29KxBn2T0xkN1CBgRBa3gGVJBKoQoRogEVk,4901
pip/_vendor/urllib3/util/proxy.py,sha256=zUvPPCJrp6dOF0N4GAVbOcl6o-4uXKSrGiTkkr5vUS4,1605
pip/_vendor/urllib3/util/queue.py,sha256=nRgX8_eX-_VkvxoX096QWoz8Ps0QHUAExILCY_7PncM,498
pip/_vendor/urllib3/util/request.py,sha256=C0OUt2tcU6LRiQJ7YYNP9GvPrSvl7ziIBekQ-5nlBZk,3997
pip/_vendor/urllib3/util/response.py,sha256=GJpg3Egi9qaJXRwBh5wv-MNuRWan5BIu40oReoxWP28,3510
pip/_vendor/urllib3/util/retry.py,sha256=6ENvOZ8PBDzh8kgixpql9lIrb2dxH-k7ZmBanJF2Ng4,22050
pip/_vendor/urllib3/util/ssl_.py,sha256=QDuuTxPSCj1rYtZ4xpD7Ux-r20TD50aHyqKyhQ7Bq4A,17460
pip/_vendor/urllib3/util/ssl_match_hostname.py,sha256=Ir4cZVEjmAk8gUAIHWSi7wtOO83UCYABY2xFD1Ql_WA,5758
pip/_vendor/urllib3/util/ssltransport.py,sha256=NA-u5rMTrDFDFC8QzRKUEKMG0561hOD4qBTr3Z4pv6E,6895
pip/_vendor/urllib3/util/timeout.py,sha256=cwq4dMk87mJHSBktK1miYJ-85G-3T3RmT20v7SFCpno,10168
pip/_vendor/urllib3/util/url.py,sha256=lCAE7M5myA8EDdW0sJuyyZhVB9K_j38ljWhHAnFaWoE,14296
pip/_vendor/urllib3/util/wait.py,sha256=fOX0_faozG2P7iVojQoE1mbydweNyTcm-hXEfFrTtLI,5403
pip/_vendor/vendor.txt,sha256=EW-E3cE5XEAtVFzGInikArOMDxGP0DLUWzXpY4RZfFY,333
pip/py.typed,sha256=EBVvvPRTn_eIpz5e5QztSCdrMX7Qwd7VP93RSoIlZ2I,286

View File

@ -1,5 +0,0 @@
Wheel-Version: 1.0
Generator: setuptools (75.8.0)
Root-Is-Purelib: true
Tag: py3-none-any

View File

@ -1,3 +0,0 @@
[console_scripts]
pip = pip._internal.cli.main:main
pip3 = pip._internal.cli.main:main

View File

@ -1,13 +0,0 @@
from typing import List, Optional
__version__ = "25.0"
def main(args: Optional[List[str]] = None) -> int:
"""This is an internal API only meant for use by pip's own console scripts.
For additional details, see https://github.com/pypa/pip/issues/7498.
"""
from pip._internal.utils.entrypoints import _wrapper
return _wrapper(args)

View File

@ -1,24 +0,0 @@
import os
import sys
# Remove '' and current working directory from the first entry
# of sys.path, if present to avoid using current directory
# in pip commands check, freeze, install, list and show,
# when invoked as python -m pip <command>
if sys.path[0] in ("", os.getcwd()):
sys.path.pop(0)
# If we are running from a wheel, add the wheel to sys.path
# This allows the usage python pip-*.whl/pip install pip-*.whl
if __package__ == "":
# __file__ is pip-*.whl/pip/__main__.py
# first dirname call strips of '/__main__.py', second strips off '/pip'
# Resulting path is the name of the wheel itself
# Add that to sys.path so we can import pip
path = os.path.dirname(os.path.dirname(__file__))
sys.path.insert(0, path)
if __name__ == "__main__":
from pip._internal.cli.main import main as _main
sys.exit(_main())

View File

@ -1,50 +0,0 @@
"""Execute exactly this copy of pip, within a different environment.
This file is named as it is, to ensure that this module can't be imported via
an import statement.
"""
# /!\ This version compatibility check section must be Python 2 compatible. /!\
import sys
# Copied from pyproject.toml
PYTHON_REQUIRES = (3, 8)
def version_str(version): # type: ignore
return ".".join(str(v) for v in version)
if sys.version_info[:2] < PYTHON_REQUIRES:
raise SystemExit(
"This version of pip does not support python {} (requires >={}).".format(
version_str(sys.version_info[:2]), version_str(PYTHON_REQUIRES)
)
)
# From here on, we can use Python 3 features, but the syntax must remain
# Python 2 compatible.
import runpy # noqa: E402
from importlib.machinery import PathFinder # noqa: E402
from os.path import dirname # noqa: E402
PIP_SOURCES_ROOT = dirname(dirname(__file__))
class PipImportRedirectingFinder:
@classmethod
def find_spec(self, fullname, path=None, target=None): # type: ignore
if fullname != "pip":
return None
spec = PathFinder.find_spec(fullname, [PIP_SOURCES_ROOT], target)
assert spec, (PIP_SOURCES_ROOT, fullname)
return spec
sys.meta_path.insert(0, PipImportRedirectingFinder())
assert __name__ == "__main__", "Cannot run __pip-runner__.py as a non-main module"
runpy.run_module("pip", run_name="__main__", alter_sys=True)

View File

@ -1,18 +0,0 @@
from typing import List, Optional
from pip._internal.utils import _log
# init_logging() must be called before any call to logging.getLogger()
# which happens at import of most modules.
_log.init_logging()
def main(args: Optional[List[str]] = None) -> int:
"""This is preserved for old console scripts that may still be referencing
it.
For additional details, see https://github.com/pypa/pip/issues/7498.
"""
from pip._internal.utils.entrypoints import _wrapper
return _wrapper(args)

View File

@ -1,323 +0,0 @@
"""Build Environment used for isolation during sdist building
"""
import logging
import os
import pathlib
import site
import sys
import textwrap
from collections import OrderedDict
from types import TracebackType
from typing import TYPE_CHECKING, Iterable, List, Optional, Set, Tuple, Type, Union
from pip._vendor.certifi import where
from pip._vendor.packaging.version import Version
from pip import __file__ as pip_location
from pip._internal.cli.spinners import open_spinner
from pip._internal.locations import get_platlib, get_purelib, get_scheme
from pip._internal.metadata import get_default_environment, get_environment
from pip._internal.utils.logging import VERBOSE
from pip._internal.utils.packaging import get_requirement
from pip._internal.utils.subprocess import call_subprocess
from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds
if TYPE_CHECKING:
from pip._internal.index.package_finder import PackageFinder
logger = logging.getLogger(__name__)
def _dedup(a: str, b: str) -> Union[Tuple[str], Tuple[str, str]]:
return (a, b) if a != b else (a,)
class _Prefix:
def __init__(self, path: str) -> None:
self.path = path
self.setup = False
scheme = get_scheme("", prefix=path)
self.bin_dir = scheme.scripts
self.lib_dirs = _dedup(scheme.purelib, scheme.platlib)
def get_runnable_pip() -> str:
"""Get a file to pass to a Python executable, to run the currently-running pip.
This is used to run a pip subprocess, for installing requirements into the build
environment.
"""
source = pathlib.Path(pip_location).resolve().parent
if not source.is_dir():
# This would happen if someone is using pip from inside a zip file. In that
# case, we can use that directly.
return str(source)
return os.fsdecode(source / "__pip-runner__.py")
def _get_system_sitepackages() -> Set[str]:
"""Get system site packages
Usually from site.getsitepackages,
but fallback on `get_purelib()/get_platlib()` if unavailable
(e.g. in a virtualenv created by virtualenv<20)
Returns normalized set of strings.
"""
if hasattr(site, "getsitepackages"):
system_sites = site.getsitepackages()
else:
# virtualenv < 20 overwrites site.py without getsitepackages
# fallback on get_purelib/get_platlib.
# this is known to miss things, but shouldn't in the cases
# where getsitepackages() has been removed (inside a virtualenv)
system_sites = [get_purelib(), get_platlib()]
return {os.path.normcase(path) for path in system_sites}
class BuildEnvironment:
"""Creates and manages an isolated environment to install build deps"""
def __init__(self) -> None:
temp_dir = TempDirectory(kind=tempdir_kinds.BUILD_ENV, globally_managed=True)
self._prefixes = OrderedDict(
(name, _Prefix(os.path.join(temp_dir.path, name)))
for name in ("normal", "overlay")
)
self._bin_dirs: List[str] = []
self._lib_dirs: List[str] = []
for prefix in reversed(list(self._prefixes.values())):
self._bin_dirs.append(prefix.bin_dir)
self._lib_dirs.extend(prefix.lib_dirs)
# Customize site to:
# - ensure .pth files are honored
# - prevent access to system site packages
system_sites = _get_system_sitepackages()
self._site_dir = os.path.join(temp_dir.path, "site")
if not os.path.exists(self._site_dir):
os.mkdir(self._site_dir)
with open(
os.path.join(self._site_dir, "sitecustomize.py"), "w", encoding="utf-8"
) as fp:
fp.write(
textwrap.dedent(
"""
import os, site, sys
# First, drop system-sites related paths.
original_sys_path = sys.path[:]
known_paths = set()
for path in {system_sites!r}:
site.addsitedir(path, known_paths=known_paths)
system_paths = set(
os.path.normcase(path)
for path in sys.path[len(original_sys_path):]
)
original_sys_path = [
path for path in original_sys_path
if os.path.normcase(path) not in system_paths
]
sys.path = original_sys_path
# Second, add lib directories.
# ensuring .pth file are processed.
for path in {lib_dirs!r}:
assert not path in sys.path
site.addsitedir(path)
"""
).format(system_sites=system_sites, lib_dirs=self._lib_dirs)
)
def __enter__(self) -> None:
self._save_env = {
name: os.environ.get(name, None)
for name in ("PATH", "PYTHONNOUSERSITE", "PYTHONPATH")
}
path = self._bin_dirs[:]
old_path = self._save_env["PATH"]
if old_path:
path.extend(old_path.split(os.pathsep))
pythonpath = [self._site_dir]
os.environ.update(
{
"PATH": os.pathsep.join(path),
"PYTHONNOUSERSITE": "1",
"PYTHONPATH": os.pathsep.join(pythonpath),
}
)
def __exit__(
self,
exc_type: Optional[Type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType],
) -> None:
for varname, old_value in self._save_env.items():
if old_value is None:
os.environ.pop(varname, None)
else:
os.environ[varname] = old_value
def check_requirements(
self, reqs: Iterable[str]
) -> Tuple[Set[Tuple[str, str]], Set[str]]:
"""Return 2 sets:
- conflicting requirements: set of (installed, wanted) reqs tuples
- missing requirements: set of reqs
"""
missing = set()
conflicting = set()
if reqs:
env = (
get_environment(self._lib_dirs)
if hasattr(self, "_lib_dirs")
else get_default_environment()
)
for req_str in reqs:
req = get_requirement(req_str)
# We're explicitly evaluating with an empty extra value, since build
# environments are not provided any mechanism to select specific extras.
if req.marker is not None and not req.marker.evaluate({"extra": ""}):
continue
dist = env.get_distribution(req.name)
if not dist:
missing.add(req_str)
continue
if isinstance(dist.version, Version):
installed_req_str = f"{req.name}=={dist.version}"
else:
installed_req_str = f"{req.name}==={dist.version}"
if not req.specifier.contains(dist.version, prereleases=True):
conflicting.add((installed_req_str, req_str))
# FIXME: Consider direct URL?
return conflicting, missing
def install_requirements(
self,
finder: "PackageFinder",
requirements: Iterable[str],
prefix_as_string: str,
*,
kind: str,
) -> None:
prefix = self._prefixes[prefix_as_string]
assert not prefix.setup
prefix.setup = True
if not requirements:
return
self._install_requirements(
get_runnable_pip(),
finder,
requirements,
prefix,
kind=kind,
)
@staticmethod
def _install_requirements(
pip_runnable: str,
finder: "PackageFinder",
requirements: Iterable[str],
prefix: _Prefix,
*,
kind: str,
) -> None:
args: List[str] = [
sys.executable,
pip_runnable,
"install",
"--ignore-installed",
"--no-user",
"--prefix",
prefix.path,
"--no-warn-script-location",
"--disable-pip-version-check",
# The prefix specified two lines above, thus
# target from config file or env var should be ignored
"--target",
"",
"--cert",
finder.custom_cert or where(),
]
if logger.getEffectiveLevel() <= logging.DEBUG:
args.append("-vv")
elif logger.getEffectiveLevel() <= VERBOSE:
args.append("-v")
for format_control in ("no_binary", "only_binary"):
formats = getattr(finder.format_control, format_control)
args.extend(
(
"--" + format_control.replace("_", "-"),
",".join(sorted(formats or {":none:"})),
)
)
index_urls = finder.index_urls
if index_urls:
args.extend(["-i", index_urls[0]])
for extra_index in index_urls[1:]:
args.extend(["--extra-index-url", extra_index])
else:
args.append("--no-index")
for link in finder.find_links:
args.extend(["--find-links", link])
if finder.proxy:
args.extend(["--proxy", finder.proxy])
for host in finder.trusted_hosts:
args.extend(["--trusted-host", host])
if finder.client_cert:
args.extend(["--client-cert", finder.client_cert])
if finder.allow_all_prereleases:
args.append("--pre")
if finder.prefer_binary:
args.append("--prefer-binary")
args.append("--")
args.extend(requirements)
with open_spinner(f"Installing {kind}") as spinner:
call_subprocess(
args,
command_desc=f"pip subprocess to install {kind}",
spinner=spinner,
)
class NoOpBuildEnvironment(BuildEnvironment):
"""A no-op drop-in replacement for BuildEnvironment"""
def __init__(self) -> None:
pass
def __enter__(self) -> None:
pass
def __exit__(
self,
exc_type: Optional[Type[BaseException]],
exc_val: Optional[BaseException],
exc_tb: Optional[TracebackType],
) -> None:
pass
def cleanup(self) -> None:
pass
def install_requirements(
self,
finder: "PackageFinder",
requirements: Iterable[str],
prefix_as_string: str,
*,
kind: str,
) -> None:
raise NotImplementedError()

View File

@ -1,290 +0,0 @@
"""Cache Management
"""
import hashlib
import json
import logging
import os
from pathlib import Path
from typing import Any, Dict, List, Optional
from pip._vendor.packaging.tags import Tag, interpreter_name, interpreter_version
from pip._vendor.packaging.utils import canonicalize_name
from pip._internal.exceptions import InvalidWheelFilename
from pip._internal.models.direct_url import DirectUrl
from pip._internal.models.link import Link
from pip._internal.models.wheel import Wheel
from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds
from pip._internal.utils.urls import path_to_url
logger = logging.getLogger(__name__)
ORIGIN_JSON_NAME = "origin.json"
def _hash_dict(d: Dict[str, str]) -> str:
"""Return a stable sha224 of a dictionary."""
s = json.dumps(d, sort_keys=True, separators=(",", ":"), ensure_ascii=True)
return hashlib.sha224(s.encode("ascii")).hexdigest()
class Cache:
"""An abstract class - provides cache directories for data from links
:param cache_dir: The root of the cache.
"""
def __init__(self, cache_dir: str) -> None:
super().__init__()
assert not cache_dir or os.path.isabs(cache_dir)
self.cache_dir = cache_dir or None
def _get_cache_path_parts(self, link: Link) -> List[str]:
"""Get parts of part that must be os.path.joined with cache_dir"""
# We want to generate an url to use as our cache key, we don't want to
# just reuse the URL because it might have other items in the fragment
# and we don't care about those.
key_parts = {"url": link.url_without_fragment}
if link.hash_name is not None and link.hash is not None:
key_parts[link.hash_name] = link.hash
if link.subdirectory_fragment:
key_parts["subdirectory"] = link.subdirectory_fragment
# Include interpreter name, major and minor version in cache key
# to cope with ill-behaved sdists that build a different wheel
# depending on the python version their setup.py is being run on,
# and don't encode the difference in compatibility tags.
# https://github.com/pypa/pip/issues/7296
key_parts["interpreter_name"] = interpreter_name()
key_parts["interpreter_version"] = interpreter_version()
# Encode our key url with sha224, we'll use this because it has similar
# security properties to sha256, but with a shorter total output (and
# thus less secure). However the differences don't make a lot of
# difference for our use case here.
hashed = _hash_dict(key_parts)
# We want to nest the directories some to prevent having a ton of top
# level directories where we might run out of sub directories on some
# FS.
parts = [hashed[:2], hashed[2:4], hashed[4:6], hashed[6:]]
return parts
def _get_candidates(self, link: Link, canonical_package_name: str) -> List[Any]:
can_not_cache = not self.cache_dir or not canonical_package_name or not link
if can_not_cache:
return []
path = self.get_path_for_link(link)
if os.path.isdir(path):
return [(candidate, path) for candidate in os.listdir(path)]
return []
def get_path_for_link(self, link: Link) -> str:
"""Return a directory to store cached items in for link."""
raise NotImplementedError()
def get(
self,
link: Link,
package_name: Optional[str],
supported_tags: List[Tag],
) -> Link:
"""Returns a link to a cached item if it exists, otherwise returns the
passed link.
"""
raise NotImplementedError()
class SimpleWheelCache(Cache):
"""A cache of wheels for future installs."""
def __init__(self, cache_dir: str) -> None:
super().__init__(cache_dir)
def get_path_for_link(self, link: Link) -> str:
"""Return a directory to store cached wheels for link
Because there are M wheels for any one sdist, we provide a directory
to cache them in, and then consult that directory when looking up
cache hits.
We only insert things into the cache if they have plausible version
numbers, so that we don't contaminate the cache with things that were
not unique. E.g. ./package might have dozens of installs done for it
and build a version of 0.0...and if we built and cached a wheel, we'd
end up using the same wheel even if the source has been edited.
:param link: The link of the sdist for which this will cache wheels.
"""
parts = self._get_cache_path_parts(link)
assert self.cache_dir
# Store wheels within the root cache_dir
return os.path.join(self.cache_dir, "wheels", *parts)
def get(
self,
link: Link,
package_name: Optional[str],
supported_tags: List[Tag],
) -> Link:
candidates = []
if not package_name:
return link
canonical_package_name = canonicalize_name(package_name)
for wheel_name, wheel_dir in self._get_candidates(link, canonical_package_name):
try:
wheel = Wheel(wheel_name)
except InvalidWheelFilename:
continue
if canonicalize_name(wheel.name) != canonical_package_name:
logger.debug(
"Ignoring cached wheel %s for %s as it "
"does not match the expected distribution name %s.",
wheel_name,
link,
package_name,
)
continue
if not wheel.supported(supported_tags):
# Built for a different python/arch/etc
continue
candidates.append(
(
wheel.support_index_min(supported_tags),
wheel_name,
wheel_dir,
)
)
if not candidates:
return link
_, wheel_name, wheel_dir = min(candidates)
return Link(path_to_url(os.path.join(wheel_dir, wheel_name)))
class EphemWheelCache(SimpleWheelCache):
"""A SimpleWheelCache that creates it's own temporary cache directory"""
def __init__(self) -> None:
self._temp_dir = TempDirectory(
kind=tempdir_kinds.EPHEM_WHEEL_CACHE,
globally_managed=True,
)
super().__init__(self._temp_dir.path)
class CacheEntry:
def __init__(
self,
link: Link,
persistent: bool,
):
self.link = link
self.persistent = persistent
self.origin: Optional[DirectUrl] = None
origin_direct_url_path = Path(self.link.file_path).parent / ORIGIN_JSON_NAME
if origin_direct_url_path.exists():
try:
self.origin = DirectUrl.from_json(
origin_direct_url_path.read_text(encoding="utf-8")
)
except Exception as e:
logger.warning(
"Ignoring invalid cache entry origin file %s for %s (%s)",
origin_direct_url_path,
link.filename,
e,
)
class WheelCache(Cache):
"""Wraps EphemWheelCache and SimpleWheelCache into a single Cache
This Cache allows for gracefully degradation, using the ephem wheel cache
when a certain link is not found in the simple wheel cache first.
"""
def __init__(self, cache_dir: str) -> None:
super().__init__(cache_dir)
self._wheel_cache = SimpleWheelCache(cache_dir)
self._ephem_cache = EphemWheelCache()
def get_path_for_link(self, link: Link) -> str:
return self._wheel_cache.get_path_for_link(link)
def get_ephem_path_for_link(self, link: Link) -> str:
return self._ephem_cache.get_path_for_link(link)
def get(
self,
link: Link,
package_name: Optional[str],
supported_tags: List[Tag],
) -> Link:
cache_entry = self.get_cache_entry(link, package_name, supported_tags)
if cache_entry is None:
return link
return cache_entry.link
def get_cache_entry(
self,
link: Link,
package_name: Optional[str],
supported_tags: List[Tag],
) -> Optional[CacheEntry]:
"""Returns a CacheEntry with a link to a cached item if it exists or
None. The cache entry indicates if the item was found in the persistent
or ephemeral cache.
"""
retval = self._wheel_cache.get(
link=link,
package_name=package_name,
supported_tags=supported_tags,
)
if retval is not link:
return CacheEntry(retval, persistent=True)
retval = self._ephem_cache.get(
link=link,
package_name=package_name,
supported_tags=supported_tags,
)
if retval is not link:
return CacheEntry(retval, persistent=False)
return None
@staticmethod
def record_download_origin(cache_dir: str, download_info: DirectUrl) -> None:
origin_path = Path(cache_dir) / ORIGIN_JSON_NAME
if origin_path.exists():
try:
origin = DirectUrl.from_json(origin_path.read_text(encoding="utf-8"))
except Exception as e:
logger.warning(
"Could not read origin file %s in cache entry (%s). "
"Will attempt to overwrite it.",
origin_path,
e,
)
else:
# TODO: use DirectUrl.equivalent when
# https://github.com/pypa/pip/pull/10564 is merged.
if origin.url != download_info.url:
logger.warning(
"Origin URL %s in cache entry %s does not match download URL "
"%s. This is likely a pip bug or a cache corruption issue. "
"Will overwrite it with the new value.",
origin.url,
cache_dir,
download_info.url,
)
origin_path.write_text(download_info.to_json(), encoding="utf-8")

View File

@ -1,4 +0,0 @@
"""Subpackage containing all of pip's command line interface related code
"""
# This file intentionally does not import submodules

View File

@ -1,176 +0,0 @@
"""Logic that powers autocompletion installed by ``pip completion``.
"""
import optparse
import os
import sys
from itertools import chain
from typing import Any, Iterable, List, Optional
from pip._internal.cli.main_parser import create_main_parser
from pip._internal.commands import commands_dict, create_command
from pip._internal.metadata import get_default_environment
def autocomplete() -> None:
"""Entry Point for completion of main and subcommand options."""
# Don't complete if user hasn't sourced bash_completion file.
if "PIP_AUTO_COMPLETE" not in os.environ:
return
# Don't complete if autocompletion environment variables
# are not present
if not os.environ.get("COMP_WORDS") or not os.environ.get("COMP_CWORD"):
return
cwords = os.environ["COMP_WORDS"].split()[1:]
cword = int(os.environ["COMP_CWORD"])
try:
current = cwords[cword - 1]
except IndexError:
current = ""
parser = create_main_parser()
subcommands = list(commands_dict)
options = []
# subcommand
subcommand_name: Optional[str] = None
for word in cwords:
if word in subcommands:
subcommand_name = word
break
# subcommand options
if subcommand_name is not None:
# special case: 'help' subcommand has no options
if subcommand_name == "help":
sys.exit(1)
# special case: list locally installed dists for show and uninstall
should_list_installed = not current.startswith("-") and subcommand_name in [
"show",
"uninstall",
]
if should_list_installed:
env = get_default_environment()
lc = current.lower()
installed = [
dist.canonical_name
for dist in env.iter_installed_distributions(local_only=True)
if dist.canonical_name.startswith(lc)
and dist.canonical_name not in cwords[1:]
]
# if there are no dists installed, fall back to option completion
if installed:
for dist in installed:
print(dist)
sys.exit(1)
should_list_installables = (
not current.startswith("-") and subcommand_name == "install"
)
if should_list_installables:
for path in auto_complete_paths(current, "path"):
print(path)
sys.exit(1)
subcommand = create_command(subcommand_name)
for opt in subcommand.parser.option_list_all:
if opt.help != optparse.SUPPRESS_HELP:
options += [
(opt_str, opt.nargs) for opt_str in opt._long_opts + opt._short_opts
]
# filter out previously specified options from available options
prev_opts = [x.split("=")[0] for x in cwords[1 : cword - 1]]
options = [(x, v) for (x, v) in options if x not in prev_opts]
# filter options by current input
options = [(k, v) for k, v in options if k.startswith(current)]
# get completion type given cwords and available subcommand options
completion_type = get_path_completion_type(
cwords,
cword,
subcommand.parser.option_list_all,
)
# get completion files and directories if ``completion_type`` is
# ``<file>``, ``<dir>`` or ``<path>``
if completion_type:
paths = auto_complete_paths(current, completion_type)
options = [(path, 0) for path in paths]
for option in options:
opt_label = option[0]
# append '=' to options which require args
if option[1] and option[0][:2] == "--":
opt_label += "="
print(opt_label)
else:
# show main parser options only when necessary
opts = [i.option_list for i in parser.option_groups]
opts.append(parser.option_list)
flattened_opts = chain.from_iterable(opts)
if current.startswith("-"):
for opt in flattened_opts:
if opt.help != optparse.SUPPRESS_HELP:
subcommands += opt._long_opts + opt._short_opts
else:
# get completion type given cwords and all available options
completion_type = get_path_completion_type(cwords, cword, flattened_opts)
if completion_type:
subcommands = list(auto_complete_paths(current, completion_type))
print(" ".join([x for x in subcommands if x.startswith(current)]))
sys.exit(1)
def get_path_completion_type(
cwords: List[str], cword: int, opts: Iterable[Any]
) -> Optional[str]:
"""Get the type of path completion (``file``, ``dir``, ``path`` or None)
:param cwords: same as the environmental variable ``COMP_WORDS``
:param cword: same as the environmental variable ``COMP_CWORD``
:param opts: The available options to check
:return: path completion type (``file``, ``dir``, ``path`` or None)
"""
if cword < 2 or not cwords[cword - 2].startswith("-"):
return None
for opt in opts:
if opt.help == optparse.SUPPRESS_HELP:
continue
for o in str(opt).split("/"):
if cwords[cword - 2].split("=")[0] == o:
if not opt.metavar or any(
x in ("path", "file", "dir") for x in opt.metavar.split("/")
):
return opt.metavar
return None
def auto_complete_paths(current: str, completion_type: str) -> Iterable[str]:
"""If ``completion_type`` is ``file`` or ``path``, list all regular files
and directories starting with ``current``; otherwise only list directories
starting with ``current``.
:param current: The word to be completed
:param completion_type: path completion type(``file``, ``path`` or ``dir``)
:return: A generator of regular files and/or directories
"""
directory, filename = os.path.split(current)
current_path = os.path.abspath(directory)
# Don't complete paths if they can't be accessed
if not os.access(current_path, os.R_OK):
return
filename = os.path.normcase(filename)
# list all files that start with ``filename``
file_list = (
x for x in os.listdir(current_path) if os.path.normcase(x).startswith(filename)
)
for f in file_list:
opt = os.path.join(current_path, f)
comp_file = os.path.normcase(os.path.join(directory, f))
# complete regular files when there is not ``<dir>`` after option
# complete directories when there is ``<file>``, ``<path>`` or
# ``<dir>``after option
if completion_type != "dir" and os.path.isfile(opt):
yield comp_file
elif os.path.isdir(opt):
yield os.path.join(comp_file, "")

View File

@ -1,240 +0,0 @@
"""Base Command class, and related routines"""
import logging
import logging.config
import optparse
import os
import sys
import traceback
from optparse import Values
from typing import List, Optional, Tuple
from pip._vendor.rich import reconfigure
from pip._vendor.rich import traceback as rich_traceback
from pip._internal.cli import cmdoptions
from pip._internal.cli.command_context import CommandContextMixIn
from pip._internal.cli.parser import ConfigOptionParser, UpdatingDefaultsHelpFormatter
from pip._internal.cli.status_codes import (
ERROR,
PREVIOUS_BUILD_DIR_ERROR,
UNKNOWN_ERROR,
VIRTUALENV_NOT_FOUND,
)
from pip._internal.exceptions import (
BadCommand,
CommandError,
DiagnosticPipError,
InstallationError,
NetworkConnectionError,
PreviousBuildDirError,
)
from pip._internal.utils.deprecation import deprecated
from pip._internal.utils.filesystem import check_path_owner
from pip._internal.utils.logging import BrokenStdoutLoggingError, setup_logging
from pip._internal.utils.misc import get_prog, normalize_path
from pip._internal.utils.temp_dir import TempDirectoryTypeRegistry as TempDirRegistry
from pip._internal.utils.temp_dir import global_tempdir_manager, tempdir_registry
from pip._internal.utils.virtualenv import running_under_virtualenv
__all__ = ["Command"]
logger = logging.getLogger(__name__)
class Command(CommandContextMixIn):
usage: str = ""
ignore_require_venv: bool = False
def __init__(self, name: str, summary: str, isolated: bool = False) -> None:
super().__init__()
self.name = name
self.summary = summary
self.parser = ConfigOptionParser(
usage=self.usage,
prog=f"{get_prog()} {name}",
formatter=UpdatingDefaultsHelpFormatter(),
add_help_option=False,
name=name,
description=self.__doc__,
isolated=isolated,
)
self.tempdir_registry: Optional[TempDirRegistry] = None
# Commands should add options to this option group
optgroup_name = f"{self.name.capitalize()} Options"
self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name)
# Add the general options
gen_opts = cmdoptions.make_option_group(
cmdoptions.general_group,
self.parser,
)
self.parser.add_option_group(gen_opts)
self.add_options()
def add_options(self) -> None:
pass
def handle_pip_version_check(self, options: Values) -> None:
"""
This is a no-op so that commands by default do not do the pip version
check.
"""
# Make sure we do the pip version check if the index_group options
# are present.
assert not hasattr(options, "no_index")
def run(self, options: Values, args: List[str]) -> int:
raise NotImplementedError
def _run_wrapper(self, level_number: int, options: Values, args: List[str]) -> int:
def _inner_run() -> int:
try:
return self.run(options, args)
finally:
self.handle_pip_version_check(options)
if options.debug_mode:
rich_traceback.install(show_locals=True)
return _inner_run()
try:
status = _inner_run()
assert isinstance(status, int)
return status
except DiagnosticPipError as exc:
logger.error("%s", exc, extra={"rich": True})
logger.debug("Exception information:", exc_info=True)
return ERROR
except PreviousBuildDirError as exc:
logger.critical(str(exc))
logger.debug("Exception information:", exc_info=True)
return PREVIOUS_BUILD_DIR_ERROR
except (
InstallationError,
BadCommand,
NetworkConnectionError,
) as exc:
logger.critical(str(exc))
logger.debug("Exception information:", exc_info=True)
return ERROR
except CommandError as exc:
logger.critical("%s", exc)
logger.debug("Exception information:", exc_info=True)
return ERROR
except BrokenStdoutLoggingError:
# Bypass our logger and write any remaining messages to
# stderr because stdout no longer works.
print("ERROR: Pipe to stdout was broken", file=sys.stderr)
if level_number <= logging.DEBUG:
traceback.print_exc(file=sys.stderr)
return ERROR
except KeyboardInterrupt:
logger.critical("Operation cancelled by user")
logger.debug("Exception information:", exc_info=True)
return ERROR
except BaseException:
logger.critical("Exception:", exc_info=True)
return UNKNOWN_ERROR
def parse_args(self, args: List[str]) -> Tuple[Values, List[str]]:
# factored out for testability
return self.parser.parse_args(args)
def main(self, args: List[str]) -> int:
try:
with self.main_context():
return self._main(args)
finally:
logging.shutdown()
def _main(self, args: List[str]) -> int:
# We must initialize this before the tempdir manager, otherwise the
# configuration would not be accessible by the time we clean up the
# tempdir manager.
self.tempdir_registry = self.enter_context(tempdir_registry())
# Intentionally set as early as possible so globally-managed temporary
# directories are available to the rest of the code.
self.enter_context(global_tempdir_manager())
options, args = self.parse_args(args)
# Set verbosity so that it can be used elsewhere.
self.verbosity = options.verbose - options.quiet
reconfigure(no_color=options.no_color)
level_number = setup_logging(
verbosity=self.verbosity,
no_color=options.no_color,
user_log_file=options.log,
)
always_enabled_features = set(options.features_enabled) & set(
cmdoptions.ALWAYS_ENABLED_FEATURES
)
if always_enabled_features:
logger.warning(
"The following features are always enabled: %s. ",
", ".join(sorted(always_enabled_features)),
)
# Make sure that the --python argument isn't specified after the
# subcommand. We can tell, because if --python was specified,
# we should only reach this point if we're running in the created
# subprocess, which has the _PIP_RUNNING_IN_SUBPROCESS environment
# variable set.
if options.python and "_PIP_RUNNING_IN_SUBPROCESS" not in os.environ:
logger.critical(
"The --python option must be placed before the pip subcommand name"
)
sys.exit(ERROR)
# TODO: Try to get these passing down from the command?
# without resorting to os.environ to hold these.
# This also affects isolated builds and it should.
if options.no_input:
os.environ["PIP_NO_INPUT"] = "1"
if options.exists_action:
os.environ["PIP_EXISTS_ACTION"] = " ".join(options.exists_action)
if options.require_venv and not self.ignore_require_venv:
# If a venv is required check if it can really be found
if not running_under_virtualenv():
logger.critical("Could not find an activated virtualenv (required).")
sys.exit(VIRTUALENV_NOT_FOUND)
if options.cache_dir:
options.cache_dir = normalize_path(options.cache_dir)
if not check_path_owner(options.cache_dir):
logger.warning(
"The directory '%s' or its parent directory is not owned "
"or is not writable by the current user. The cache "
"has been disabled. Check the permissions and owner of "
"that directory. If executing pip with sudo, you should "
"use sudo's -H flag.",
options.cache_dir,
)
options.cache_dir = None
if options.no_python_version_warning:
deprecated(
reason="--no-python-version-warning is deprecated.",
replacement="to remove the flag as it's a no-op",
gone_in="25.1",
issue=13154,
)
return self._run_wrapper(level_number, options, args)

View File

@ -1,27 +0,0 @@
from contextlib import ExitStack, contextmanager
from typing import ContextManager, Generator, TypeVar
_T = TypeVar("_T", covariant=True)
class CommandContextMixIn:
def __init__(self) -> None:
super().__init__()
self._in_main_context = False
self._main_context = ExitStack()
@contextmanager
def main_context(self) -> Generator[None, None, None]:
assert not self._in_main_context
self._in_main_context = True
try:
with self._main_context:
yield
finally:
self._in_main_context = False
def enter_context(self, context_provider: ContextManager[_T]) -> _T:
assert self._in_main_context
return self._main_context.enter_context(context_provider)

View File

@ -1,171 +0,0 @@
"""
Contains command classes which may interact with an index / the network.
Unlike its sister module, req_command, this module still uses lazy imports
so commands which don't always hit the network (e.g. list w/o --outdated or
--uptodate) don't need waste time importing PipSession and friends.
"""
import logging
import os
import sys
from optparse import Values
from typing import TYPE_CHECKING, List, Optional
from pip._vendor import certifi
from pip._internal.cli.base_command import Command
from pip._internal.cli.command_context import CommandContextMixIn
if TYPE_CHECKING:
from ssl import SSLContext
from pip._internal.network.session import PipSession
logger = logging.getLogger(__name__)
def _create_truststore_ssl_context() -> Optional["SSLContext"]:
if sys.version_info < (3, 10):
logger.debug("Disabling truststore because Python version isn't 3.10+")
return None
try:
import ssl
except ImportError:
logger.warning("Disabling truststore since ssl support is missing")
return None
try:
from pip._vendor import truststore
except ImportError:
logger.warning("Disabling truststore because platform isn't supported")
return None
ctx = truststore.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ctx.load_verify_locations(certifi.where())
return ctx
class SessionCommandMixin(CommandContextMixIn):
"""
A class mixin for command classes needing _build_session().
"""
def __init__(self) -> None:
super().__init__()
self._session: Optional[PipSession] = None
@classmethod
def _get_index_urls(cls, options: Values) -> Optional[List[str]]:
"""Return a list of index urls from user-provided options."""
index_urls = []
if not getattr(options, "no_index", False):
url = getattr(options, "index_url", None)
if url:
index_urls.append(url)
urls = getattr(options, "extra_index_urls", None)
if urls:
index_urls.extend(urls)
# Return None rather than an empty list
return index_urls or None
def get_default_session(self, options: Values) -> "PipSession":
"""Get a default-managed session."""
if self._session is None:
self._session = self.enter_context(self._build_session(options))
# there's no type annotation on requests.Session, so it's
# automatically ContextManager[Any] and self._session becomes Any,
# then https://github.com/python/mypy/issues/7696 kicks in
assert self._session is not None
return self._session
def _build_session(
self,
options: Values,
retries: Optional[int] = None,
timeout: Optional[int] = None,
) -> "PipSession":
from pip._internal.network.session import PipSession
cache_dir = options.cache_dir
assert not cache_dir or os.path.isabs(cache_dir)
if "legacy-certs" not in options.deprecated_features_enabled:
ssl_context = _create_truststore_ssl_context()
else:
ssl_context = None
session = PipSession(
cache=os.path.join(cache_dir, "http-v2") if cache_dir else None,
retries=retries if retries is not None else options.retries,
trusted_hosts=options.trusted_hosts,
index_urls=self._get_index_urls(options),
ssl_context=ssl_context,
)
# Handle custom ca-bundles from the user
if options.cert:
session.verify = options.cert
# Handle SSL client certificate
if options.client_cert:
session.cert = options.client_cert
# Handle timeouts
if options.timeout or timeout:
session.timeout = timeout if timeout is not None else options.timeout
# Handle configured proxies
if options.proxy:
session.proxies = {
"http": options.proxy,
"https": options.proxy,
}
session.trust_env = False
session.pip_proxy = options.proxy
# Determine if we can prompt the user for authentication or not
session.auth.prompting = not options.no_input
session.auth.keyring_provider = options.keyring_provider
return session
def _pip_self_version_check(session: "PipSession", options: Values) -> None:
from pip._internal.self_outdated_check import pip_self_version_check as check
check(session, options)
class IndexGroupCommand(Command, SessionCommandMixin):
"""
Abstract base class for commands with the index_group options.
This also corresponds to the commands that permit the pip version check.
"""
def handle_pip_version_check(self, options: Values) -> None:
"""
Do the pip version check if not disabled.
This overrides the default behavior of not doing the check.
"""
# Make sure the index_group options are present.
assert hasattr(options, "no_index")
if options.disable_pip_version_check or options.no_index:
return
try:
# Otherwise, check if we're using the latest version of pip available.
session = self._build_session(
options,
retries=0,
timeout=min(5, options.timeout),
)
with session:
_pip_self_version_check(session, options)
except Exception:
logger.warning("There was an error checking the latest version of pip.")
logger.debug("See below for error", exc_info=True)

View File

@ -1,80 +0,0 @@
"""Primary application entrypoint.
"""
import locale
import logging
import os
import sys
import warnings
from typing import List, Optional
from pip._internal.cli.autocompletion import autocomplete
from pip._internal.cli.main_parser import parse_command
from pip._internal.commands import create_command
from pip._internal.exceptions import PipError
from pip._internal.utils import deprecation
logger = logging.getLogger(__name__)
# Do not import and use main() directly! Using it directly is actively
# discouraged by pip's maintainers. The name, location and behavior of
# this function is subject to change, so calling it directly is not
# portable across different pip versions.
# In addition, running pip in-process is unsupported and unsafe. This is
# elaborated in detail at
# https://pip.pypa.io/en/stable/user_guide/#using-pip-from-your-program.
# That document also provides suggestions that should work for nearly
# all users that are considering importing and using main() directly.
# However, we know that certain users will still want to invoke pip
# in-process. If you understand and accept the implications of using pip
# in an unsupported manner, the best approach is to use runpy to avoid
# depending on the exact location of this entry point.
# The following example shows how to use runpy to invoke pip in that
# case:
#
# sys.argv = ["pip", your, args, here]
# runpy.run_module("pip", run_name="__main__")
#
# Note that this will exit the process after running, unlike a direct
# call to main. As it is not safe to do any processing after calling
# main, this should not be an issue in practice.
def main(args: Optional[List[str]] = None) -> int:
if args is None:
args = sys.argv[1:]
# Suppress the pkg_resources deprecation warning
# Note - we use a module of .*pkg_resources to cover
# the normal case (pip._vendor.pkg_resources) and the
# devendored case (a bare pkg_resources)
warnings.filterwarnings(
action="ignore", category=DeprecationWarning, module=".*pkg_resources"
)
# Configure our deprecation warnings to be sent through loggers
deprecation.install_warning_logger()
autocomplete()
try:
cmd_name, cmd_args = parse_command(args)
except PipError as exc:
sys.stderr.write(f"ERROR: {exc}")
sys.stderr.write(os.linesep)
sys.exit(1)
# Needed for locale.getpreferredencoding(False) to work
# in pip._internal.utils.encoding.auto_decode
try:
locale.setlocale(locale.LC_ALL, "")
except locale.Error as e:
# setlocale can apparently crash if locale are uninitialized
logger.debug("Ignoring error %s when setting locale", e)
command = create_command(cmd_name, isolated=("--isolated" in cmd_args))
return command.main(cmd_args)

View File

@ -1,134 +0,0 @@
"""A single place for constructing and exposing the main parser
"""
import os
import subprocess
import sys
from typing import List, Optional, Tuple
from pip._internal.build_env import get_runnable_pip
from pip._internal.cli import cmdoptions
from pip._internal.cli.parser import ConfigOptionParser, UpdatingDefaultsHelpFormatter
from pip._internal.commands import commands_dict, get_similar_commands
from pip._internal.exceptions import CommandError
from pip._internal.utils.misc import get_pip_version, get_prog
__all__ = ["create_main_parser", "parse_command"]
def create_main_parser() -> ConfigOptionParser:
"""Creates and returns the main parser for pip's CLI"""
parser = ConfigOptionParser(
usage="\n%prog <command> [options]",
add_help_option=False,
formatter=UpdatingDefaultsHelpFormatter(),
name="global",
prog=get_prog(),
)
parser.disable_interspersed_args()
parser.version = get_pip_version()
# add the general options
gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, parser)
parser.add_option_group(gen_opts)
# so the help formatter knows
parser.main = True # type: ignore
# create command listing for description
description = [""] + [
f"{name:27} {command_info.summary}"
for name, command_info in commands_dict.items()
]
parser.description = "\n".join(description)
return parser
def identify_python_interpreter(python: str) -> Optional[str]:
# If the named file exists, use it.
# If it's a directory, assume it's a virtual environment and
# look for the environment's Python executable.
if os.path.exists(python):
if os.path.isdir(python):
# bin/python for Unix, Scripts/python.exe for Windows
# Try both in case of odd cases like cygwin.
for exe in ("bin/python", "Scripts/python.exe"):
py = os.path.join(python, exe)
if os.path.exists(py):
return py
else:
return python
# Could not find the interpreter specified
return None
def parse_command(args: List[str]) -> Tuple[str, List[str]]:
parser = create_main_parser()
# Note: parser calls disable_interspersed_args(), so the result of this
# call is to split the initial args into the general options before the
# subcommand and everything else.
# For example:
# args: ['--timeout=5', 'install', '--user', 'INITools']
# general_options: ['--timeout==5']
# args_else: ['install', '--user', 'INITools']
general_options, args_else = parser.parse_args(args)
# --python
if general_options.python and "_PIP_RUNNING_IN_SUBPROCESS" not in os.environ:
# Re-invoke pip using the specified Python interpreter
interpreter = identify_python_interpreter(general_options.python)
if interpreter is None:
raise CommandError(
f"Could not locate Python interpreter {general_options.python}"
)
pip_cmd = [
interpreter,
get_runnable_pip(),
]
pip_cmd.extend(args)
# Set a flag so the child doesn't re-invoke itself, causing
# an infinite loop.
os.environ["_PIP_RUNNING_IN_SUBPROCESS"] = "1"
returncode = 0
try:
proc = subprocess.run(pip_cmd)
returncode = proc.returncode
except (subprocess.SubprocessError, OSError) as exc:
raise CommandError(f"Failed to run pip under {interpreter}: {exc}")
sys.exit(returncode)
# --version
if general_options.version:
sys.stdout.write(parser.version)
sys.stdout.write(os.linesep)
sys.exit()
# pip || pip help -> print_help()
if not args_else or (args_else[0] == "help" and len(args_else) == 1):
parser.print_help()
sys.exit()
# the subcommand name
cmd_name = args_else[0]
if cmd_name not in commands_dict:
guess = get_similar_commands(cmd_name)
msg = [f'unknown command "{cmd_name}"']
if guess:
msg.append(f'maybe you meant "{guess}"')
raise CommandError(" - ".join(msg))
# all the args without the subcommand
cmd_args = args[:]
cmd_args.remove(cmd_name)
return cmd_name, cmd_args

View File

@ -1,294 +0,0 @@
"""Base option parser setup"""
import logging
import optparse
import shutil
import sys
import textwrap
from contextlib import suppress
from typing import Any, Dict, Generator, List, NoReturn, Optional, Tuple
from pip._internal.cli.status_codes import UNKNOWN_ERROR
from pip._internal.configuration import Configuration, ConfigurationError
from pip._internal.utils.misc import redact_auth_from_url, strtobool
logger = logging.getLogger(__name__)
class PrettyHelpFormatter(optparse.IndentedHelpFormatter):
"""A prettier/less verbose help formatter for optparse."""
def __init__(self, *args: Any, **kwargs: Any) -> None:
# help position must be aligned with __init__.parseopts.description
kwargs["max_help_position"] = 30
kwargs["indent_increment"] = 1
kwargs["width"] = shutil.get_terminal_size()[0] - 2
super().__init__(*args, **kwargs)
def format_option_strings(self, option: optparse.Option) -> str:
return self._format_option_strings(option)
def _format_option_strings(
self, option: optparse.Option, mvarfmt: str = " <{}>", optsep: str = ", "
) -> str:
"""
Return a comma-separated list of option strings and metavars.
:param option: tuple of (short opt, long opt), e.g: ('-f', '--format')
:param mvarfmt: metavar format string
:param optsep: separator
"""
opts = []
if option._short_opts:
opts.append(option._short_opts[0])
if option._long_opts:
opts.append(option._long_opts[0])
if len(opts) > 1:
opts.insert(1, optsep)
if option.takes_value():
assert option.dest is not None
metavar = option.metavar or option.dest.lower()
opts.append(mvarfmt.format(metavar.lower()))
return "".join(opts)
def format_heading(self, heading: str) -> str:
if heading == "Options":
return ""
return heading + ":\n"
def format_usage(self, usage: str) -> str:
"""
Ensure there is only one newline between usage and the first heading
if there is no description.
"""
msg = "\nUsage: {}\n".format(self.indent_lines(textwrap.dedent(usage), " "))
return msg
def format_description(self, description: Optional[str]) -> str:
# leave full control over description to us
if description:
if hasattr(self.parser, "main"):
label = "Commands"
else:
label = "Description"
# some doc strings have initial newlines, some don't
description = description.lstrip("\n")
# some doc strings have final newlines and spaces, some don't
description = description.rstrip()
# dedent, then reindent
description = self.indent_lines(textwrap.dedent(description), " ")
description = f"{label}:\n{description}\n"
return description
else:
return ""
def format_epilog(self, epilog: Optional[str]) -> str:
# leave full control over epilog to us
if epilog:
return epilog
else:
return ""
def indent_lines(self, text: str, indent: str) -> str:
new_lines = [indent + line for line in text.split("\n")]
return "\n".join(new_lines)
class UpdatingDefaultsHelpFormatter(PrettyHelpFormatter):
"""Custom help formatter for use in ConfigOptionParser.
This is updates the defaults before expanding them, allowing
them to show up correctly in the help listing.
Also redact auth from url type options
"""
def expand_default(self, option: optparse.Option) -> str:
default_values = None
if self.parser is not None:
assert isinstance(self.parser, ConfigOptionParser)
self.parser._update_defaults(self.parser.defaults)
assert option.dest is not None
default_values = self.parser.defaults.get(option.dest)
help_text = super().expand_default(option)
if default_values and option.metavar == "URL":
if isinstance(default_values, str):
default_values = [default_values]
# If its not a list, we should abort and just return the help text
if not isinstance(default_values, list):
default_values = []
for val in default_values:
help_text = help_text.replace(val, redact_auth_from_url(val))
return help_text
class CustomOptionParser(optparse.OptionParser):
def insert_option_group(
self, idx: int, *args: Any, **kwargs: Any
) -> optparse.OptionGroup:
"""Insert an OptionGroup at a given position."""
group = self.add_option_group(*args, **kwargs)
self.option_groups.pop()
self.option_groups.insert(idx, group)
return group
@property
def option_list_all(self) -> List[optparse.Option]:
"""Get a list of all options, including those in option groups."""
res = self.option_list[:]
for i in self.option_groups:
res.extend(i.option_list)
return res
class ConfigOptionParser(CustomOptionParser):
"""Custom option parser which updates its defaults by checking the
configuration files and environmental variables"""
def __init__(
self,
*args: Any,
name: str,
isolated: bool = False,
**kwargs: Any,
) -> None:
self.name = name
self.config = Configuration(isolated)
assert self.name
super().__init__(*args, **kwargs)
def check_default(self, option: optparse.Option, key: str, val: Any) -> Any:
try:
return option.check_value(key, val)
except optparse.OptionValueError as exc:
print(f"An error occurred during configuration: {exc}")
sys.exit(3)
def _get_ordered_configuration_items(
self,
) -> Generator[Tuple[str, Any], None, None]:
# Configuration gives keys in an unordered manner. Order them.
override_order = ["global", self.name, ":env:"]
# Pool the options into different groups
section_items: Dict[str, List[Tuple[str, Any]]] = {
name: [] for name in override_order
}
for section_key, val in self.config.items():
# ignore empty values
if not val:
logger.debug(
"Ignoring configuration key '%s' as it's value is empty.",
section_key,
)
continue
section, key = section_key.split(".", 1)
if section in override_order:
section_items[section].append((key, val))
# Yield each group in their override order
for section in override_order:
for key, val in section_items[section]:
yield key, val
def _update_defaults(self, defaults: Dict[str, Any]) -> Dict[str, Any]:
"""Updates the given defaults with values from the config files and
the environ. Does a little special handling for certain types of
options (lists)."""
# Accumulate complex default state.
self.values = optparse.Values(self.defaults)
late_eval = set()
# Then set the options with those values
for key, val in self._get_ordered_configuration_items():
# '--' because configuration supports only long names
option = self.get_option("--" + key)
# Ignore options not present in this parser. E.g. non-globals put
# in [global] by users that want them to apply to all applicable
# commands.
if option is None:
continue
assert option.dest is not None
if option.action in ("store_true", "store_false"):
try:
val = strtobool(val)
except ValueError:
self.error(
f"{val} is not a valid value for {key} option, "
"please specify a boolean value like yes/no, "
"true/false or 1/0 instead."
)
elif option.action == "count":
with suppress(ValueError):
val = strtobool(val)
with suppress(ValueError):
val = int(val)
if not isinstance(val, int) or val < 0:
self.error(
f"{val} is not a valid value for {key} option, "
"please instead specify either a non-negative integer "
"or a boolean value like yes/no or false/true "
"which is equivalent to 1/0."
)
elif option.action == "append":
val = val.split()
val = [self.check_default(option, key, v) for v in val]
elif option.action == "callback":
assert option.callback is not None
late_eval.add(option.dest)
opt_str = option.get_opt_string()
val = option.convert_value(opt_str, val)
# From take_action
args = option.callback_args or ()
kwargs = option.callback_kwargs or {}
option.callback(option, opt_str, val, self, *args, **kwargs)
else:
val = self.check_default(option, key, val)
defaults[option.dest] = val
for key in late_eval:
defaults[key] = getattr(self.values, key)
self.values = None
return defaults
def get_default_values(self) -> optparse.Values:
"""Overriding to make updating the defaults after instantiation of
the option parser possible, _update_defaults() does the dirty work."""
if not self.process_default_values:
# Old, pre-Optik 1.5 behaviour.
return optparse.Values(self.defaults)
# Load the configuration, or error out in case of an error
try:
self.config.load()
except ConfigurationError as err:
self.exit(UNKNOWN_ERROR, str(err))
defaults = self._update_defaults(self.defaults.copy()) # ours
for option in self._get_all_options():
assert option.dest is not None
default = defaults.get(option.dest)
if isinstance(default, str):
opt_str = option.get_opt_string()
defaults[option.dest] = option.check_value(opt_str, default)
return optparse.Values(defaults)
def error(self, msg: str) -> NoReturn:
self.print_usage(sys.stderr)
self.exit(UNKNOWN_ERROR, f"{msg}\n")

View File

@ -1,94 +0,0 @@
import functools
import sys
from typing import Callable, Generator, Iterable, Iterator, Optional, Tuple
from pip._vendor.rich.progress import (
BarColumn,
DownloadColumn,
FileSizeColumn,
Progress,
ProgressColumn,
SpinnerColumn,
TextColumn,
TimeElapsedColumn,
TimeRemainingColumn,
TransferSpeedColumn,
)
from pip._internal.cli.spinners import RateLimiter
from pip._internal.utils.logging import get_indentation
DownloadProgressRenderer = Callable[[Iterable[bytes]], Iterator[bytes]]
def _rich_progress_bar(
iterable: Iterable[bytes],
*,
bar_type: str,
size: Optional[int],
) -> Generator[bytes, None, None]:
assert bar_type == "on", "This should only be used in the default mode."
if not size:
total = float("inf")
columns: Tuple[ProgressColumn, ...] = (
TextColumn("[progress.description]{task.description}"),
SpinnerColumn("line", speed=1.5),
FileSizeColumn(),
TransferSpeedColumn(),
TimeElapsedColumn(),
)
else:
total = size
columns = (
TextColumn("[progress.description]{task.description}"),
BarColumn(),
DownloadColumn(),
TransferSpeedColumn(),
TextColumn("eta"),
TimeRemainingColumn(),
)
progress = Progress(*columns, refresh_per_second=5)
task_id = progress.add_task(" " * (get_indentation() + 2), total=total)
with progress:
for chunk in iterable:
yield chunk
progress.update(task_id, advance=len(chunk))
def _raw_progress_bar(
iterable: Iterable[bytes],
*,
size: Optional[int],
) -> Generator[bytes, None, None]:
def write_progress(current: int, total: int) -> None:
sys.stdout.write(f"Progress {current} of {total}\n")
sys.stdout.flush()
current = 0
total = size or 0
rate_limiter = RateLimiter(0.25)
write_progress(current, total)
for chunk in iterable:
current += len(chunk)
if rate_limiter.ready() or current == total:
write_progress(current, total)
rate_limiter.reset()
yield chunk
def get_download_progress_renderer(
*, bar_type: str, size: Optional[int] = None
) -> DownloadProgressRenderer:
"""Get an object that can be used to render the download progress.
Returns a callable, that takes an iterable to "wrap".
"""
if bar_type == "on":
return functools.partial(_rich_progress_bar, bar_type=bar_type, size=size)
elif bar_type == "raw":
return functools.partial(_raw_progress_bar, size=size)
else:
return iter # no-op, when passed an iterator

View File

@ -1,329 +0,0 @@
"""Contains the RequirementCommand base class.
This class is in a separate module so the commands that do not always
need PackageFinder capability don't unnecessarily import the
PackageFinder machinery and all its vendored dependencies, etc.
"""
import logging
from functools import partial
from optparse import Values
from typing import Any, List, Optional, Tuple
from pip._internal.cache import WheelCache
from pip._internal.cli import cmdoptions
from pip._internal.cli.index_command import IndexGroupCommand
from pip._internal.cli.index_command import SessionCommandMixin as SessionCommandMixin
from pip._internal.exceptions import CommandError, PreviousBuildDirError
from pip._internal.index.collector import LinkCollector
from pip._internal.index.package_finder import PackageFinder
from pip._internal.models.selection_prefs import SelectionPreferences
from pip._internal.models.target_python import TargetPython
from pip._internal.network.session import PipSession
from pip._internal.operations.build.build_tracker import BuildTracker
from pip._internal.operations.prepare import RequirementPreparer
from pip._internal.req.constructors import (
install_req_from_editable,
install_req_from_line,
install_req_from_parsed_requirement,
install_req_from_req_string,
)
from pip._internal.req.req_file import parse_requirements
from pip._internal.req.req_install import InstallRequirement
from pip._internal.resolution.base import BaseResolver
from pip._internal.utils.temp_dir import (
TempDirectory,
TempDirectoryTypeRegistry,
tempdir_kinds,
)
logger = logging.getLogger(__name__)
KEEPABLE_TEMPDIR_TYPES = [
tempdir_kinds.BUILD_ENV,
tempdir_kinds.EPHEM_WHEEL_CACHE,
tempdir_kinds.REQ_BUILD,
]
def with_cleanup(func: Any) -> Any:
"""Decorator for common logic related to managing temporary
directories.
"""
def configure_tempdir_registry(registry: TempDirectoryTypeRegistry) -> None:
for t in KEEPABLE_TEMPDIR_TYPES:
registry.set_delete(t, False)
def wrapper(
self: RequirementCommand, options: Values, args: List[Any]
) -> Optional[int]:
assert self.tempdir_registry is not None
if options.no_clean:
configure_tempdir_registry(self.tempdir_registry)
try:
return func(self, options, args)
except PreviousBuildDirError:
# This kind of conflict can occur when the user passes an explicit
# build directory with a pre-existing folder. In that case we do
# not want to accidentally remove it.
configure_tempdir_registry(self.tempdir_registry)
raise
return wrapper
class RequirementCommand(IndexGroupCommand):
def __init__(self, *args: Any, **kw: Any) -> None:
super().__init__(*args, **kw)
self.cmd_opts.add_option(cmdoptions.no_clean())
@staticmethod
def determine_resolver_variant(options: Values) -> str:
"""Determines which resolver should be used, based on the given options."""
if "legacy-resolver" in options.deprecated_features_enabled:
return "legacy"
return "resolvelib"
@classmethod
def make_requirement_preparer(
cls,
temp_build_dir: TempDirectory,
options: Values,
build_tracker: BuildTracker,
session: PipSession,
finder: PackageFinder,
use_user_site: bool,
download_dir: Optional[str] = None,
verbosity: int = 0,
) -> RequirementPreparer:
"""
Create a RequirementPreparer instance for the given parameters.
"""
temp_build_dir_path = temp_build_dir.path
assert temp_build_dir_path is not None
legacy_resolver = False
resolver_variant = cls.determine_resolver_variant(options)
if resolver_variant == "resolvelib":
lazy_wheel = "fast-deps" in options.features_enabled
if lazy_wheel:
logger.warning(
"pip is using lazily downloaded wheels using HTTP "
"range requests to obtain dependency information. "
"This experimental feature is enabled through "
"--use-feature=fast-deps and it is not ready for "
"production."
)
else:
legacy_resolver = True
lazy_wheel = False
if "fast-deps" in options.features_enabled:
logger.warning(
"fast-deps has no effect when used with the legacy resolver."
)
return RequirementPreparer(
build_dir=temp_build_dir_path,
src_dir=options.src_dir,
download_dir=download_dir,
build_isolation=options.build_isolation,
check_build_deps=options.check_build_deps,
build_tracker=build_tracker,
session=session,
progress_bar=options.progress_bar,
finder=finder,
require_hashes=options.require_hashes,
use_user_site=use_user_site,
lazy_wheel=lazy_wheel,
verbosity=verbosity,
legacy_resolver=legacy_resolver,
)
@classmethod
def make_resolver(
cls,
preparer: RequirementPreparer,
finder: PackageFinder,
options: Values,
wheel_cache: Optional[WheelCache] = None,
use_user_site: bool = False,
ignore_installed: bool = True,
ignore_requires_python: bool = False,
force_reinstall: bool = False,
upgrade_strategy: str = "to-satisfy-only",
use_pep517: Optional[bool] = None,
py_version_info: Optional[Tuple[int, ...]] = None,
) -> BaseResolver:
"""
Create a Resolver instance for the given parameters.
"""
make_install_req = partial(
install_req_from_req_string,
isolated=options.isolated_mode,
use_pep517=use_pep517,
)
resolver_variant = cls.determine_resolver_variant(options)
# The long import name and duplicated invocation is needed to convince
# Mypy into correctly typechecking. Otherwise it would complain the
# "Resolver" class being redefined.
if resolver_variant == "resolvelib":
import pip._internal.resolution.resolvelib.resolver
return pip._internal.resolution.resolvelib.resolver.Resolver(
preparer=preparer,
finder=finder,
wheel_cache=wheel_cache,
make_install_req=make_install_req,
use_user_site=use_user_site,
ignore_dependencies=options.ignore_dependencies,
ignore_installed=ignore_installed,
ignore_requires_python=ignore_requires_python,
force_reinstall=force_reinstall,
upgrade_strategy=upgrade_strategy,
py_version_info=py_version_info,
)
import pip._internal.resolution.legacy.resolver
return pip._internal.resolution.legacy.resolver.Resolver(
preparer=preparer,
finder=finder,
wheel_cache=wheel_cache,
make_install_req=make_install_req,
use_user_site=use_user_site,
ignore_dependencies=options.ignore_dependencies,
ignore_installed=ignore_installed,
ignore_requires_python=ignore_requires_python,
force_reinstall=force_reinstall,
upgrade_strategy=upgrade_strategy,
py_version_info=py_version_info,
)
def get_requirements(
self,
args: List[str],
options: Values,
finder: PackageFinder,
session: PipSession,
) -> List[InstallRequirement]:
"""
Parse command-line arguments into the corresponding requirements.
"""
requirements: List[InstallRequirement] = []
for filename in options.constraints:
for parsed_req in parse_requirements(
filename,
constraint=True,
finder=finder,
options=options,
session=session,
):
req_to_add = install_req_from_parsed_requirement(
parsed_req,
isolated=options.isolated_mode,
user_supplied=False,
)
requirements.append(req_to_add)
for req in args:
req_to_add = install_req_from_line(
req,
comes_from=None,
isolated=options.isolated_mode,
use_pep517=options.use_pep517,
user_supplied=True,
config_settings=getattr(options, "config_settings", None),
)
requirements.append(req_to_add)
for req in options.editables:
req_to_add = install_req_from_editable(
req,
user_supplied=True,
isolated=options.isolated_mode,
use_pep517=options.use_pep517,
config_settings=getattr(options, "config_settings", None),
)
requirements.append(req_to_add)
# NOTE: options.require_hashes may be set if --require-hashes is True
for filename in options.requirements:
for parsed_req in parse_requirements(
filename, finder=finder, options=options, session=session
):
req_to_add = install_req_from_parsed_requirement(
parsed_req,
isolated=options.isolated_mode,
use_pep517=options.use_pep517,
user_supplied=True,
config_settings=(
parsed_req.options.get("config_settings")
if parsed_req.options
else None
),
)
requirements.append(req_to_add)
# If any requirement has hash options, enable hash checking.
if any(req.has_hash_options for req in requirements):
options.require_hashes = True
if not (args or options.editables or options.requirements):
opts = {"name": self.name}
if options.find_links:
raise CommandError(
"You must give at least one requirement to {name} "
'(maybe you meant "pip {name} {links}"?)'.format(
**dict(opts, links=" ".join(options.find_links))
)
)
else:
raise CommandError(
"You must give at least one requirement to {name} "
'(see "pip help {name}")'.format(**opts)
)
return requirements
@staticmethod
def trace_basic_info(finder: PackageFinder) -> None:
"""
Trace basic information about the provided objects.
"""
# Display where finder is looking for packages
search_scope = finder.search_scope
locations = search_scope.get_formatted_locations()
if locations:
logger.info(locations)
def _build_package_finder(
self,
options: Values,
session: PipSession,
target_python: Optional[TargetPython] = None,
ignore_requires_python: Optional[bool] = None,
) -> PackageFinder:
"""
Create a package finder appropriate to this requirement command.
:param ignore_requires_python: Whether to ignore incompatible
"Requires-Python" values in links. Defaults to False.
"""
link_collector = LinkCollector.create(session, options=options)
selection_prefs = SelectionPreferences(
allow_yanked=True,
format_control=options.format_control,
allow_all_prereleases=options.pre,
prefer_binary=options.prefer_binary,
ignore_requires_python=ignore_requires_python,
)
return PackageFinder.create(
link_collector=link_collector,
selection_prefs=selection_prefs,
target_python=target_python,
)

View File

@ -1,159 +0,0 @@
import contextlib
import itertools
import logging
import sys
import time
from typing import IO, Generator, Optional
from pip._internal.utils.compat import WINDOWS
from pip._internal.utils.logging import get_indentation
logger = logging.getLogger(__name__)
class SpinnerInterface:
def spin(self) -> None:
raise NotImplementedError()
def finish(self, final_status: str) -> None:
raise NotImplementedError()
class InteractiveSpinner(SpinnerInterface):
def __init__(
self,
message: str,
file: Optional[IO[str]] = None,
spin_chars: str = "-\\|/",
# Empirically, 8 updates/second looks nice
min_update_interval_seconds: float = 0.125,
):
self._message = message
if file is None:
file = sys.stdout
self._file = file
self._rate_limiter = RateLimiter(min_update_interval_seconds)
self._finished = False
self._spin_cycle = itertools.cycle(spin_chars)
self._file.write(" " * get_indentation() + self._message + " ... ")
self._width = 0
def _write(self, status: str) -> None:
assert not self._finished
# Erase what we wrote before by backspacing to the beginning, writing
# spaces to overwrite the old text, and then backspacing again
backup = "\b" * self._width
self._file.write(backup + " " * self._width + backup)
# Now we have a blank slate to add our status
self._file.write(status)
self._width = len(status)
self._file.flush()
self._rate_limiter.reset()
def spin(self) -> None:
if self._finished:
return
if not self._rate_limiter.ready():
return
self._write(next(self._spin_cycle))
def finish(self, final_status: str) -> None:
if self._finished:
return
self._write(final_status)
self._file.write("\n")
self._file.flush()
self._finished = True
# Used for dumb terminals, non-interactive installs (no tty), etc.
# We still print updates occasionally (once every 60 seconds by default) to
# act as a keep-alive for systems like Travis-CI that take lack-of-output as
# an indication that a task has frozen.
class NonInteractiveSpinner(SpinnerInterface):
def __init__(self, message: str, min_update_interval_seconds: float = 60.0) -> None:
self._message = message
self._finished = False
self._rate_limiter = RateLimiter(min_update_interval_seconds)
self._update("started")
def _update(self, status: str) -> None:
assert not self._finished
self._rate_limiter.reset()
logger.info("%s: %s", self._message, status)
def spin(self) -> None:
if self._finished:
return
if not self._rate_limiter.ready():
return
self._update("still running...")
def finish(self, final_status: str) -> None:
if self._finished:
return
self._update(f"finished with status '{final_status}'")
self._finished = True
class RateLimiter:
def __init__(self, min_update_interval_seconds: float) -> None:
self._min_update_interval_seconds = min_update_interval_seconds
self._last_update: float = 0
def ready(self) -> bool:
now = time.time()
delta = now - self._last_update
return delta >= self._min_update_interval_seconds
def reset(self) -> None:
self._last_update = time.time()
@contextlib.contextmanager
def open_spinner(message: str) -> Generator[SpinnerInterface, None, None]:
# Interactive spinner goes directly to sys.stdout rather than being routed
# through the logging system, but it acts like it has level INFO,
# i.e. it's only displayed if we're at level INFO or better.
# Non-interactive spinner goes through the logging system, so it is always
# in sync with logging configuration.
if sys.stdout.isatty() and logger.getEffectiveLevel() <= logging.INFO:
spinner: SpinnerInterface = InteractiveSpinner(message)
else:
spinner = NonInteractiveSpinner(message)
try:
with hidden_cursor(sys.stdout):
yield spinner
except KeyboardInterrupt:
spinner.finish("canceled")
raise
except Exception:
spinner.finish("error")
raise
else:
spinner.finish("done")
HIDE_CURSOR = "\x1b[?25l"
SHOW_CURSOR = "\x1b[?25h"
@contextlib.contextmanager
def hidden_cursor(file: IO[str]) -> Generator[None, None, None]:
# The Windows terminal does not support the hide/show cursor ANSI codes,
# even via colorama. So don't even try.
if WINDOWS:
yield
# We don't want to clutter the output with control characters if we're
# writing to a file, or if the user is running with --quiet.
# See https://github.com/pypa/pip/issues/3418
elif not file.isatty() or logger.getEffectiveLevel() > logging.INFO:
yield
else:
file.write(HIDE_CURSOR)
try:
yield
finally:
file.write(SHOW_CURSOR)

View File

@ -1,6 +0,0 @@
SUCCESS = 0
ERROR = 1
UNKNOWN_ERROR = 2
VIRTUALENV_NOT_FOUND = 3
PREVIOUS_BUILD_DIR_ERROR = 4
NO_MATCHES_FOUND = 23

View File

@ -1,132 +0,0 @@
"""
Package containing all pip commands
"""
import importlib
from collections import namedtuple
from typing import Any, Dict, Optional
from pip._internal.cli.base_command import Command
CommandInfo = namedtuple("CommandInfo", "module_path, class_name, summary")
# This dictionary does a bunch of heavy lifting for help output:
# - Enables avoiding additional (costly) imports for presenting `--help`.
# - The ordering matters for help display.
#
# Even though the module path starts with the same "pip._internal.commands"
# prefix, the full path makes testing easier (specifically when modifying
# `commands_dict` in test setup / teardown).
commands_dict: Dict[str, CommandInfo] = {
"install": CommandInfo(
"pip._internal.commands.install",
"InstallCommand",
"Install packages.",
),
"download": CommandInfo(
"pip._internal.commands.download",
"DownloadCommand",
"Download packages.",
),
"uninstall": CommandInfo(
"pip._internal.commands.uninstall",
"UninstallCommand",
"Uninstall packages.",
),
"freeze": CommandInfo(
"pip._internal.commands.freeze",
"FreezeCommand",
"Output installed packages in requirements format.",
),
"inspect": CommandInfo(
"pip._internal.commands.inspect",
"InspectCommand",
"Inspect the python environment.",
),
"list": CommandInfo(
"pip._internal.commands.list",
"ListCommand",
"List installed packages.",
),
"show": CommandInfo(
"pip._internal.commands.show",
"ShowCommand",
"Show information about installed packages.",
),
"check": CommandInfo(
"pip._internal.commands.check",
"CheckCommand",
"Verify installed packages have compatible dependencies.",
),
"config": CommandInfo(
"pip._internal.commands.configuration",
"ConfigurationCommand",
"Manage local and global configuration.",
),
"search": CommandInfo(
"pip._internal.commands.search",
"SearchCommand",
"Search PyPI for packages.",
),
"cache": CommandInfo(
"pip._internal.commands.cache",
"CacheCommand",
"Inspect and manage pip's wheel cache.",
),
"index": CommandInfo(
"pip._internal.commands.index",
"IndexCommand",
"Inspect information available from package indexes.",
),
"wheel": CommandInfo(
"pip._internal.commands.wheel",
"WheelCommand",
"Build wheels from your requirements.",
),
"hash": CommandInfo(
"pip._internal.commands.hash",
"HashCommand",
"Compute hashes of package archives.",
),
"completion": CommandInfo(
"pip._internal.commands.completion",
"CompletionCommand",
"A helper command used for command completion.",
),
"debug": CommandInfo(
"pip._internal.commands.debug",
"DebugCommand",
"Show information useful for debugging.",
),
"help": CommandInfo(
"pip._internal.commands.help",
"HelpCommand",
"Show help for commands.",
),
}
def create_command(name: str, **kwargs: Any) -> Command:
"""
Create an instance of the Command class with the given name.
"""
module_path, class_name, summary = commands_dict[name]
module = importlib.import_module(module_path)
command_class = getattr(module, class_name)
command = command_class(name=name, summary=summary, **kwargs)
return command
def get_similar_commands(name: str) -> Optional[str]:
"""Command name auto-correct."""
from difflib import get_close_matches
name = name.lower()
close_commands = get_close_matches(name, commands_dict.keys())
if close_commands:
return close_commands[0]
else:
return None

View File

@ -1,228 +0,0 @@
import os
import textwrap
from optparse import Values
from typing import Any, List
from pip._internal.cli.base_command import Command
from pip._internal.cli.status_codes import ERROR, SUCCESS
from pip._internal.exceptions import CommandError, PipError
from pip._internal.utils import filesystem
from pip._internal.utils.logging import getLogger
from pip._internal.utils.misc import format_size
logger = getLogger(__name__)
class CacheCommand(Command):
"""
Inspect and manage pip's wheel cache.
Subcommands:
- dir: Show the cache directory.
- info: Show information about the cache.
- list: List filenames of packages stored in the cache.
- remove: Remove one or more package from the cache.
- purge: Remove all items from the cache.
``<pattern>`` can be a glob expression or a package name.
"""
ignore_require_venv = True
usage = """
%prog dir
%prog info
%prog list [<pattern>] [--format=[human, abspath]]
%prog remove <pattern>
%prog purge
"""
def add_options(self) -> None:
self.cmd_opts.add_option(
"--format",
action="store",
dest="list_format",
default="human",
choices=("human", "abspath"),
help="Select the output format among: human (default) or abspath",
)
self.parser.insert_option_group(0, self.cmd_opts)
def run(self, options: Values, args: List[str]) -> int:
handlers = {
"dir": self.get_cache_dir,
"info": self.get_cache_info,
"list": self.list_cache_items,
"remove": self.remove_cache_items,
"purge": self.purge_cache,
}
if not options.cache_dir:
logger.error("pip cache commands can not function since cache is disabled.")
return ERROR
# Determine action
if not args or args[0] not in handlers:
logger.error(
"Need an action (%s) to perform.",
", ".join(sorted(handlers)),
)
return ERROR
action = args[0]
# Error handling happens here, not in the action-handlers.
try:
handlers[action](options, args[1:])
except PipError as e:
logger.error(e.args[0])
return ERROR
return SUCCESS
def get_cache_dir(self, options: Values, args: List[Any]) -> None:
if args:
raise CommandError("Too many arguments")
logger.info(options.cache_dir)
def get_cache_info(self, options: Values, args: List[Any]) -> None:
if args:
raise CommandError("Too many arguments")
num_http_files = len(self._find_http_files(options))
num_packages = len(self._find_wheels(options, "*"))
http_cache_location = self._cache_dir(options, "http-v2")
old_http_cache_location = self._cache_dir(options, "http")
wheels_cache_location = self._cache_dir(options, "wheels")
http_cache_size = filesystem.format_size(
filesystem.directory_size(http_cache_location)
+ filesystem.directory_size(old_http_cache_location)
)
wheels_cache_size = filesystem.format_directory_size(wheels_cache_location)
message = (
textwrap.dedent(
"""
Package index page cache location (pip v23.3+): {http_cache_location}
Package index page cache location (older pips): {old_http_cache_location}
Package index page cache size: {http_cache_size}
Number of HTTP files: {num_http_files}
Locally built wheels location: {wheels_cache_location}
Locally built wheels size: {wheels_cache_size}
Number of locally built wheels: {package_count}
""" # noqa: E501
)
.format(
http_cache_location=http_cache_location,
old_http_cache_location=old_http_cache_location,
http_cache_size=http_cache_size,
num_http_files=num_http_files,
wheels_cache_location=wheels_cache_location,
package_count=num_packages,
wheels_cache_size=wheels_cache_size,
)
.strip()
)
logger.info(message)
def list_cache_items(self, options: Values, args: List[Any]) -> None:
if len(args) > 1:
raise CommandError("Too many arguments")
if args:
pattern = args[0]
else:
pattern = "*"
files = self._find_wheels(options, pattern)
if options.list_format == "human":
self.format_for_human(files)
else:
self.format_for_abspath(files)
def format_for_human(self, files: List[str]) -> None:
if not files:
logger.info("No locally built wheels cached.")
return
results = []
for filename in files:
wheel = os.path.basename(filename)
size = filesystem.format_file_size(filename)
results.append(f" - {wheel} ({size})")
logger.info("Cache contents:\n")
logger.info("\n".join(sorted(results)))
def format_for_abspath(self, files: List[str]) -> None:
if files:
logger.info("\n".join(sorted(files)))
def remove_cache_items(self, options: Values, args: List[Any]) -> None:
if len(args) > 1:
raise CommandError("Too many arguments")
if not args:
raise CommandError("Please provide a pattern")
files = self._find_wheels(options, args[0])
no_matching_msg = "No matching packages"
if args[0] == "*":
# Only fetch http files if no specific pattern given
files += self._find_http_files(options)
else:
# Add the pattern to the log message
no_matching_msg += f' for pattern "{args[0]}"'
if not files:
logger.warning(no_matching_msg)
bytes_removed = 0
for filename in files:
bytes_removed += os.stat(filename).st_size
os.unlink(filename)
logger.verbose("Removed %s", filename)
logger.info("Files removed: %s (%s)", len(files), format_size(bytes_removed))
def purge_cache(self, options: Values, args: List[Any]) -> None:
if args:
raise CommandError("Too many arguments")
return self.remove_cache_items(options, ["*"])
def _cache_dir(self, options: Values, subdir: str) -> str:
return os.path.join(options.cache_dir, subdir)
def _find_http_files(self, options: Values) -> List[str]:
old_http_dir = self._cache_dir(options, "http")
new_http_dir = self._cache_dir(options, "http-v2")
return filesystem.find_files(old_http_dir, "*") + filesystem.find_files(
new_http_dir, "*"
)
def _find_wheels(self, options: Values, pattern: str) -> List[str]:
wheel_dir = self._cache_dir(options, "wheels")
# The wheel filename format, as specified in PEP 427, is:
# {distribution}-{version}(-{build})?-{python}-{abi}-{platform}.whl
#
# Additionally, non-alphanumeric values in the distribution are
# normalized to underscores (_), meaning hyphens can never occur
# before `-{version}`.
#
# Given that information:
# - If the pattern we're given contains a hyphen (-), the user is
# providing at least the version. Thus, we can just append `*.whl`
# to match the rest of it.
# - If the pattern we're given doesn't contain a hyphen (-), the
# user is only providing the name. Thus, we append `-*.whl` to
# match the hyphen before the version, followed by anything else.
#
# PEP 427: https://www.python.org/dev/peps/pep-0427/
pattern = pattern + ("*.whl" if "-" in pattern else "-*.whl")
return filesystem.find_files(wheel_dir, pattern)

View File

@ -1,67 +0,0 @@
import logging
from optparse import Values
from typing import List
from pip._internal.cli.base_command import Command
from pip._internal.cli.status_codes import ERROR, SUCCESS
from pip._internal.metadata import get_default_environment
from pip._internal.operations.check import (
check_package_set,
check_unsupported,
create_package_set_from_installed,
)
from pip._internal.utils.compatibility_tags import get_supported
from pip._internal.utils.misc import write_output
logger = logging.getLogger(__name__)
class CheckCommand(Command):
"""Verify installed packages have compatible dependencies."""
ignore_require_venv = True
usage = """
%prog [options]"""
def run(self, options: Values, args: List[str]) -> int:
package_set, parsing_probs = create_package_set_from_installed()
missing, conflicting = check_package_set(package_set)
unsupported = list(
check_unsupported(
get_default_environment().iter_installed_distributions(),
get_supported(),
)
)
for project_name in missing:
version = package_set[project_name].version
for dependency in missing[project_name]:
write_output(
"%s %s requires %s, which is not installed.",
project_name,
version,
dependency[0],
)
for project_name in conflicting:
version = package_set[project_name].version
for dep_name, dep_version, req in conflicting[project_name]:
write_output(
"%s %s has requirement %s, but you have %s %s.",
project_name,
version,
req,
dep_name,
dep_version,
)
for package in unsupported:
write_output(
"%s %s is not supported on this platform",
package.raw_name,
package.version,
)
if missing or conflicting or parsing_probs or unsupported:
return ERROR
else:
write_output("No broken requirements found.")
return SUCCESS

View File

@ -1,130 +0,0 @@
import sys
import textwrap
from optparse import Values
from typing import List
from pip._internal.cli.base_command import Command
from pip._internal.cli.status_codes import SUCCESS
from pip._internal.utils.misc import get_prog
BASE_COMPLETION = """
# pip {shell} completion start{script}# pip {shell} completion end
"""
COMPLETION_SCRIPTS = {
"bash": """
_pip_completion()
{{
COMPREPLY=( $( COMP_WORDS="${{COMP_WORDS[*]}}" \\
COMP_CWORD=$COMP_CWORD \\
PIP_AUTO_COMPLETE=1 $1 2>/dev/null ) )
}}
complete -o default -F _pip_completion {prog}
""",
"zsh": """
#compdef -P pip[0-9.]#
__pip() {{
compadd $( COMP_WORDS="$words[*]" \\
COMP_CWORD=$((CURRENT-1)) \\
PIP_AUTO_COMPLETE=1 $words[1] 2>/dev/null )
}}
if [[ $zsh_eval_context[-1] == loadautofunc ]]; then
# autoload from fpath, call function directly
__pip "$@"
else
# eval/source/. command, register function for later
compdef __pip -P 'pip[0-9.]#'
fi
""",
"fish": """
function __fish_complete_pip
set -lx COMP_WORDS (commandline -o) ""
set -lx COMP_CWORD ( \\
math (contains -i -- (commandline -t) $COMP_WORDS)-1 \\
)
set -lx PIP_AUTO_COMPLETE 1
string split \\ -- (eval $COMP_WORDS[1])
end
complete -fa "(__fish_complete_pip)" -c {prog}
""",
"powershell": """
if ((Test-Path Function:\\TabExpansion) -and -not `
(Test-Path Function:\\_pip_completeBackup)) {{
Rename-Item Function:\\TabExpansion _pip_completeBackup
}}
function TabExpansion($line, $lastWord) {{
$lastBlock = [regex]::Split($line, '[|;]')[-1].TrimStart()
if ($lastBlock.StartsWith("{prog} ")) {{
$Env:COMP_WORDS=$lastBlock
$Env:COMP_CWORD=$lastBlock.Split().Length - 1
$Env:PIP_AUTO_COMPLETE=1
(& {prog}).Split()
Remove-Item Env:COMP_WORDS
Remove-Item Env:COMP_CWORD
Remove-Item Env:PIP_AUTO_COMPLETE
}}
elseif (Test-Path Function:\\_pip_completeBackup) {{
# Fall back on existing tab expansion
_pip_completeBackup $line $lastWord
}}
}}
""",
}
class CompletionCommand(Command):
"""A helper command to be used for command completion."""
ignore_require_venv = True
def add_options(self) -> None:
self.cmd_opts.add_option(
"--bash",
"-b",
action="store_const",
const="bash",
dest="shell",
help="Emit completion code for bash",
)
self.cmd_opts.add_option(
"--zsh",
"-z",
action="store_const",
const="zsh",
dest="shell",
help="Emit completion code for zsh",
)
self.cmd_opts.add_option(
"--fish",
"-f",
action="store_const",
const="fish",
dest="shell",
help="Emit completion code for fish",
)
self.cmd_opts.add_option(
"--powershell",
"-p",
action="store_const",
const="powershell",
dest="shell",
help="Emit completion code for powershell",
)
self.parser.insert_option_group(0, self.cmd_opts)
def run(self, options: Values, args: List[str]) -> int:
"""Prints the completion code of the given shell"""
shells = COMPLETION_SCRIPTS.keys()
shell_options = ["--" + shell for shell in sorted(shells)]
if options.shell in shells:
script = textwrap.dedent(
COMPLETION_SCRIPTS.get(options.shell, "").format(prog=get_prog())
)
print(BASE_COMPLETION.format(script=script, shell=options.shell))
return SUCCESS
else:
sys.stderr.write(
"ERROR: You must pass {}\n".format(" or ".join(shell_options))
)
return SUCCESS

Some files were not shown because too many files have changed in this diff Show More