diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3459116
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+venv/
+www/
+
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..b18e420
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,3 @@
+jinja2
+markdown
+pygments
diff --git a/template.html b/template.html
index 10498ea..17a70a9 100755
--- a/template.html
+++ b/template.html
@@ -19,7 +19,7 @@
});
}
- window.addEventListener('DOMContentLoaded', (event) => {
+ window.addEventListener('load', (event) => {
makeImagesClickeable();
});
diff --git a/venv/bin/Activate.ps1 b/venv/bin/Activate.ps1
index 900f50e..2fb3852 100644
--- a/venv/bin/Activate.ps1
+++ b/venv/bin/Activate.ps1
@@ -1,6 +1,6 @@
<#
.Synopsis
-Activate a Python virtual environment for the current Powershell session.
+Activate a Python virtual environment for the current PowerShell session.
.Description
Pushes the python executable for a virtual environment to the front of the
@@ -37,6 +37,15 @@ 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(
@@ -137,7 +146,7 @@ function Get-PyVenvConfig(
$val = $keyval[1]
# Remove extraneous quotations around a string value.
- if ("'""".Contains($val.Substring(0,1))) {
+ if ("'""".Contains($val.Substring(0, 1))) {
$val = $val.Substring(1, $val.Length - 2)
}
@@ -165,7 +174,8 @@ Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)"
# VenvExecDir if specified on the command line.
if ($VenvDir) {
Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values"
-} else {
+}
+else {
Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir."
$VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/")
Write-Verbose "VenvDir=$VenvDir"
@@ -179,7 +189,8 @@ $pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir
# just use the name of the virtual environment folder.
if ($Prompt) {
Write-Verbose "Prompt specified as argument, using '$Prompt'"
-} else {
+}
+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'])'"
diff --git a/venv/bin/activate b/venv/bin/activate
index 65245be..7420877 100644
--- a/venv/bin/activate
+++ b/venv/bin/activate
@@ -37,7 +37,7 @@ deactivate () {
# unset irrelevant variables
deactivate nondestructive
-VIRTUAL_ENV="/home/ryuuji/src/generator/venv"
+VIRTUAL_ENV="/home/ryuuji/src/danielcortes.xyz/venv"
export VIRTUAL_ENV
_OLD_VIRTUAL_PATH="$PATH"
@@ -59,7 +59,7 @@ if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then
else
if [ "`basename \"$VIRTUAL_ENV\"`" = "__" ] ; then
# special case for Aspen magic directories
- # see http://www.zetadev.com/software/aspen/
+ # see https://aspen.io/
PS1="[`basename \`dirname \"$VIRTUAL_ENV\"\``] $PS1"
else
PS1="(`basename \"$VIRTUAL_ENV\"`)$PS1"
diff --git a/venv/bin/activate.csh b/venv/bin/activate.csh
index 2b65f2f..2b5b120 100644
--- a/venv/bin/activate.csh
+++ b/venv/bin/activate.csh
@@ -8,7 +8,7 @@ alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PA
# Unset irrelevant variables.
deactivate nondestructive
-setenv VIRTUAL_ENV "/home/ryuuji/src/generator/venv"
+setenv VIRTUAL_ENV "/home/ryuuji/src/danielcortes.xyz/venv"
set _OLD_VIRTUAL_PATH="$PATH"
setenv PATH "$VIRTUAL_ENV/bin:$PATH"
@@ -22,7 +22,7 @@ if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then
else
if (`basename "VIRTUAL_ENV"` == "__") then
# special case for Aspen magic directories
- # see http://www.zetadev.com/software/aspen/
+ # see https://aspen.io/
set env_name = `basename \`dirname "$VIRTUAL_ENV"\``
else
set env_name = `basename "$VIRTUAL_ENV"`
diff --git a/venv/bin/activate.fish b/venv/bin/activate.fish
index edcb526..a60de0f 100644
--- a/venv/bin/activate.fish
+++ b/venv/bin/activate.fish
@@ -29,7 +29,7 @@ end
# unset irrelevant variables
deactivate nondestructive
-set -gx VIRTUAL_ENV "/home/ryuuji/src/generator/venv"
+set -gx VIRTUAL_ENV "/home/ryuuji/src/danielcortes.xyz/venv"
set -gx _OLD_VIRTUAL_PATH $PATH
set -gx PATH "$VIRTUAL_ENV/bin" $PATH
@@ -59,7 +59,7 @@ if test -z "$VIRTUAL_ENV_DISABLE_PROMPT"
set -l _checkbase (basename "$VIRTUAL_ENV")
if test $_checkbase = "__"
# special case for Aspen magic directories
- # see http://www.zetadev.com/software/aspen/
+ # see https://aspen.io/
printf "%s[%s]%s " (set_color -b blue white) (basename (dirname "$VIRTUAL_ENV")) (set_color normal)
else
printf "%s(%s)%s" (set_color -b blue white) (basename "$VIRTUAL_ENV") (set_color normal)
diff --git a/venv/bin/easy_install b/venv/bin/easy_install
index 5c40f51..b7a0820 100755
--- a/venv/bin/easy_install
+++ b/venv/bin/easy_install
@@ -1,10 +1,8 @@
-#!/home/ryuuji/src/generator/venv/bin/python
+#!/home/ryuuji/src/danielcortes.xyz/venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
-
from setuptools.command.easy_install import main
-
if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())
diff --git a/venv/bin/easy_install-3.8 b/venv/bin/easy_install-3.8
index 5c40f51..b7a0820 100755
--- a/venv/bin/easy_install-3.8
+++ b/venv/bin/easy_install-3.8
@@ -1,10 +1,8 @@
-#!/home/ryuuji/src/generator/venv/bin/python
+#!/home/ryuuji/src/danielcortes.xyz/venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
-
from setuptools.command.easy_install import main
-
if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())
diff --git a/venv/bin/markdown_py b/venv/bin/markdown_py
index a851441..95e2f9e 100755
--- a/venv/bin/markdown_py
+++ b/venv/bin/markdown_py
@@ -1,10 +1,8 @@
-#!/home/ryuuji/src/generator/venv/bin/python
+#!/home/ryuuji/src/danielcortes.xyz/venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
-
from markdown.__main__ import run
-
if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(run())
diff --git a/venv/bin/pip b/venv/bin/pip
index 9e49170..2674b75 100755
--- a/venv/bin/pip
+++ b/venv/bin/pip
@@ -1,10 +1,8 @@
-#!/home/ryuuji/src/generator/venv/bin/python
+#!/home/ryuuji/src/danielcortes.xyz/venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
-
-from pip._internal import main
-
+from pip._internal.cli.main import main
if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())
diff --git a/venv/bin/pip3 b/venv/bin/pip3
index 9e49170..2674b75 100755
--- a/venv/bin/pip3
+++ b/venv/bin/pip3
@@ -1,10 +1,8 @@
-#!/home/ryuuji/src/generator/venv/bin/python
+#!/home/ryuuji/src/danielcortes.xyz/venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
-
-from pip._internal import main
-
+from pip._internal.cli.main import main
if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())
diff --git a/venv/bin/pip3.8 b/venv/bin/pip3.8
index 9e49170..2674b75 100755
--- a/venv/bin/pip3.8
+++ b/venv/bin/pip3.8
@@ -1,10 +1,8 @@
-#!/home/ryuuji/src/generator/venv/bin/python
+#!/home/ryuuji/src/danielcortes.xyz/venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
-
-from pip._internal import main
-
+from pip._internal.cli.main import main
if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(main())
diff --git a/venv/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/RECORD b/venv/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/RECORD
index 413fef4..3a6cdaa 100644
--- a/venv/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/RECORD
+++ b/venv/lib/python3.8/site-packages/Jinja2-2.11.2.dist-info/RECORD
@@ -2,6 +2,7 @@ Jinja2-2.11.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuw
Jinja2-2.11.2.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475
Jinja2-2.11.2.dist-info/METADATA,sha256=5ZHRZoIRAMHsJPnqhlJ622_dRPsYePYJ-9EH4-Ry7yI,3535
Jinja2-2.11.2.dist-info/RECORD,,
+Jinja2-2.11.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
Jinja2-2.11.2.dist-info/WHEEL,sha256=kGT74LWyRUZrL4VgLh6_g12IeVl_9u9ZVhadrgXZUEY,110
Jinja2-2.11.2.dist-info/entry_points.txt,sha256=Qy_DkVo6Xj_zzOtmErrATe8lHZhOqdjpt3e4JJAGyi8,61
Jinja2-2.11.2.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7
diff --git a/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/LICENSE.md b/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/LICENSE.md
deleted file mode 100644
index 2652d97..0000000
--- a/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/LICENSE.md
+++ /dev/null
@@ -1,29 +0,0 @@
-Copyright 2007, 2008 The Python Markdown Project (v. 1.7 and later)
-Copyright 2004, 2005, 2006 Yuri Takhteyev (v. 0.2-1.6b)
-Copyright 2004 Manfred Stienstra (the original version)
-
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are met:
-
-* Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-* Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-* Neither the name of the Python Markdown Project nor the
- names of its contributors may be used to endorse or promote products
- derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE PYTHON MARKDOWN PROJECT ''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 ANY CONTRIBUTORS TO THE PYTHON MARKDOWN PROJECT
-BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-POSSIBILITY OF SUCH DAMAGE.
diff --git a/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/METADATA b/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/METADATA
deleted file mode 100644
index b80bb75..0000000
--- a/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/METADATA
+++ /dev/null
@@ -1,57 +0,0 @@
-Metadata-Version: 2.1
-Name: Markdown
-Version: 3.2.1
-Summary: Python implementation of Markdown.
-Home-page: https://Python-Markdown.github.io/
-Author: Manfred Stienstra, Yuri takhteyev and Waylan limberg
-Author-email: waylan.limberg@icloud.com
-Maintainer: Waylan Limberg
-Maintainer-email: waylan.limberg@icloud.com
-License: BSD License
-Download-URL: http://pypi.python.org/packages/source/M/Markdown/Markdown-3.2.1-py2.py3-none-any.whl
-Platform: UNKNOWN
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: License :: OSI Approved :: BSD License
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.5
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3 :: Only
-Classifier: Programming Language :: Python :: Implementation :: CPython
-Classifier: Programming Language :: Python :: Implementation :: PyPy
-Classifier: Topic :: Communications :: Email :: Filters
-Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content :: CGI Tools/Libraries
-Classifier: Topic :: Internet :: WWW/HTTP :: Site Management
-Classifier: Topic :: Software Development :: Documentation
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Classifier: Topic :: Text Processing :: Filters
-Classifier: Topic :: Text Processing :: Markup :: HTML
-Requires-Python: >=3.5
-Requires-Dist: setuptools (>=36)
-Provides-Extra: testing
-Requires-Dist: coverage ; extra == 'testing'
-Requires-Dist: pyyaml ; extra == 'testing'
-
-
-This is a Python implementation of John Gruber's Markdown_.
-It is almost completely compliant with the reference implementation,
-though there are a few known issues. See Features_ for information
-on what exactly is supported and what is not. Additional features are
-supported by the `Available Extensions`_.
-
-.. _Markdown: https://daringfireball.net/projects/markdown/
-.. _Features: https://Python-Markdown.github.io#features
-.. _`Available Extensions`: https://Python-Markdown.github.io/extensions/
-
-Support
-=======
-
-You may report bugs, ask for help, and discuss various other issues on
-the `bug tracker`_.
-
-.. _`bug tracker`: https://github.com/Python-Markdown/markdown/issues
-
-
diff --git a/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/RECORD b/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/RECORD
deleted file mode 100644
index be08e6f..0000000
--- a/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/RECORD
+++ /dev/null
@@ -1,74 +0,0 @@
-../../../bin/markdown_py,sha256=CN-Ji-5IbiekxHQIaCGuLnffDcAJe1KbGNP2M75sqGM,243
-Markdown-3.2.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-Markdown-3.2.1.dist-info/LICENSE.md,sha256=bxGTy2NHGOZcOlN9biXr1hSCDsDvaTz8EiSBEmONZNo,1645
-Markdown-3.2.1.dist-info/METADATA,sha256=PK6UzXb9yL09qZJH7SCqZd6-mj8keovCmxQLt89NlEQ,2383
-Markdown-3.2.1.dist-info/RECORD,,
-Markdown-3.2.1.dist-info/WHEEL,sha256=h_aVn5OB2IERUjMbi2pucmR_zzWJtk303YXvhh60NJ8,110
-Markdown-3.2.1.dist-info/entry_points.txt,sha256=j4jiKg-iwZGImvi8OzotZePWoFbJJ4GrfzDqH03u3SQ,1103
-Markdown-3.2.1.dist-info/top_level.txt,sha256=IAxs8x618RXoH1uCqeLLxXsDefJvE_mIibr_M4sOlyk,9
-markdown/__init__.py,sha256=002-LuHviYzROW2rg_gBGai81nMouUNO9UFj5nSsTSk,2065
-markdown/__main__.py,sha256=MpVK3zlwQ-4AzDzZmIScPB90PpunMGVgS5KBmJuHYTw,5802
-markdown/__meta__.py,sha256=xhmwLb0Eb6kfiapdM21pCb80lyVEl8hxv8Re_X6wsI0,1837
-markdown/__pycache__/__init__.cpython-38.pyc,,
-markdown/__pycache__/__main__.cpython-38.pyc,,
-markdown/__pycache__/__meta__.cpython-38.pyc,,
-markdown/__pycache__/blockparser.cpython-38.pyc,,
-markdown/__pycache__/blockprocessors.cpython-38.pyc,,
-markdown/__pycache__/core.cpython-38.pyc,,
-markdown/__pycache__/inlinepatterns.cpython-38.pyc,,
-markdown/__pycache__/pep562.cpython-38.pyc,,
-markdown/__pycache__/postprocessors.cpython-38.pyc,,
-markdown/__pycache__/preprocessors.cpython-38.pyc,,
-markdown/__pycache__/serializers.cpython-38.pyc,,
-markdown/__pycache__/test_tools.cpython-38.pyc,,
-markdown/__pycache__/treeprocessors.cpython-38.pyc,,
-markdown/__pycache__/util.cpython-38.pyc,,
-markdown/blockparser.py,sha256=JpBhOokOoBUGCXolftOc5m1hPcR2y9s9hVd9WSuhHzo,4285
-markdown/blockprocessors.py,sha256=l4gmkAN9b2L340EX0gm24EyWS7UzBviPqX6wYrcgEco,23736
-markdown/core.py,sha256=JLR5hIMwWSeIHRQhTzAymB3QUD3gHCdITFvmuuCpIcA,15360
-markdown/extensions/__init__.py,sha256=6kUSgoqDT4gGUVsqf7F9oQD_jA0RJCbX5EK3JVo8iQE,3517
-markdown/extensions/__pycache__/__init__.cpython-38.pyc,,
-markdown/extensions/__pycache__/abbr.cpython-38.pyc,,
-markdown/extensions/__pycache__/admonition.cpython-38.pyc,,
-markdown/extensions/__pycache__/attr_list.cpython-38.pyc,,
-markdown/extensions/__pycache__/codehilite.cpython-38.pyc,,
-markdown/extensions/__pycache__/def_list.cpython-38.pyc,,
-markdown/extensions/__pycache__/extra.cpython-38.pyc,,
-markdown/extensions/__pycache__/fenced_code.cpython-38.pyc,,
-markdown/extensions/__pycache__/footnotes.cpython-38.pyc,,
-markdown/extensions/__pycache__/legacy_attrs.cpython-38.pyc,,
-markdown/extensions/__pycache__/legacy_em.cpython-38.pyc,,
-markdown/extensions/__pycache__/md_in_html.cpython-38.pyc,,
-markdown/extensions/__pycache__/meta.cpython-38.pyc,,
-markdown/extensions/__pycache__/nl2br.cpython-38.pyc,,
-markdown/extensions/__pycache__/sane_lists.cpython-38.pyc,,
-markdown/extensions/__pycache__/smarty.cpython-38.pyc,,
-markdown/extensions/__pycache__/tables.cpython-38.pyc,,
-markdown/extensions/__pycache__/toc.cpython-38.pyc,,
-markdown/extensions/__pycache__/wikilinks.cpython-38.pyc,,
-markdown/extensions/abbr.py,sha256=pqp2HnOR2giT-iYKyqtsp2_eUOWBR0j_hUfjvUV5c88,2916
-markdown/extensions/admonition.py,sha256=HWHHjuYZPAPOg5X8hbpDuSbw8gB6k0odw8GuTT1v_N4,3124
-markdown/extensions/attr_list.py,sha256=m9a1H-S33rV2twtlFYuoxSiCAf22ndU5tziSzNF2dNg,6003
-markdown/extensions/codehilite.py,sha256=rVZVOIjp2KEIZsnz90mX6E2_xnwVPQZpVVQVJMuMVU0,9834
-markdown/extensions/def_list.py,sha256=iqRXAEl2XnyF415afCxihAgOmEUOK1hIuBPIK1k7Tzo,3521
-markdown/extensions/extra.py,sha256=udRN8OvSWcq3UwkPygvsFl1RlCVtCJ-ARVg2IwVH6VY,1831
-markdown/extensions/fenced_code.py,sha256=dww9rDu2kQtkoTpjn9BBgeGCTNdE1bMPJ2wgR6695iM,3897
-markdown/extensions/footnotes.py,sha256=a9sb8RoKqFU8p8ZhpTObrn_Uek0hbyPFVGYpRaEDXaw,15339
-markdown/extensions/legacy_attrs.py,sha256=2EaVQkxQoNnP8_lMPvGRBdNda8L4weUQroiyEuVdS-w,2547
-markdown/extensions/legacy_em.py,sha256=9ZMGCTrFh01eiOpnFjS0jVkqgYXiTzCGn-eNvYcvObg,1579
-markdown/extensions/md_in_html.py,sha256=ohSiGcgR5yBqusuTs0opbTO_5fq442fqPK-klFd_qaM,4040
-markdown/extensions/meta.py,sha256=EUfkzM7l7UpH__Or9K3pl8ldVddwndlCZWA3d712RAE,2331
-markdown/extensions/nl2br.py,sha256=wAqTNOuf2L1NzlEvEqoID70n9y-aiYaGLkuyQk3CD0w,783
-markdown/extensions/sane_lists.py,sha256=ZQmCf-247KBexVG0fc62nDvokGkV6W1uavYbieNKSG4,1505
-markdown/extensions/smarty.py,sha256=0padzkVCNACainKw-Xj1S5UfT0125VCTfNejmrCZItA,10238
-markdown/extensions/tables.py,sha256=bicFx_wqhnEx6Y_8MJqA56rh71pt5fOe94oiWbvcobY,7685
-markdown/extensions/toc.py,sha256=E-d3R4etcM_R2sQyTpKkejRv2NHrHPCvaXK9hUqfK58,13224
-markdown/extensions/wikilinks.py,sha256=GkgT9BY7b1-qW--dIwFAhC9V20RoeF13b7CFdw_V21Q,2812
-markdown/inlinepatterns.py,sha256=EnYq9aU_Hi1gu5e8dcbUxUu0mRz-pHFV79uGQCYbD5I,29378
-markdown/pep562.py,sha256=5UkqT7sb-cQufgbOl_jF-RYUVVHS7VThzlMzR9vrd3I,8917
-markdown/postprocessors.py,sha256=25g6qqpJ4kuiq4RBrGz8RA6GMb7ArUi1AN2VDVnR35U,3738
-markdown/preprocessors.py,sha256=dsmMVPP2afKAZ0s59_mFidM_mCiNfgdBJ9aVDWu_viE,15323
-markdown/serializers.py,sha256=_wQl-iJrPSUEQ4Q1owWYqN9qceVh6TOlAOH_i44BKAQ,6540
-markdown/test_tools.py,sha256=zFHFzmtzjfMRroyyli3LY4SP8yLfLf4S7SsU3z7Z1SQ,6823
-markdown/treeprocessors.py,sha256=NBaYc9TEGP7TBaN6YRROIqE5Lj-AMoAqp0jN-coGW3Q,15401
-markdown/util.py,sha256=0ySktJgYplEV7g6TOOs8fatAS4Fi-6F7iv4D9Vw3g0c,15201
diff --git a/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/WHEEL b/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/WHEEL
deleted file mode 100644
index 78e6f69..0000000
--- a/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/WHEEL
+++ /dev/null
@@ -1,6 +0,0 @@
-Wheel-Version: 1.0
-Generator: bdist_wheel (0.33.4)
-Root-Is-Purelib: true
-Tag: py2-none-any
-Tag: py3-none-any
-
diff --git a/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/entry_points.txt b/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/entry_points.txt
deleted file mode 100644
index f49693d..0000000
--- a/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/entry_points.txt
+++ /dev/null
@@ -1,23 +0,0 @@
-[console_scripts]
-markdown_py = markdown.__main__:run
-
-[markdown.extensions]
-abbr = markdown.extensions.abbr:AbbrExtension
-admonition = markdown.extensions.admonition:AdmonitionExtension
-attr_list = markdown.extensions.attr_list:AttrListExtension
-codehilite = markdown.extensions.codehilite:CodeHiliteExtension
-def_list = markdown.extensions.def_list:DefListExtension
-extra = markdown.extensions.extra:ExtraExtension
-fenced_code = markdown.extensions.fenced_code:FencedCodeExtension
-footnotes = markdown.extensions.footnotes:FootnoteExtension
-legacy_attrs = markdown.extensions.legacy_attrs:LegacyAttrExtension
-legacy_em = markdown.extensions.legacy_em:LegacyEmExtension
-md_in_html = markdown.extensions.md_in_html:MarkdownInHtmlExtension
-meta = markdown.extensions.meta:MetaExtension
-nl2br = markdown.extensions.nl2br:Nl2BrExtension
-sane_lists = markdown.extensions.sane_lists:SaneListExtension
-smarty = markdown.extensions.smarty:SmartyExtension
-tables = markdown.extensions.tables:TableExtension
-toc = markdown.extensions.toc:TocExtension
-wikilinks = markdown.extensions.wikilinks:WikiLinkExtension
-
diff --git a/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/top_level.txt
deleted file mode 100644
index 0918c97..0000000
--- a/venv/lib/python3.8/site-packages/Markdown-3.2.1.dist-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-markdown
diff --git a/venv/lib/python3.8/site-packages/__pycache__/easy_install.cpython-38.pyc b/venv/lib/python3.8/site-packages/__pycache__/easy_install.cpython-38.pyc
index 70b4024..6495ebc 100644
Binary files a/venv/lib/python3.8/site-packages/__pycache__/easy_install.cpython-38.pyc and b/venv/lib/python3.8/site-packages/__pycache__/easy_install.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/__init__.cpython-38.pyc
index f6ee23c..d6a6542 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/_compat.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/_compat.cpython-38.pyc
index f91d13e..f82fb0b 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/_compat.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/_compat.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/_identifier.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/_identifier.cpython-38.pyc
index 190453f..28ddb16 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/_identifier.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/_identifier.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/asyncfilters.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/asyncfilters.cpython-38.pyc
index 2d16bca..1a38c64 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/asyncfilters.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/asyncfilters.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/asyncsupport.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/asyncsupport.cpython-38.pyc
index 9f8d8f9..b117e2c 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/asyncsupport.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/asyncsupport.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/bccache.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/bccache.cpython-38.pyc
index d3aa474..c499c12 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/bccache.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/bccache.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/compiler.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/compiler.cpython-38.pyc
index ad500f5..94f92a2 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/compiler.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/compiler.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/constants.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/constants.cpython-38.pyc
index 0c84764..af8f1fb 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/constants.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/constants.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/debug.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/debug.cpython-38.pyc
index 4e6b4c8..3600d2a 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/debug.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/debug.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/defaults.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/defaults.cpython-38.pyc
index ffc808a..aa2c4fe 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/defaults.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/defaults.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/environment.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/environment.cpython-38.pyc
index 106d05d..34d84fb 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/environment.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/environment.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/exceptions.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/exceptions.cpython-38.pyc
index 186c823..ae42d90 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/exceptions.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/exceptions.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/ext.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/ext.cpython-38.pyc
index f02ed07..e3c8da6 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/ext.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/ext.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/filters.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/filters.cpython-38.pyc
index 75a261b..d986775 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/filters.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/filters.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/idtracking.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/idtracking.cpython-38.pyc
index e65c76a..eb341a5 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/idtracking.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/idtracking.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/lexer.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/lexer.cpython-38.pyc
index 58536a5..ff0e889 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/lexer.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/lexer.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/loaders.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/loaders.cpython-38.pyc
index 8c4e86a..29e2ebc 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/loaders.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/loaders.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/meta.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/meta.cpython-38.pyc
index 94e6cfc..a30d506 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/meta.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/meta.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/nativetypes.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/nativetypes.cpython-38.pyc
index ef6ab79..0b50489 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/nativetypes.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/nativetypes.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/nodes.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/nodes.cpython-38.pyc
index dc26d80..7689dc1 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/nodes.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/nodes.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/optimizer.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/optimizer.cpython-38.pyc
index e9a2701..9e40227 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/optimizer.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/optimizer.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/parser.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/parser.cpython-38.pyc
index bf5cfa8..28aeab0 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/parser.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/parser.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/runtime.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/runtime.cpython-38.pyc
index 88987d1..693552a 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/runtime.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/runtime.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/sandbox.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/sandbox.cpython-38.pyc
index f0bc310..e682327 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/sandbox.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/sandbox.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/tests.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/tests.cpython-38.pyc
index 7e64141..b69db5e 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/tests.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/tests.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/utils.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/utils.cpython-38.pyc
index 91027ef..1c11546 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/utils.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/utils.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/jinja2/__pycache__/visitor.cpython-38.pyc b/venv/lib/python3.8/site-packages/jinja2/__pycache__/visitor.cpython-38.pyc
index 45ba90f..8ecd3d3 100644
Binary files a/venv/lib/python3.8/site-packages/jinja2/__pycache__/visitor.cpython-38.pyc and b/venv/lib/python3.8/site-packages/jinja2/__pycache__/visitor.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/__meta__.py b/venv/lib/python3.8/site-packages/markdown/__meta__.py
index ead7c31..c5b5a33 100644
--- a/venv/lib/python3.8/site-packages/markdown/__meta__.py
+++ b/venv/lib/python3.8/site-packages/markdown/__meta__.py
@@ -19,11 +19,6 @@ Copyright 2004 Manfred Stienstra (the original version)
License: BSD (see LICENSE.md for details).
"""
-try:
- import packaging.version
-except ImportError:
- from pkg_resources.extern import packaging
-
# __version_info__ format:
# (major, minor, patch, dev/alpha/beta/rc/final, #)
# (1, 1, 2, 'dev', 0) => "1.1.2.dev0"
@@ -31,25 +26,24 @@ except ImportError:
# (1, 2, 0, 'beta', 2) => "1.2b2"
# (1, 2, 0, 'rc', 4) => "1.2rc4"
# (1, 2, 0, 'final', 0) => "1.2"
-__version_info__ = (3, 2, 1, 'final', 0)
+__version_info__ = (3, 3, 3, 'final', 0)
-def _get_version(): # pragma: no cover
+def _get_version(version_info):
" Returns a PEP 440-compliant version number from version_info. "
- assert len(__version_info__) == 5
- assert __version_info__[3] in ('dev', 'alpha', 'beta', 'rc', 'final')
+ assert len(version_info) == 5
+ assert version_info[3] in ('dev', 'alpha', 'beta', 'rc', 'final')
- parts = 2 if __version_info__[2] == 0 else 3
- v = '.'.join(map(str, __version_info__[:parts]))
+ parts = 2 if version_info[2] == 0 else 3
+ v = '.'.join(map(str, version_info[:parts]))
- if __version_info__[3] == 'dev':
- v += '.dev' + str(__version_info__[4])
- elif __version_info__[3] != 'final':
+ if version_info[3] == 'dev':
+ v += '.dev' + str(version_info[4])
+ elif version_info[3] != 'final':
mapping = {'alpha': 'a', 'beta': 'b', 'rc': 'rc'}
- v += mapping[__version_info__[3]] + str(__version_info__[4])
+ v += mapping[version_info[3]] + str(version_info[4])
- # Ensure version is valid and normalized
- return str(packaging.version.Version(v))
+ return v
-__version__ = _get_version()
+__version__ = _get_version(__version_info__)
diff --git a/venv/lib/python3.8/site-packages/markdown/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/__pycache__/__init__.cpython-38.pyc
index 1516eff..324abdf 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/__pycache__/__main__.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/__pycache__/__main__.cpython-38.pyc
index e84a0f2..9fd2faf 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/__pycache__/__main__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/__pycache__/__main__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/__pycache__/__meta__.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/__pycache__/__meta__.cpython-38.pyc
index 270065a..72224d2 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/__pycache__/__meta__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/__pycache__/__meta__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/__pycache__/blockparser.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/__pycache__/blockparser.cpython-38.pyc
index 0539345..f653e9e 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/__pycache__/blockparser.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/__pycache__/blockparser.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/__pycache__/blockprocessors.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/__pycache__/blockprocessors.cpython-38.pyc
index 09c54fa..2323986 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/__pycache__/blockprocessors.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/__pycache__/blockprocessors.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/__pycache__/core.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/__pycache__/core.cpython-38.pyc
index 1e788b6..6c01de2 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/__pycache__/core.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/__pycache__/core.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/__pycache__/inlinepatterns.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/__pycache__/inlinepatterns.cpython-38.pyc
index 7dd5c2d..cda7e13 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/__pycache__/inlinepatterns.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/__pycache__/inlinepatterns.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/__pycache__/pep562.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/__pycache__/pep562.cpython-38.pyc
index 59d2018..07d675b 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/__pycache__/pep562.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/__pycache__/pep562.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/__pycache__/postprocessors.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/__pycache__/postprocessors.cpython-38.pyc
index e0ffba4..ee5f891 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/__pycache__/postprocessors.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/__pycache__/postprocessors.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/__pycache__/preprocessors.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/__pycache__/preprocessors.cpython-38.pyc
index ed51984..0aadba6 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/__pycache__/preprocessors.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/__pycache__/preprocessors.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/__pycache__/serializers.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/__pycache__/serializers.cpython-38.pyc
index f2133ce..35b9423 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/__pycache__/serializers.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/__pycache__/serializers.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/__pycache__/test_tools.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/__pycache__/test_tools.cpython-38.pyc
index 6f71347..30d0db5 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/__pycache__/test_tools.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/__pycache__/test_tools.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/__pycache__/treeprocessors.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/__pycache__/treeprocessors.cpython-38.pyc
index dfd46d5..8b7daea 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/__pycache__/treeprocessors.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/__pycache__/treeprocessors.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/__pycache__/util.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/__pycache__/util.cpython-38.pyc
index 5dad6a3..a15efec 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/__pycache__/util.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/__pycache__/util.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/blockprocessors.py b/venv/lib/python3.8/site-packages/markdown/blockprocessors.py
index 60baca1..7d31a7f 100644
--- a/venv/lib/python3.8/site-packages/markdown/blockprocessors.py
+++ b/venv/lib/python3.8/site-packages/markdown/blockprocessors.py
@@ -51,6 +51,7 @@ def build_block_parser(md, **kwargs):
parser.blockprocessors.register(OListProcessor(parser), 'olist', 40)
parser.blockprocessors.register(UListProcessor(parser), 'ulist', 30)
parser.blockprocessors.register(BlockQuoteProcessor(parser), 'quote', 20)
+ parser.blockprocessors.register(ReferenceProcessor(parser), 'reference', 15)
parser.blockprocessors.register(ParagraphProcessor(parser), 'paragraph', 10)
return parser
@@ -276,7 +277,7 @@ class BlockQuoteProcessor(BlockProcessor):
RE = re.compile(r'(^|\n)[ ]{0,3}>[ ]?(.*)')
def test(self, parent, block):
- return bool(self.RE.search(block))
+ return bool(self.RE.search(block)) and not util.nearing_recursion_limit()
def run(self, parent, blocks):
block = blocks.pop(0)
@@ -495,16 +496,15 @@ class SetextHeaderProcessor(BlockProcessor):
class HRProcessor(BlockProcessor):
""" Process Horizontal Rules. """
- RE = r'^[ ]{0,3}((-+[ ]{0,2}){3,}|(_+[ ]{0,2}){3,}|(\*+[ ]{0,2}){3,})[ ]*'
+ # Python's re module doesn't officially support atomic grouping. However you can fake it.
+ # See https://stackoverflow.com/a/13577411/866026
+ RE = r'^[ ]{0,3}(?=(?P(-+[ ]{0,2}){3,}|(_+[ ]{0,2}){3,}|(\*+[ ]{0,2}){3,}))(?P=atomicgroup)[ ]*$'
# Detect hr on any line of a block.
SEARCH_RE = re.compile(RE, re.MULTILINE)
def test(self, parent, block):
m = self.SEARCH_RE.search(block)
- # No atomic grouping in python so we simulate it here for performance.
- # The regex only matches what would be in the atomic group - the HR.
- # Then check if we are at end of block or if next char is a newline.
- if m and (m.end() == len(block) or block[m.end()] == '\n'):
+ if m:
# Save match object on class instance so we can use it later.
self.match = m
return True
@@ -554,6 +554,35 @@ class EmptyBlockProcessor(BlockProcessor):
)
+class ReferenceProcessor(BlockProcessor):
+ """ Process link references. """
+ RE = re.compile(
+ r'^[ ]{0,3}\[([^\]]*)\]:[ ]*\n?[ ]*([^\s]+)[ ]*\n?[ ]*((["\'])(.*)\4|\((.*)\))?[ ]*$', re.MULTILINE
+ )
+
+ def test(self, parent, block):
+ return True
+
+ def run(self, parent, blocks):
+ block = blocks.pop(0)
+ m = self.RE.search(block)
+ if m:
+ id = m.group(1).strip().lower()
+ link = m.group(2).lstrip('<').rstrip('>')
+ title = m.group(5) or m.group(6)
+ self.parser.md.references[id] = (link, title)
+ if block[m.end():].strip():
+ # Add any content after match back to blocks as separate block
+ blocks.insert(0, block[m.end():].lstrip('\n'))
+ if block[:m.start()].strip():
+ # Add any content before match back to blocks as separate block
+ blocks.insert(0, block[:m.start()].rstrip('\n'))
+ return True
+ # No match. Restore block.
+ blocks.insert(0, block)
+ return False
+
+
class ParagraphProcessor(BlockProcessor):
""" Process Paragraph blocks. """
diff --git a/venv/lib/python3.8/site-packages/markdown/core.py b/venv/lib/python3.8/site-packages/markdown/core.py
index 6c7822c..2f7f2d5 100644
--- a/venv/lib/python3.8/site-packages/markdown/core.py
+++ b/venv/lib/python3.8/site-packages/markdown/core.py
@@ -23,7 +23,6 @@ import codecs
import sys
import logging
import importlib
-import pkg_resources
from . import util
from .preprocessors import build_preprocessors
from .blockprocessors import build_block_parser
@@ -78,11 +77,12 @@ class Markdown:
# See https://w3c.github.io/html/grouping-content.html#the-p-element
'address', 'article', 'aside', 'blockquote', 'details', 'div', 'dl',
'fieldset', 'figcaption', 'figure', 'footer', 'form', 'h1', 'h2', 'h3',
- 'h4', 'h5', 'h6', 'header', 'hr', 'main', 'menu', 'nav', 'ol', 'p', 'pre',
- 'section', 'table', 'ul',
+ 'h4', 'h5', 'h6', 'header', 'hgroup', 'hr', 'main', 'menu', 'nav', 'ol',
+ 'p', 'pre', 'section', 'table', 'ul',
# Other elements which Markdown should not be mucking up the contents of.
- 'canvas', 'dd', 'dt', 'group', 'iframe', 'li', 'math', 'noscript', 'output',
- 'progress', 'script', 'style', 'tbody', 'td', 'th', 'thead', 'tr', 'video'
+ 'canvas', 'colgroup', 'dd', 'body', 'dt', 'group', 'iframe', 'li', 'legend',
+ 'math', 'map', 'noscript', 'output', 'object', 'option', 'progress', 'script',
+ 'style', 'tbody', 'td', 'textarea', 'tfoot', 'th', 'thead', 'tr', 'video'
]
self.registeredExtensions = []
@@ -141,9 +141,8 @@ class Markdown:
Build extension from a string name, then return an instance.
First attempt to load an entry point. The string name must be registered as an entry point in the
- `markdown.extensions` group which points to a subclass of the `markdown.extensions.Extension` class. If
- multiple distributions have registered the same name, the first one found by `pkg_resources.iter_entry_points`
- is returned.
+ `markdown.extensions` group which points to a subclass of the `markdown.extensions.Extension` class.
+ If multiple distributions have registered the same name, the first one found is returned.
If no entry point is found, assume dot notation (`path.to.module:ClassName`). Load the specified class and
return an instance. If no class is specified, import the module and call a `makeExtension` function and return
@@ -151,7 +150,7 @@ class Markdown:
"""
configs = dict(configs)
- entry_points = [ep for ep in pkg_resources.iter_entry_points('markdown.extensions', ext_name)]
+ entry_points = [ep for ep in util.INSTALLED_EXTENSIONS if ep.name == ext_name]
if entry_points:
ext = entry_points[0].load()
return ext(**configs)
@@ -278,14 +277,14 @@ class Markdown:
'<%s>' % self.doc_tag) + len(self.doc_tag) + 2
end = output.rindex('%s>' % self.doc_tag)
output = output[start:end].strip()
- except ValueError: # pragma: no cover
+ except ValueError as e: # pragma: no cover
if output.strip().endswith('<%s />' % self.doc_tag):
# We have an empty document
output = ''
else:
# We have a serious problem
raise ValueError('Markdown failed to strip top-level '
- 'tags. Document=%r' % output.strip())
+ 'tags. Document=%r' % output.strip()) from e
# Run the text post-processors
for pp in self.postprocessors:
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__init__.py b/venv/lib/python3.8/site-packages/markdown/extensions/__init__.py
index 010e310..4bc8e5f 100644
--- a/venv/lib/python3.8/site-packages/markdown/extensions/__init__.py
+++ b/venv/lib/python3.8/site-packages/markdown/extensions/__init__.py
@@ -75,15 +75,18 @@ class Extension:
md = args[0]
try:
self.extendMarkdown(md)
- except TypeError:
- # Must be a 2.x extension. Pass in a dumby md_globals.
- self.extendMarkdown(md, {})
- warnings.warn(
- "The 'md_globals' parameter of '{}.{}.extendMarkdown' is "
- "deprecated.".format(self.__class__.__module__, self.__class__.__name__),
- category=DeprecationWarning,
- stacklevel=2
- )
+ except TypeError as e:
+ if "missing 1 required positional argument" in str(e):
+ # Must be a 2.x extension. Pass in a dumby md_globals.
+ self.extendMarkdown(md, {})
+ warnings.warn(
+ "The 'md_globals' parameter of '{}.{}.extendMarkdown' is "
+ "deprecated.".format(self.__class__.__module__, self.__class__.__name__),
+ category=DeprecationWarning,
+ stacklevel=2
+ )
+ else:
+ raise
def extendMarkdown(self, md):
"""
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/__init__.cpython-38.pyc
index 9d4d582..347abe4 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/abbr.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/abbr.cpython-38.pyc
index af8f21f..c9b60c6 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/abbr.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/abbr.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/admonition.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/admonition.cpython-38.pyc
index df9cb82..5b0e898 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/admonition.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/admonition.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/attr_list.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/attr_list.cpython-38.pyc
index 5249e03..e4e0e81 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/attr_list.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/attr_list.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/codehilite.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/codehilite.cpython-38.pyc
index 1789dde..6a2cfb5 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/codehilite.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/codehilite.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/def_list.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/def_list.cpython-38.pyc
index b596afa..e382d74 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/def_list.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/def_list.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/extra.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/extra.cpython-38.pyc
index f66cb75..e2285fb 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/extra.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/extra.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/fenced_code.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/fenced_code.cpython-38.pyc
index 4c43484..28393fa 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/fenced_code.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/fenced_code.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/footnotes.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/footnotes.cpython-38.pyc
index d446ac2..d0dc74c 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/footnotes.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/footnotes.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/legacy_attrs.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/legacy_attrs.cpython-38.pyc
index 1b64530..af5380f 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/legacy_attrs.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/legacy_attrs.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/legacy_em.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/legacy_em.cpython-38.pyc
index 2dcb3db..f28d3ff 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/legacy_em.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/legacy_em.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/md_in_html.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/md_in_html.cpython-38.pyc
index af63947..fa39fde 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/md_in_html.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/md_in_html.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/meta.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/meta.cpython-38.pyc
index 9200890..ea7ed84 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/meta.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/meta.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/nl2br.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/nl2br.cpython-38.pyc
index 6eb574f..cb2251c 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/nl2br.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/nl2br.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/sane_lists.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/sane_lists.cpython-38.pyc
index dec36ec..c2915ff 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/sane_lists.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/sane_lists.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/smarty.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/smarty.cpython-38.pyc
index 7b5972a..c347439 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/smarty.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/smarty.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/tables.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/tables.cpython-38.pyc
index c81a34b..1223856 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/tables.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/tables.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/toc.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/toc.cpython-38.pyc
index 0856e26..7877484 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/toc.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/toc.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/wikilinks.cpython-38.pyc b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/wikilinks.cpython-38.pyc
index f1c945d..2102caf 100644
Binary files a/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/wikilinks.cpython-38.pyc and b/venv/lib/python3.8/site-packages/markdown/extensions/__pycache__/wikilinks.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/abbr.py b/venv/lib/python3.8/site-packages/markdown/extensions/abbr.py
index b53f2c4..9879314 100644
--- a/venv/lib/python3.8/site-packages/markdown/extensions/abbr.py
+++ b/venv/lib/python3.8/site-packages/markdown/extensions/abbr.py
@@ -17,48 +17,53 @@ License: [BSD](https://opensource.org/licenses/bsd-license.php)
'''
from . import Extension
-from ..preprocessors import Preprocessor
+from ..blockprocessors import BlockProcessor
from ..inlinepatterns import InlineProcessor
from ..util import AtomicString
import re
import xml.etree.ElementTree as etree
-# Global Vars
-ABBR_REF_RE = re.compile(r'[*]\[(?P[^\]]*)\][ ]?:\s*(?P.*)')
-
class AbbrExtension(Extension):
""" Abbreviation Extension for Python-Markdown. """
def extendMarkdown(self, md):
""" Insert AbbrPreprocessor before ReferencePreprocessor. """
- md.preprocessors.register(AbbrPreprocessor(md), 'abbr', 12)
+ md.parser.blockprocessors.register(AbbrPreprocessor(md.parser), 'abbr', 16)
-class AbbrPreprocessor(Preprocessor):
+class AbbrPreprocessor(BlockProcessor):
""" Abbreviation Preprocessor - parse text for abbr references. """
- def run(self, lines):
+ RE = re.compile(r'^[*]\[(?P[^\]]*)\][ ]?:[ ]*\n?[ ]*(?P.*)$', re.MULTILINE)
+
+ def test(self, parent, block):
+ return True
+
+ def run(self, parent, blocks):
'''
Find and remove all Abbreviation references from the text.
Each reference is set as a new AbbrPattern in the markdown instance.
'''
- new_text = []
- for line in lines:
- m = ABBR_REF_RE.match(line)
- if m:
- abbr = m.group('abbr').strip()
- title = m.group('title').strip()
- self.md.inlinePatterns.register(
- AbbrInlineProcessor(self._generate_pattern(abbr), title), 'abbr-%s' % abbr, 2
- )
- # Preserve the line to prevent raw HTML indexing issue.
- # https://github.com/Python-Markdown/markdown/issues/584
- new_text.append('')
- else:
- new_text.append(line)
- return new_text
+ block = blocks.pop(0)
+ m = self.RE.search(block)
+ if m:
+ abbr = m.group('abbr').strip()
+ title = m.group('title').strip()
+ self.parser.md.inlinePatterns.register(
+ AbbrInlineProcessor(self._generate_pattern(abbr), title), 'abbr-%s' % abbr, 2
+ )
+ if block[m.end():].strip():
+ # Add any content after match back to blocks as separate block
+ blocks.insert(0, block[m.end():].lstrip('\n'))
+ if block[:m.start()].strip():
+ # Add any content before match back to blocks as separate block
+ blocks.insert(0, block[:m.start()].rstrip('\n'))
+ return True
+ # No match. Restore block.
+ blocks.insert(0, block)
+ return False
def _generate_pattern(self, text):
'''
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/admonition.py b/venv/lib/python3.8/site-packages/markdown/extensions/admonition.py
index 3926628..01f9940 100644
--- a/venv/lib/python3.8/site-packages/markdown/extensions/admonition.py
+++ b/venv/lib/python3.8/site-packages/markdown/extensions/admonition.py
@@ -40,19 +40,82 @@ class AdmonitionProcessor(BlockProcessor):
RE = re.compile(r'(?:^|\n)!!! ?([\w\-]+(?: +[\w\-]+)*)(?: +"(.*?)")? *(?:\n|$)')
RE_SPACES = re.compile(' +')
- def test(self, parent, block):
+ def __init__(self, parser):
+ """Initialization."""
+
+ super().__init__(parser)
+
+ self.current_sibling = None
+ self.content_indention = 0
+
+ def get_sibling(self, parent, block):
+ """Get sibling admontion.
+
+ Retrieve the appropriate siblimg element. This can get trickly when
+ dealing with lists.
+
+ """
+
+ # We already acquired the block via test
+ if self.current_sibling is not None:
+ sibling = self.current_sibling
+ block = block[self.content_indent:]
+ self.current_sibling = None
+ self.content_indent = 0
+ return sibling, block
+
sibling = self.lastChild(parent)
- return self.RE.search(block) or \
- (block.startswith(' ' * self.tab_length) and sibling is not None and
- sibling.get('class', '').find(self.CLASSNAME) != -1)
+
+ if sibling is None or sibling.get('class', '').find(self.CLASSNAME) == -1:
+ sibling = None
+ else:
+ # If the last child is a list and the content is idented sufficient
+ # to be under it, then the content's is sibling is in the list.
+ last_child = self.lastChild(sibling)
+ indent = 0
+ while last_child:
+ if (
+ sibling and block.startswith(' ' * self.tab_length * 2) and
+ last_child and last_child.tag in ('ul', 'ol', 'dl')
+ ):
+
+ # The expectation is that we'll find an or .
+ # We should get it's last child as well.
+ sibling = self.lastChild(last_child)
+ last_child = self.lastChild(sibling) if sibling else None
+
+ # Context has been lost at this point, so we must adjust the
+ # text's identation level so it will be evaluated correctly
+ # under the list.
+ block = block[self.tab_length:]
+ indent += self.tab_length
+ else:
+ last_child = None
+
+ if not block.startswith(' ' * self.tab_length):
+ sibling = None
+
+ if sibling is not None:
+ self.current_sibling = sibling
+ self.content_indent = indent
+
+ return sibling, block
+
+ def test(self, parent, block):
+
+ if self.RE.search(block):
+ return True
+ else:
+ return self.get_sibling(parent, block)[0] is not None
def run(self, parent, blocks):
- sibling = self.lastChild(parent)
block = blocks.pop(0)
m = self.RE.search(block)
if m:
block = block[m.end():] # removes the first line
+ else:
+ sibling, block = self.get_sibling(parent, block)
block, theRest = self.detab(block)
@@ -65,6 +128,13 @@ class AdmonitionProcessor(BlockProcessor):
p.text = title
p.set('class', self.CLASSNAME_TITLE)
else:
+ # Sibling is a list item, but we need to wrap it's content should be wrapped in
+ if sibling.tag in ('li', 'dd') and sibling.text:
+ text = sibling.text
+ sibling.text = ''
+ p = etree.SubElement(sibling, 'p')
+ p.text = text
+
div = sibling
self.parser.parseChunk(div, block)
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/attr_list.py b/venv/lib/python3.8/site-packages/markdown/extensions/attr_list.py
index 23c6ad0..9a67551 100644
--- a/venv/lib/python3.8/site-packages/markdown/extensions/attr_list.py
+++ b/venv/lib/python3.8/site-packages/markdown/extensions/attr_list.py
@@ -64,10 +64,10 @@ def isheader(elem):
class AttrListTreeprocessor(Treeprocessor):
- BASE_RE = r'\{\:?([^\}\n]*)\}'
- HEADER_RE = re.compile(r'[ ]+%s[ ]*$' % BASE_RE)
- BLOCK_RE = re.compile(r'\n[ ]*%s[ ]*$' % BASE_RE)
- INLINE_RE = re.compile(r'^%s' % BASE_RE)
+ BASE_RE = r'\{\:?[ ]*([^\}\n ][^\}\n]*)[ ]*\}'
+ HEADER_RE = re.compile(r'[ ]+{}[ ]*$'.format(BASE_RE))
+ BLOCK_RE = re.compile(r'\n[ ]*{}[ ]*$'.format(BASE_RE))
+ INLINE_RE = re.compile(r'^{}'.format(BASE_RE))
NAME_RE = re.compile(r'[^A-Z_a-z\u00c0-\u00d6\u00d8-\u00f6\u00f8-\u02ff'
r'\u0370-\u037d\u037f-\u1fff\u200c-\u200d'
r'\u2070-\u218f\u2c00-\u2fef\u3001-\ud7ff'
@@ -79,8 +79,8 @@ class AttrListTreeprocessor(Treeprocessor):
if self.md.is_block_level(elem.tag):
# Block level: check for attrs on last line of text
RE = self.BLOCK_RE
- if isheader(elem) or elem.tag == 'dt':
- # header or def-term: check for attrs at end of line
+ if isheader(elem) or elem.tag in ['dt', 'td', 'th']:
+ # header, def-term, or table cell: check for attrs at end of element
RE = self.HEADER_RE
if len(elem) and elem.tag == 'li':
# special case list items. children may include a ul or ol.
@@ -120,8 +120,6 @@ class AttrListTreeprocessor(Treeprocessor):
elif elem.text:
# no children. Get from text.
m = RE.search(elem.text)
- if not m and elem.tag == 'td':
- m = re.search(self.BASE_RE, elem.text)
if m:
self.assign_attrs(elem, m.group(1))
elem.text = elem.text[:m.start()]
@@ -161,6 +159,7 @@ class AttrListTreeprocessor(Treeprocessor):
class AttrListExtension(Extension):
def extendMarkdown(self, md):
md.treeprocessors.register(AttrListTreeprocessor(md), 'attr_list', 8)
+ md.registerExtension(self)
def makeExtension(**kwargs): # pragma: no cover
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/codehilite.py b/venv/lib/python3.8/site-packages/markdown/extensions/codehilite.py
index c3f3257..9eed561 100644
--- a/venv/lib/python3.8/site-packages/markdown/extensions/codehilite.py
+++ b/venv/lib/python3.8/site-packages/markdown/extensions/codehilite.py
@@ -17,13 +17,14 @@ License: [BSD](https://opensource.org/licenses/bsd-license.php)
from . import Extension
from ..treeprocessors import Treeprocessor
+from ..util import parseBoolValue
-try:
+try: # pragma: no cover
from pygments import highlight
from pygments.lexers import get_lexer_by_name, guess_lexer
from pygments.formatters import get_formatter_by_name
pygments = True
-except ImportError:
+except ImportError: # pragma: no cover
pygments = False
@@ -38,52 +39,78 @@ def parse_hl_lines(expr):
try:
return list(map(int, expr.split()))
- except ValueError:
+ except ValueError: # pragma: no cover
return []
# ------------------ The Main CodeHilite Class ----------------------
class CodeHilite:
"""
- Determine language of source code, and pass it into pygments hilighter.
+ Determine language of source code, and pass it on to the Pygments highlighter.
- Basic Usage:
- >>> code = CodeHilite(src = 'some text')
- >>> html = code.hilite()
+ Usage:
+ code = CodeHilite(src=some_code, lang='python')
+ html = code.hilite()
+ Arguments:
* src: Source string or any object with a .readline attribute.
- * linenums: (Boolean) Set line numbering to 'on' (True),
- 'off' (False) or 'auto'(None). Set to 'auto' by default.
+ * lang: String name of Pygments lexer to use for highlighting. Default: `None`.
- * guess_lang: (Boolean) Turn language auto-detection
- 'on' or 'off' (on by default).
+ * guess_lang: Auto-detect which lexer to use. Ignored if `lang` is set to a valid
+ value. Default: `True`.
- * css_class: Set class name of wrapper div ('codehilite' by default).
+ * use_pygments: Pass code to pygments for code highlighting. If `False`, the code is
+ instead wrapped for highlighting by a JavaScript library. Default: `True`.
- * hl_lines: (List of integers) Lines to emphasize, 1-indexed.
+ * linenums: An alias to Pygments `linenos` formatter option. Default: `None`.
- Low Level Usage:
- >>> code = CodeHilite()
- >>> code.src = 'some text' # String or anything with a .readline attr.
- >>> code.linenos = True # Turns line numbering on or of.
- >>> html = code.hilite()
+ * css_class: An alias to Pygments `cssclass` formatter option. Default: 'codehilite'.
+
+ * lang_prefix: Prefix prepended to the language when `use_pygments` is `False`.
+ Default: "language-".
+
+ Other Options:
+ Any other options are accepted and passed on to the lexer and formatter. Therefore,
+ valid options include any options which are accepted by the `html` formatter or
+ whichever lexer the code's language uses. Note that most lexers do not have any
+ options. However, a few have very useful options, such as PHP's `startinline` option.
+ Any invalid options are ignored without error.
+
+ Formatter options: https://pygments.org/docs/formatters/#HtmlFormatter
+ Lexer Options: https://pygments.org/docs/lexers/
+
+ Advanced Usage:
+ code = CodeHilite(
+ src = some_code,
+ lang = 'php',
+ startinline = True, # Lexer option. Snippet does not start with `%s\n' % \
- (self.css_class, class_str, txt)
+ class_str = ' class="{}"'.format(' '.join(classes))
+ return '
{}\n \n'.format(
+ self.options['cssclass'],
+ class_str,
+ txt
+ )
def _parseHeader(self):
"""
- Determines language of a code block from shebang line and whether said
- line should be removed or left in place. If the sheband line contains a
- path (even a single /) then it is assumed to be a real shebang line and
- left alone. However, if no path is given (e.i.: #!python or :::python)
- then it is assumed to be a mock shebang for language identifitation of
- a code fragment and removed from the code block prior to processing for
- code highlighting. When a mock shebang (e.i: #!python) is found, line
- numbering is turned on. When colons are found in place of a shebang
- (e.i.: :::python), line numbering is left in the current state - off
- by default.
+ Determines language of a code block from shebang line and whether the
+ said line should be removed or left in place. If the sheband line
+ contains a path (even a single /) then it is assumed to be a real
+ shebang line and left alone. However, if no path is given
+ (e.i.: #!python or :::python) then it is assumed to be a mock shebang
+ for language identification of a code fragment and removed from the
+ code block prior to processing for code highlighting. When a mock
+ shebang (e.i: #!python) is found, line numbering is turned on. When
+ colons are found in place of a shebang (e.i.: :::python), line
+ numbering is left in the current state - off by default.
Also parses optional list of highlight lines, like:
@@ -176,16 +200,16 @@ class CodeHilite:
# we have a match
try:
self.lang = m.group('lang').lower()
- except IndexError:
+ except IndexError: # pragma: no cover
self.lang = None
if m.group('path'):
# path exists - restore first line
lines.insert(0, fl)
- if self.linenums is None and m.group('shebang'):
+ if self.options['linenos'] is None and m.group('shebang'):
# Overridable and Shebang exists - use line numbers
- self.linenums = True
+ self.options['linenos'] = True
- self.hl_lines = parse_hl_lines(m.group('hl_lines'))
+ self.options['hl_lines'] = parse_hl_lines(m.group('hl_lines'))
else:
# No match
lines.insert(0, fl)
@@ -201,9 +225,11 @@ class HiliteTreeprocessor(Treeprocessor):
def code_unescape(self, text):
"""Unescape code."""
- text = text.replace("&", "&")
text = text.replace("<", "<")
text = text.replace(">", ">")
+ # Escaped '&' should be replaced at the end to avoid
+ # conflicting with < and >.
+ text = text.replace("&", "&")
return text
def run(self, root):
@@ -213,13 +239,9 @@ class HiliteTreeprocessor(Treeprocessor):
if len(block) == 1 and block[0].tag == 'code':
code = CodeHilite(
self.code_unescape(block[0].text),
- linenums=self.config['linenums'],
- guess_lang=self.config['guess_lang'],
- css_class=self.config['css_class'],
- style=self.config['pygments_style'],
- noclasses=self.config['noclasses'],
tab_length=self.md.tab_length,
- use_pygments=self.config['use_pygments']
+ style=self.config.pop('pygments_style', 'default'),
+ **self.config
)
placeholder = self.md.htmlStash.store(code.hilite())
# Clear codeblock in etree instance
@@ -237,7 +259,7 @@ class CodeHiliteExtension(Extension):
# define default configs
self.config = {
'linenums': [None,
- "Use lines numbers. True=yes, False=no, None=auto"],
+ "Use lines numbers. True|table|inline=yes, False=no, None=auto"],
'guess_lang': [True,
"Automatic language detection - Default: True"],
'css_class': ["codehilite",
@@ -252,10 +274,25 @@ class CodeHiliteExtension(Extension):
'use_pygments': [True,
'Use Pygments to Highlight code blocks. '
'Disable if using a JavaScript library. '
- 'Default: True']
+ 'Default: True'],
+ 'lang_prefix': [
+ 'language-',
+ 'Prefix prepended to the language when use_pygments is false. Default: "language-"'
+ ]
}
- super().__init__(**kwargs)
+ for key, value in kwargs.items():
+ if key in self.config:
+ self.setConfig(key, value)
+ else:
+ # manually set unknown keywords.
+ if isinstance(value, str):
+ try:
+ # Attempt to parse str as a bool value
+ value = parseBoolValue(value, preserve_none=True)
+ except ValueError:
+ pass # Assume it's not a bool value. Use as-is.
+ self.config[key] = [value, '']
def extendMarkdown(self, md):
""" Add HilitePostprocessor to Markdown instance. """
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/def_list.py b/venv/lib/python3.8/site-packages/markdown/extensions/def_list.py
index 3978b4d..0e8e452 100644
--- a/venv/lib/python3.8/site-packages/markdown/extensions/def_list.py
+++ b/venv/lib/python3.8/site-packages/markdown/extensions/def_list.py
@@ -34,8 +34,8 @@ class DefListProcessor(BlockProcessor):
raw_block = blocks.pop(0)
m = self.RE.search(raw_block)
- terms = [l.strip() for l in
- raw_block[:m.start()].split('\n') if l.strip()]
+ terms = [term.strip() for term in
+ raw_block[:m.start()].split('\n') if term.strip()]
block = raw_block[m.end():]
no_indent = self.NO_INDENT_RE.match(block)
if no_indent:
@@ -87,11 +87,13 @@ class DefListProcessor(BlockProcessor):
class DefListIndentProcessor(ListIndentProcessor):
""" Process indented children of definition list items. """
- ITEM_TYPES = ['dd']
- LIST_TYPES = ['dl']
+ # Defintion lists need to be aware of all list types
+ ITEM_TYPES = ['dd', 'li']
+ LIST_TYPES = ['dl', 'ol', 'ul']
def create_item(self, parent, block):
- """ Create a new dd and parse the block with it as the parent. """
+ """ Create a new dd or li (depending on parent) and parse the block with it as the parent. """
+
dd = etree.SubElement(parent, 'dd')
self.parser.parseBlocks(dd, [block])
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/fenced_code.py b/venv/lib/python3.8/site-packages/markdown/extensions/fenced_code.py
index 71fac1a..716b467 100644
--- a/venv/lib/python3.8/site-packages/markdown/extensions/fenced_code.py
+++ b/venv/lib/python3.8/site-packages/markdown/extensions/fenced_code.py
@@ -15,78 +15,130 @@ All changes Copyright 2008-2014 The Python Markdown Project
License: [BSD](https://opensource.org/licenses/bsd-license.php)
"""
+
+from textwrap import dedent
from . import Extension
from ..preprocessors import Preprocessor
from .codehilite import CodeHilite, CodeHiliteExtension, parse_hl_lines
+from .attr_list import get_attrs, AttrListExtension
+from ..util import parseBoolValue
import re
class FencedCodeExtension(Extension):
+ def __init__(self, **kwargs):
+ self.config = {
+ 'lang_prefix': ['language-', 'Prefix prepended to the language. Default: "language-"']
+ }
+ super().__init__(**kwargs)
def extendMarkdown(self, md):
""" Add FencedBlockPreprocessor to the Markdown instance. """
md.registerExtension(self)
- md.preprocessors.register(FencedBlockPreprocessor(md), 'fenced_code_block', 25)
+ md.preprocessors.register(FencedBlockPreprocessor(md, self.getConfigs()), 'fenced_code_block', 25)
class FencedBlockPreprocessor(Preprocessor):
- FENCED_BLOCK_RE = re.compile(r'''
-(?P^(?:~{3,}|`{3,}))[ ]* # Opening ``` or ~~~
-(\{?\.?(?P[\w#.+-]*))?[ ]* # Optional {, and lang
-# Optional highlight lines, single- or double-quote-delimited
-(hl_lines=(?P"|')(?P.*?)(?P=quot))?[ ]*
-}?[ ]*\n # Optional closing }
-(?P.*?)(?<=\n)
-(?P=fence)[ ]*$''', re.MULTILINE | re.DOTALL | re.VERBOSE)
- CODE_WRAP = '%s '
- LANG_TAG = ' class="%s"'
+ FENCED_BLOCK_RE = re.compile(
+ dedent(r'''
+ (?P^(?:~{3,}|`{3,}))[ ]* # opening fence
+ ((\{(?P[^\}\n]*)\})?| # (optional {attrs} or
+ (\.?(?P[\w#.+-]*))?[ ]* # optional (.)lang
+ (hl_lines=(?P"|')(?P.*?)(?P=quot))?) # optional hl_lines)
+ [ ]*\n # newline (end of opening fence)
+ (?P.*?)(?<=\n) # the code block
+ (?P=fence)[ ]*$ # closing fence
+ '''),
+ re.MULTILINE | re.DOTALL | re.VERBOSE
+ )
- def __init__(self, md):
+ def __init__(self, md, config):
super().__init__(md)
-
- self.checked_for_codehilite = False
+ self.config = config
+ self.checked_for_deps = False
self.codehilite_conf = {}
+ self.use_attr_list = False
+ # List of options to convert to bool values
+ self.bool_options = [
+ 'linenums',
+ 'guess_lang',
+ 'noclasses',
+ 'use_pygments'
+ ]
def run(self, lines):
""" Match and store Fenced Code Blocks in the HtmlStash. """
- # Check for code hilite extension
- if not self.checked_for_codehilite:
+ # Check for dependent extensions
+ if not self.checked_for_deps:
for ext in self.md.registeredExtensions:
if isinstance(ext, CodeHiliteExtension):
- self.codehilite_conf = ext.config
- break
+ self.codehilite_conf = ext.getConfigs()
+ if isinstance(ext, AttrListExtension):
+ self.use_attr_list = True
- self.checked_for_codehilite = True
+ self.checked_for_deps = True
text = "\n".join(lines)
while 1:
m = self.FENCED_BLOCK_RE.search(text)
if m:
- lang = ''
- if m.group('lang'):
- lang = self.LANG_TAG % m.group('lang')
+ lang, id, classes, config = None, '', [], {}
+ if m.group('attrs'):
+ id, classes, config = self.handle_attrs(get_attrs(m.group('attrs')))
+ if len(classes):
+ lang = classes.pop(0)
+ else:
+ if m.group('lang'):
+ lang = m.group('lang')
+ if m.group('hl_lines'):
+ # Support hl_lines outside of attrs for backward-compatibility
+ config['hl_lines'] = parse_hl_lines(m.group('hl_lines'))
# If config is not empty, then the codehighlite extension
# is enabled, so we call it to highlight the code
- if self.codehilite_conf:
+ if self.codehilite_conf and self.codehilite_conf['use_pygments'] and config.get('use_pygments', True):
+ local_config = self.codehilite_conf.copy()
+ local_config.update(config)
+ # Combine classes with cssclass. Ensure cssclass is at end
+ # as pygments appends a suffix under certain circumstances.
+ # Ignore ID as Pygments does not offer an option to set it.
+ if classes:
+ local_config['css_class'] = '{} {}'.format(
+ ' '.join(classes),
+ local_config['css_class']
+ )
highliter = CodeHilite(
m.group('code'),
- linenums=self.codehilite_conf['linenums'][0],
- guess_lang=self.codehilite_conf['guess_lang'][0],
- css_class=self.codehilite_conf['css_class'][0],
- style=self.codehilite_conf['pygments_style'][0],
- use_pygments=self.codehilite_conf['use_pygments'][0],
- lang=(m.group('lang') or None),
- noclasses=self.codehilite_conf['noclasses'][0],
- hl_lines=parse_hl_lines(m.group('hl_lines'))
+ lang=lang,
+ style=local_config.pop('pygments_style', 'default'),
+ **local_config
)
code = highliter.hilite()
else:
- code = self.CODE_WRAP % (lang,
- self._escape(m.group('code')))
+ id_attr = lang_attr = class_attr = kv_pairs = ''
+ if lang:
+ lang_attr = ' class="{}{}"'.format(self.config.get('lang_prefix', 'language-'), lang)
+ if classes:
+ class_attr = ' class="{}"'.format(' '.join(classes))
+ if id:
+ id_attr = ' id="{}"'.format(id)
+ if self.use_attr_list and config and not config.get('use_pygments', False):
+ # Only assign key/value pairs to code element if attr_list ext is enabled, key/value pairs
+ # were defined on the code block, and the `use_pygments` key was not set to True. The
+ # `use_pygments` key could be either set to False or not defined. It is omitted from output.
+ kv_pairs = ' ' + ' '.join(
+ '{k}="{v}"'.format(k=k, v=v) for k, v in config.items() if k != 'use_pygments'
+ )
+ code = '{code} '.format(
+ id=id_attr,
+ cls=class_attr,
+ lang=lang_attr,
+ kv=kv_pairs,
+ code=self._escape(m.group('code'))
+ )
placeholder = self.md.htmlStash.store(code)
text = '{}\n{}\n{}'.format(text[:m.start()],
@@ -96,6 +148,24 @@ class FencedBlockPreprocessor(Preprocessor):
break
return text.split("\n")
+ def handle_attrs(self, attrs):
+ """ Return tuple: (id, [list, of, classes], {configs}) """
+ id = ''
+ classes = []
+ configs = {}
+ for k, v in attrs:
+ if k == 'id':
+ id = v
+ elif k == '.':
+ classes.append(v)
+ elif k == 'hl_lines':
+ configs[k] = parse_hl_lines(v)
+ elif k in self.bool_options:
+ configs[k] = parseBoolValue(v, fail_on_errors=False, preserve_none=True)
+ else:
+ configs[k] = v
+ return id, classes, configs
+
def _escape(self, txt):
""" basic html escaping """
txt = txt.replace('&', '&')
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/footnotes.py b/venv/lib/python3.8/site-packages/markdown/extensions/footnotes.py
index 7d7ad3f..f6f4c85 100644
--- a/venv/lib/python3.8/site-packages/markdown/extensions/footnotes.py
+++ b/venv/lib/python3.8/site-packages/markdown/extensions/footnotes.py
@@ -14,7 +14,7 @@ License: [BSD](https://opensource.org/licenses/bsd-license.php)
"""
from . import Extension
-from ..preprocessors import Preprocessor
+from ..blockprocessors import BlockProcessor
from ..inlinepatterns import InlineProcessor
from ..treeprocessors import Treeprocessor
from ..postprocessors import Postprocessor
@@ -26,8 +26,6 @@ import xml.etree.ElementTree as etree
FN_BACKLINK_TEXT = util.STX + "zz1337820767766393qq" + util.ETX
NBSP_PLACEHOLDER = util.STX + "qq3936677670287331zz" + util.ETX
-DEF_RE = re.compile(r'[ ]{0,3}\[\^([^\]]*)\]:\s*(.*)')
-TABBED_RE = re.compile(r'((\t)|( ))(.*)')
RE_REF_ID = re.compile(r'(fnref)(\d+)')
@@ -72,8 +70,8 @@ class FootnoteExtension(Extension):
md.registerExtension(self)
self.parser = md.parser
self.md = md
- # Insert a preprocessor before ReferencePreprocessor
- md.preprocessors.register(FootnotePreprocessor(self), 'footnote', 15)
+ # Insert a blockprocessor before ReferencePreprocessor
+ md.parser.blockprocessors.register(FootnoteBlockProcessor(self), 'footnote', 17)
# Insert an inline pattern before ImageReferencePattern
FOOTNOTE_RE = r'\[\^([^\]]*)\]' # blah blah [^1] blah
@@ -202,106 +200,92 @@ class FootnoteExtension(Extension):
return div
-class FootnotePreprocessor(Preprocessor):
+class FootnoteBlockProcessor(BlockProcessor):
""" Find all footnote references and store for later use. """
+ RE = re.compile(r'^[ ]{0,3}\[\^([^\]]*)\]:[ ]*(.*)$', re.MULTILINE)
+
def __init__(self, footnotes):
+ super().__init__(footnotes.parser)
self.footnotes = footnotes
- def run(self, lines):
- """
- Loop through lines and find, set, and remove footnote definitions.
+ def test(self, parent, block):
+ return True
- Keywords:
+ def run(self, parent, blocks):
+ """ Find, set, and remove footnote definitions. """
+ block = blocks.pop(0)
+ m = self.RE.search(block)
+ if m:
+ id = m.group(1)
+ fn_blocks = [m.group(2)]
- * lines: A list of lines of text
-
- Return: A list of lines of text with footnote definitions removed.
-
- """
- newlines = []
- i = 0
- while True:
- m = DEF_RE.match(lines[i])
- if m:
- fn, _i = self.detectTabbed(lines[i+1:])
- fn.insert(0, m.group(2))
- i += _i-1 # skip past footnote
- footnote = "\n".join(fn)
- self.footnotes.setFootnote(m.group(1), footnote.rstrip())
- # Preserve a line for each block to prevent raw HTML indexing issue.
- # https://github.com/Python-Markdown/markdown/issues/584
- num_blocks = (len(footnote.split('\n\n')) * 2)
- newlines.extend([''] * (num_blocks))
+ # Handle rest of block
+ therest = block[m.end():].lstrip('\n')
+ m2 = self.RE.search(therest)
+ if m2:
+ # Another footnote exists in the rest of this block.
+ # Any content before match is continuation of this footnote, which may be lazily indented.
+ before = therest[:m2.start()].rstrip('\n')
+ fn_blocks[0] = '\n'.join([fn_blocks[0], self.detab(before)]).lstrip('\n')
+ # Add back to blocks everything from begining of match forward for next iteration.
+ blocks.insert(0, therest[m2.start():])
else:
- newlines.append(lines[i])
- if len(lines) > i+1:
- i += 1
- else:
- break
- return newlines
+ # All remaining lines of block are continuation of this footnote, which may be lazily indented.
+ fn_blocks[0] = '\n'.join([fn_blocks[0], self.detab(therest)]).strip('\n')
- def detectTabbed(self, lines):
+ # Check for child elements in remaining blocks.
+ fn_blocks.extend(self.detectTabbed(blocks))
+
+ footnote = "\n\n".join(fn_blocks)
+ self.footnotes.setFootnote(id, footnote.rstrip())
+
+ if block[:m.start()].strip():
+ # Add any content before match back to blocks as separate block
+ blocks.insert(0, block[:m.start()].rstrip('\n'))
+ return True
+ # No match. Restore block.
+ blocks.insert(0, block)
+ return False
+
+ def detectTabbed(self, blocks):
""" Find indented text and remove indent before further proccesing.
- Keyword arguments:
-
- * lines: an array of strings
-
- Returns: a list of post processed items and the index of last line.
-
+ Returns: a list of blocks with indentation removed.
"""
- items = []
- blank_line = False # have we encountered a blank line yet?
- i = 0 # to keep track of where we are
-
- def detab(line):
- match = TABBED_RE.match(line)
- if match:
- return match.group(4)
-
- for line in lines:
- if line.strip(): # Non-blank line
- detabbed_line = detab(line)
- if detabbed_line:
- items.append(detabbed_line)
- i += 1
- continue
- elif not blank_line and not DEF_RE.match(line):
- # not tabbed but still part of first par.
- items.append(line)
- i += 1
- continue
+ fn_blocks = []
+ while blocks:
+ if blocks[0].startswith(' '*4):
+ block = blocks.pop(0)
+ # Check for new footnotes within this block and split at new footnote.
+ m = self.RE.search(block)
+ if m:
+ # Another footnote exists in this block.
+ # Any content before match is continuation of this footnote, which may be lazily indented.
+ before = block[:m.start()].rstrip('\n')
+ fn_blocks.append(self.detab(before))
+ # Add back to blocks everything from begining of match forward for next iteration.
+ blocks.insert(0, block[m.start():])
+ # End of this footnote.
+ break
else:
- return items, i+1
+ # Entire block is part of this footnote.
+ fn_blocks.append(self.detab(block))
+ else:
+ # End of this footnote.
+ break
+ return fn_blocks
- else: # Blank line: _maybe_ we are done.
- blank_line = True
- i += 1 # advance
+ def detab(self, block):
+ """ Remove one level of indent from a block.
- # Find the next non-blank line
- for j in range(i, len(lines)):
- if lines[j].strip():
- next_line = lines[j]
- break
- else:
- # Include extreaneous padding to prevent raw HTML
- # parsing issue: https://github.com/Python-Markdown/markdown/issues/584
- items.append("")
- i += 1
- else:
- break # There is no more text; we are done.
-
- # Check if the next non-blank line is tabbed
- if detab(next_line): # Yes, more work to do.
- items.append("")
- continue
- else:
- break # No, we are done.
- else:
- i += 1
-
- return items, i
+ Preserve lazily indented blocks by only removing indent from indented lines.
+ """
+ lines = block.split('\n')
+ for i, line in enumerate(lines):
+ if line.startswith(' '*4):
+ lines[i] = line[4:]
+ return '\n'.join(lines)
class FootnoteInlineProcessor(InlineProcessor):
@@ -347,8 +331,8 @@ class FootnotePostTreeprocessor(Treeprocessor):
self.offset += 1
# Add all the new duplicate links.
el = list(li)[-1]
- for l in links:
- el.append(l)
+ for link in links:
+ el.append(link)
break
def get_num_duplicates(self, li):
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/legacy_em.py b/venv/lib/python3.8/site-packages/markdown/extensions/legacy_em.py
index c3d7b54..7fddb77 100644
--- a/venv/lib/python3.8/site-packages/markdown/extensions/legacy_em.py
+++ b/venv/lib/python3.8/site-packages/markdown/extensions/legacy_em.py
@@ -21,7 +21,7 @@ EMPHASIS_RE = r'(_)([^_]+)\1'
STRONG_RE = r'(_{2})(.+?)\1'
# __strong_em___
-STRONG_EM_RE = r'(_)\1(?!\1)(.+?)\1(?!\1)(.+?)\1{3}'
+STRONG_EM_RE = r'(_)\1(?!\1)([^_]+?)\1(?!\1)(.+?)\1{3}'
class LegacyUnderscoreProcessor(UnderscoreProcessor):
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/md_in_html.py b/venv/lib/python3.8/site-packages/markdown/extensions/md_in_html.py
index 500c166..eb8902e 100644
--- a/venv/lib/python3.8/site-packages/markdown/extensions/md_in_html.py
+++ b/venv/lib/python3.8/site-packages/markdown/extensions/md_in_html.py
@@ -16,68 +16,313 @@ License: [BSD](https://opensource.org/licenses/bsd-license.php)
from . import Extension
from ..blockprocessors import BlockProcessor
+from ..preprocessors import Preprocessor
+from ..postprocessors import RawHtmlPostprocessor
from .. import util
-import re
+from ..htmlparser import HTMLExtractor
import xml.etree.ElementTree as etree
-class MarkdownInHtmlProcessor(BlockProcessor):
- """Process Markdown Inside HTML Blocks."""
- def test(self, parent, block):
- return block == util.TAG_PLACEHOLDER % \
- str(self.parser.blockprocessors.tag_counter + 1)
+class HTMLExtractorExtra(HTMLExtractor):
+ """
+ Override HTMLExtractor and create etree Elements for any elements which should have content parsed as Markdown.
+ """
- def _process_nests(self, element, block):
- """Process the element's child elements in self.run."""
- # Build list of indexes of each nest within the parent element.
- nest_index = [] # a list of tuples: (left index, right index)
- i = self.parser.blockprocessors.tag_counter + 1
- while len(self._tag_data) > i and self._tag_data[i]['left_index']:
- left_child_index = self._tag_data[i]['left_index']
- right_child_index = self._tag_data[i]['right_index']
- nest_index.append((left_child_index - 1, right_child_index))
- i += 1
+ def __init__(self, md, *args, **kwargs):
+ # All block-level tags.
+ self.block_level_tags = set(md.block_level_elements.copy())
+ # Block-level tags in which the content only gets span level parsing
+ self.span_tags = set(
+ ['address', 'dd', 'dt', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'legend', 'li', 'p', 'td', 'th']
+ )
+ # Block-level tags which never get their content parsed.
+ self.raw_tags = set(['canvas', 'math', 'option', 'pre', 'script', 'style', 'textarea'])
+ # Block-level tags in which the content gets parsed as blocks
+ super().__init__(md, *args, **kwargs)
- # Create each nest subelement.
- for i, (left_index, right_index) in enumerate(nest_index[:-1]):
- self.run(element, block[left_index:right_index],
- block[right_index:nest_index[i + 1][0]], True)
- self.run(element, block[nest_index[-1][0]:nest_index[-1][1]], # last
- block[nest_index[-1][1]:], True) # nest
+ self.block_tags = set(self.block_level_tags) - (self.span_tags | self.raw_tags | self.empty_tags)
+ self.span_and_blocks_tags = self.block_tags | self.span_tags
- def run(self, parent, blocks, tail=None, nest=False):
- self._tag_data = self.parser.md.htmlStash.tag_data
+ def reset(self):
+ """Reset this instance. Loses all unprocessed data."""
+ self.mdstack = [] # When markdown=1, stack contains a list of tags
+ self.treebuilder = etree.TreeBuilder()
+ self.mdstate = [] # one of 'block', 'span', 'off', or None
+ super().reset()
- self.parser.blockprocessors.tag_counter += 1
- tag = self._tag_data[self.parser.blockprocessors.tag_counter]
+ def close(self):
+ """Handle any buffered data."""
+ super().close()
+ # Handle any unclosed tags.
+ if self.mdstack:
+ # Close the outermost parent. handle_endtag will close all unclosed children.
+ self.handle_endtag(self.mdstack[0])
- # Create Element
- markdown_value = tag['attrs'].pop('markdown')
- element = etree.SubElement(parent, tag['tag'], tag['attrs'])
+ def get_element(self):
+ """ Return element from treebuilder and reset treebuilder for later use. """
+ element = self.treebuilder.close()
+ self.treebuilder = etree.TreeBuilder()
+ return element
- # Slice Off Block
- if nest:
- self.parser.parseBlocks(parent, tail) # Process Tail
- block = blocks[1:]
- else: # includes nests since a third level of nesting isn't supported
- block = blocks[tag['left_index'] + 1: tag['right_index']]
- del blocks[:tag['right_index']]
+ def get_state(self, tag, attrs):
+ """ Return state from tag and `markdown` attr. One of 'block', 'span', or 'off'. """
+ md_attr = attrs.get('markdown', '0')
+ if md_attr == 'markdown':
+ # `` is the same as ``.
+ md_attr = '1'
+ parent_state = self.mdstate[-1] if self.mdstate else None
+ if parent_state == 'off' or (parent_state == 'span' and md_attr != '0'):
+ # Only use the parent state if it is more restrictive than the markdown attribute.
+ md_attr = parent_state
+ if ((md_attr == '1' and tag in self.block_tags) or
+ (md_attr == 'block' and tag in self.span_and_blocks_tags)):
+ return 'block'
+ elif ((md_attr == '1' and tag in self.span_tags) or
+ (md_attr == 'span' and tag in self.span_and_blocks_tags)):
+ return 'span'
+ elif tag in self.block_level_tags:
+ return 'off'
+ else: # pragma: no cover
+ return None
- # Process Text
- if (self.parser.blockprocessors.contain_span_tags.match( # Span Mode
- tag['tag']) and markdown_value != 'block') or \
- markdown_value == 'span':
- element.text = '\n'.join(block)
- else: # Block Mode
- i = self.parser.blockprocessors.tag_counter + 1
- if len(self._tag_data) > i and self._tag_data[i]['left_index']:
- first_subelement_index = self._tag_data[i]['left_index'] - 1
- self.parser.parseBlocks(
- element, block[:first_subelement_index])
- if not nest:
- block = self._process_nests(element, block)
+ def at_line_start(self):
+ """At line start."""
+
+ value = super().at_line_start()
+ if not value and self.cleandoc and self.cleandoc[-1].endswith('\n'):
+ value = True
+ return value
+
+ def handle_starttag(self, tag, attrs):
+ # Handle tags that should always be empty and do not specify a closing tag
+ if tag in self.empty_tags:
+ attrs = {key: value if value is not None else key for key, value in attrs}
+ if "markdown" in attrs:
+ attrs.pop('markdown')
+ element = etree.Element(tag, attrs)
+ data = etree.tostring(element, encoding='unicode', method='html')
else:
- self.parser.parseBlocks(element, block)
+ data = self.get_starttag_text()
+ self.handle_empty_tag(data, True)
+ return
+
+ if tag in self.block_level_tags:
+ # Valueless attr (ex: ``) results in `[('checked', None)]`.
+ # Convert to `{'checked': 'checked'}`.
+ attrs = {key: value if value is not None else key for key, value in attrs}
+ state = self.get_state(tag, attrs)
+
+ if self.inraw or (state in [None, 'off'] and not self.mdstack) or not self.at_line_start():
+ # fall back to default behavior
+ attrs.pop('markdown', None)
+ super().handle_starttag(tag, attrs)
+ else:
+ if 'p' in self.mdstack and tag in self.block_level_tags:
+ # Close unclosed 'p' tag
+ self.handle_endtag('p')
+ self.mdstate.append(state)
+ self.mdstack.append(tag)
+ attrs['markdown'] = state
+ self.treebuilder.start(tag, attrs)
+ else:
+ # Span level tag
+ if self.inraw:
+ super().handle_starttag(tag, attrs)
+ else:
+ text = self.get_starttag_text()
+ if self.mdstate and self.mdstate[-1] == "off":
+ self.handle_data(self.md.htmlStash.store(text))
+ else:
+ self.handle_data(text)
+
+ def handle_endtag(self, tag):
+ if tag in self.block_level_tags:
+ if self.inraw:
+ super().handle_endtag(tag)
+ elif tag in self.mdstack:
+ # Close element and any unclosed children
+ while self.mdstack:
+ item = self.mdstack.pop()
+ self.mdstate.pop()
+ self.treebuilder.end(item)
+ if item == tag:
+ break
+ if not self.mdstack:
+ # Last item in stack is closed. Stash it
+ element = self.get_element()
+ # Get last entry to see if it ends in newlines
+ # If it is an element, assume there is no newlines
+ item = self.cleandoc[-1] if self.cleandoc else ''
+ # If we only have one newline before block element, add another
+ if not item.endswith('\n\n') and item.endswith('\n'):
+ self.cleandoc.append('\n')
+ self.cleandoc.append(self.md.htmlStash.store(element))
+ self.cleandoc.append('\n\n')
+ self.state = []
+ else:
+ # Treat orphan closing tag as a span level tag.
+ text = self.get_endtag_text(tag)
+ if self.mdstate and self.mdstate[-1] == "off":
+ self.handle_data(self.md.htmlStash.store(text))
+ else:
+ self.handle_data(text)
+ else:
+ # Span level tag
+ if self.inraw:
+ super().handle_endtag(tag)
+ else:
+ text = self.get_endtag_text(tag)
+ if self.mdstate and self.mdstate[-1] == "off":
+ self.handle_data(self.md.htmlStash.store(text))
+ else:
+ self.handle_data(text)
+
+ def handle_startendtag(self, tag, attrs):
+ if tag in self.empty_tags:
+ attrs = {key: value if value is not None else key for key, value in attrs}
+ if "markdown" in attrs:
+ attrs.pop('markdown')
+ element = etree.Element(tag, attrs)
+ data = etree.tostring(element, encoding='unicode', method='html')
+ else:
+ data = self.get_starttag_text()
+ else:
+ data = self.get_starttag_text()
+ self.handle_empty_tag(data, is_block=self.md.is_block_level(tag))
+
+ def handle_data(self, data):
+ if self.inraw or not self.mdstack:
+ super().handle_data(data)
+ else:
+ self.treebuilder.data(data)
+
+ def handle_empty_tag(self, data, is_block):
+ if self.inraw or not self.mdstack:
+ super().handle_empty_tag(data, is_block)
+ else:
+ if self.at_line_start() and is_block:
+ self.handle_data('\n' + self.md.htmlStash.store(data) + '\n\n')
+ else:
+ if self.mdstate and self.mdstate[-1] == "off":
+ self.handle_data(self.md.htmlStash.store(data))
+ else:
+ self.handle_data(data)
+
+
+class HtmlBlockPreprocessor(Preprocessor):
+ """Remove html blocks from the text and store them for later retrieval."""
+
+ def run(self, lines):
+ source = '\n'.join(lines)
+ parser = HTMLExtractorExtra(self.md)
+ parser.feed(source)
+ parser.close()
+ return ''.join(parser.cleandoc).split('\n')
+
+
+class MarkdownInHtmlProcessor(BlockProcessor):
+ """Process Markdown Inside HTML Blocks which have been stored in the HtmlStash."""
+
+ def test(self, parent, block):
+ # ALways return True. `run` will return `False` it not a valid match.
+ return True
+
+ def parse_element_content(self, element):
+ """
+ Resursively parse the text content of an etree Element as Markdown.
+
+ Any block level elements generated from the Markdown will be inserted as children of the element in place
+ of the text content. All `markdown` attributes are removed. For any elements in which Markdown parsing has
+ been dissabled, the text content of it and its chidlren are wrapped in an `AtomicString`.
+ """
+
+ md_attr = element.attrib.pop('markdown', 'off')
+
+ if md_attr == 'block':
+ # Parse content as block level
+ # The order in which the different parts are parsed (text, children, tails) is important here as the
+ # order of elements needs to be preserved. We can't be inserting items at a later point in the current
+ # iteration as we don't want to do raw processing on elements created from parsing Markdown text (for
+ # example). Therefore, the order of operations is children, tails, text.
+
+ # Recursively parse existing children from raw HTML
+ for child in list(element):
+ self.parse_element_content(child)
+
+ # Parse Markdown text in tail of children. Do this seperate to avoid raw HTML parsing.
+ # Save the position of each item to be inserted later in reverse.
+ tails = []
+ for pos, child in enumerate(element):
+ if child.tail:
+ block = child.tail.rstrip('\n')
+ child.tail = ''
+ # Use a dummy placeholder element.
+ dummy = etree.Element('div')
+ self.parser.parseBlocks(dummy, block.split('\n\n'))
+ children = list(dummy)
+ children.reverse()
+ tails.append((pos + 1, children))
+
+ # Insert the elements created from the tails in reverse.
+ tails.reverse()
+ for pos, tail in tails:
+ for item in tail:
+ element.insert(pos, item)
+
+ # Parse Markdown text content. Do this last to avoid raw HTML parsing.
+ if element.text:
+ block = element.text.rstrip('\n')
+ element.text = ''
+ # Use a dummy placeholder element as the content needs to get inserted before existing children.
+ dummy = etree.Element('div')
+ self.parser.parseBlocks(dummy, block.split('\n\n'))
+ children = list(dummy)
+ children.reverse()
+ for child in children:
+ element.insert(0, child)
+
+ elif md_attr == 'span':
+ # Span level parsing will be handled by inlineprocessors.
+ # Walk children here to remove any `markdown` attributes.
+ for child in list(element):
+ self.parse_element_content(child)
+
+ else:
+ # Disable inline parsing for everything else
+ if element.text is None:
+ element.text = ''
+ element.text = util.AtomicString(element.text)
+ for child in list(element):
+ self.parse_element_content(child)
+ if child.tail:
+ child.tail = util.AtomicString(child.tail)
+
+ def run(self, parent, blocks):
+ m = util.HTML_PLACEHOLDER_RE.match(blocks[0])
+ if m:
+ index = int(m.group(1))
+ element = self.parser.md.htmlStash.rawHtmlBlocks[index]
+ if isinstance(element, etree.Element):
+ # We have a matched element. Process it.
+ blocks.pop(0)
+ self.parse_element_content(element)
+ parent.append(element)
+ # Cleanup stash. Replace element with empty string to avoid confusing postprocessor.
+ self.parser.md.htmlStash.rawHtmlBlocks.pop(index)
+ self.parser.md.htmlStash.rawHtmlBlocks.insert(index, '')
+ # Comfirm the match to the blockparser.
+ return True
+ # No match found.
+ return False
+
+
+class MarkdownInHTMLPostprocessor(RawHtmlPostprocessor):
+ def stash_to_string(self, text):
+ """ Override default to handle any etree elements still in the stash. """
+ if isinstance(text, etree.Element):
+ return self.md.serializer(text)
+ else:
+ return str(text)
class MarkdownInHtmlExtension(Extension):
@@ -86,14 +331,14 @@ class MarkdownInHtmlExtension(Extension):
def extendMarkdown(self, md):
""" Register extension instances. """
- # Turn on processing of markdown text within raw html
- md.preprocessors['html_block'].markdown_in_raw = True
+ # Replace raw HTML preprocessor
+ md.preprocessors.register(HtmlBlockPreprocessor(md), 'html_block', 20)
+ # Add blockprocessor which handles the placeholders for etree elements
md.parser.blockprocessors.register(
MarkdownInHtmlProcessor(md.parser), 'markdown_block', 105
)
- md.parser.blockprocessors.tag_counter = -1
- md.parser.blockprocessors.contain_span_tags = re.compile(
- r'^(p|h[1-6]|li|dd|dt|td|th|legend|address)$', re.IGNORECASE)
+ # Replace raw HTML postprocessor
+ md.postprocessors.register(MarkdownInHTMLPostprocessor(md), 'raw_html', 30)
def makeExtension(**kwargs): # pragma: no cover
diff --git a/venv/lib/python3.8/site-packages/markdown/extensions/toc.py b/venv/lib/python3.8/site-packages/markdown/extensions/toc.py
index 8f2b13f..b2564c9 100644
--- a/venv/lib/python3.8/site-packages/markdown/extensions/toc.py
+++ b/venv/lib/python3.8/site-packages/markdown/extensions/toc.py
@@ -15,18 +15,24 @@ License: [BSD](https://opensource.org/licenses/bsd-license.php)
from . import Extension
from ..treeprocessors import Treeprocessor
-from ..util import code_escape, parseBoolValue, AMP_SUBSTITUTE, HTML_PLACEHOLDER_RE
+from ..util import code_escape, parseBoolValue, AMP_SUBSTITUTE, HTML_PLACEHOLDER_RE, AtomicString
from ..postprocessors import UnescapePostprocessor
import re
+import html
import unicodedata
import xml.etree.ElementTree as etree
-def slugify(value, separator):
+def slugify(value, separator, encoding='ascii'):
""" Slugify a string, to make it URL friendly. """
- value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
- value = re.sub(r'[^\w\s-]', '', value.decode('ascii')).strip().lower()
- return re.sub(r'[%s\s]+' % separator, separator, value)
+ value = unicodedata.normalize('NFKD', value).encode(encoding, 'ignore')
+ value = re.sub(r'[^\w\s-]', '', value.decode(encoding)).strip().lower()
+ return re.sub(r'[{}\s]+'.format(separator), separator, value)
+
+
+def slugify_unicode(value, separator):
+ """ Slugify a string, to make it URL friendly while preserving Unicode characters. """
+ return slugify(value, separator, 'utf-8')
IDCOUNT_RE = re.compile(r'^(.*)_([0-9]+)$')
@@ -44,6 +50,18 @@ def unique(id, ids):
return id
+def get_name(el):
+ """Get title name."""
+
+ text = []
+ for c in el.itertext():
+ if isinstance(c, AtomicString):
+ text.append(html.unescape(c))
+ else:
+ text.append(c)
+ return ''.join(text).strip()
+
+
def stashedHTML2text(text, md, strip_entities=True):
""" Extract raw HTML from stash, reduce to plain text and swap with placeholder. """
def _html_sub(m):
@@ -253,7 +271,7 @@ class TocTreeprocessor(Treeprocessor):
self.set_level(el)
if int(el.tag[-1]) < self.toc_top or int(el.tag[-1]) > self.toc_bottom:
continue
- text = ''.join(el.itertext()).strip()
+ text = get_name(el)
# Do not override pre-existing ids
if "id" not in el.attrib:
diff --git a/venv/lib/python3.8/site-packages/markdown/inlinepatterns.py b/venv/lib/python3.8/site-packages/markdown/inlinepatterns.py
index ad95519..1d0a7e1 100644
--- a/venv/lib/python3.8/site-packages/markdown/inlinepatterns.py
+++ b/venv/lib/python3.8/site-packages/markdown/inlinepatterns.py
@@ -84,6 +84,9 @@ def build_inlinepatterns(md, **kwargs):
inlinePatterns.register(
ShortReferenceInlineProcessor(REFERENCE_RE, md), 'short_reference', 130
)
+ inlinePatterns.register(
+ ShortImageReferenceInlineProcessor(IMAGE_REFERENCE_RE, md), 'short_image_ref', 125
+ )
inlinePatterns.register(AutolinkInlineProcessor(AUTOLINK_RE, md), 'autolink', 120)
inlinePatterns.register(AutomailInlineProcessor(AUTOMAIL_RE, md), 'automail', 110)
inlinePatterns.register(SubstituteTagInlineProcessor(LINE_BREAK_RE, 'br'), 'linebreak', 100)
@@ -135,8 +138,8 @@ STRONG_EM_RE = r'(\*)\1{2}(.+?)\1{2}(.*?)\1'
# ___strong__em_
STRONG_EM2_RE = r'(_)\1{2}(.+?)\1{2}(.*?)\1'
-# __strong_em___
-STRONG_EM3_RE = r'(\*)\1(?!\1)(.+?)\1(?!\1)(.+?)\1{3}'
+# **strong*em***
+STRONG_EM3_RE = r'(\*)\1(?!\1)([^*]+?)\1(?!\1)(.+?)\1{3}'
# [text](url) or [text]() or [text](url "title")
LINK_RE = NOIMG + r'\['
@@ -844,6 +847,14 @@ class ImageReferenceInlineProcessor(ReferenceInlineProcessor):
return el
+class ShortImageReferenceInlineProcessor(ImageReferenceInlineProcessor):
+ """ Short form of inage reference: ![ref]. """
+ def evalId(self, data, index, text):
+ """Evaluate the id from of [ref] """
+
+ return text.lower(), index, True
+
+
class AutolinkInlineProcessor(InlineProcessor):
""" Return a link Element given an autolink (``). """
def handleMatch(self, m, data):
diff --git a/venv/lib/python3.8/site-packages/markdown/postprocessors.py b/venv/lib/python3.8/site-packages/markdown/postprocessors.py
index 95b85cd..2e68cd9 100644
--- a/venv/lib/python3.8/site-packages/markdown/postprocessors.py
+++ b/venv/lib/python3.8/site-packages/markdown/postprocessors.py
@@ -69,11 +69,10 @@ class RawHtmlPostprocessor(Postprocessor):
""" Iterate over html stash and restore html. """
replacements = OrderedDict()
for i in range(self.md.htmlStash.html_counter):
- html = self.md.htmlStash.rawHtmlBlocks[i]
+ html = self.stash_to_string(self.md.htmlStash.rawHtmlBlocks[i])
if self.isblocklevel(html):
- replacements["%s
" %
- (self.md.htmlStash.get_placeholder(i))] = \
- html + "\n"
+ replacements["{}
".format(
+ self.md.htmlStash.get_placeholder(i))] = html
replacements[self.md.htmlStash.get_placeholder(i)] = html
if replacements:
@@ -96,6 +95,10 @@ class RawHtmlPostprocessor(Postprocessor):
return self.md.is_block_level(m.group(1))
return False
+ def stash_to_string(self, text):
+ """ Convert a stashed object to a string. """
+ return str(text)
+
class AndSubstitutePostprocessor(Postprocessor):
""" Restore valid entities """
diff --git a/venv/lib/python3.8/site-packages/markdown/preprocessors.py b/venv/lib/python3.8/site-packages/markdown/preprocessors.py
index f12a02a..e1023c5 100644
--- a/venv/lib/python3.8/site-packages/markdown/preprocessors.py
+++ b/venv/lib/python3.8/site-packages/markdown/preprocessors.py
@@ -26,6 +26,7 @@ complicated.
"""
from . import util
+from .htmlparser import HTMLExtractor
import re
@@ -34,7 +35,6 @@ def build_preprocessors(md, **kwargs):
preprocessors = util.Registry()
preprocessors.register(NormalizeWhitespace(md), 'normalize_whitespace', 30)
preprocessors.register(HtmlBlockPreprocessor(md), 'html_block', 20)
- preprocessors.register(ReferencePreprocessor(md), 'reference', 10)
return preprocessors
@@ -74,297 +74,9 @@ class NormalizeWhitespace(Preprocessor):
class HtmlBlockPreprocessor(Preprocessor):
"""Remove html blocks from the text and store them for later retrieval."""
- right_tag_patterns = ["%s>", "%s>"]
- attrs_pattern = r"""
- \s+(?P[^>"'/= ]+)=(?P['"])(?P.*?)(?P=q) # attr="value"
- | # OR
- \s+(?P[^>"'/= ]+)=(?P[^> ]+) # attr=value
- | # OR
- \s+(?P[^>"'/= ]+) # attr
- """
- left_tag_pattern = r'^\<(?P[^> ]+)(?P(%s)*)\s*\/?\>?' % \
- attrs_pattern
- attrs_re = re.compile(attrs_pattern, re.VERBOSE)
- left_tag_re = re.compile(left_tag_pattern, re.VERBOSE)
- markdown_in_raw = False
-
- def _get_left_tag(self, block):
- m = self.left_tag_re.match(block)
- if m:
- tag = m.group('tag')
- raw_attrs = m.group('attrs')
- attrs = {}
- if raw_attrs:
- for ma in self.attrs_re.finditer(raw_attrs):
- if ma.group('attr'):
- if ma.group('value'):
- attrs[ma.group('attr').strip()] = ma.group('value')
- else:
- attrs[ma.group('attr').strip()] = ""
- elif ma.group('attr1'):
- if ma.group('value1'):
- attrs[ma.group('attr1').strip()] = ma.group(
- 'value1'
- )
- else:
- attrs[ma.group('attr1').strip()] = ""
- elif ma.group('attr2'):
- attrs[ma.group('attr2').strip()] = ""
- return tag, len(m.group(0)), attrs
- else:
- tag = block[1:].split(">", 1)[0].lower()
- return tag, len(tag)+2, {}
-
- def _recursive_tagfind(self, ltag, rtag, start_index, block):
- while 1:
- i = block.find(rtag, start_index)
- if i == -1:
- return -1
- j = block.find(ltag, start_index)
- # if no ltag, or rtag found before another ltag, return index
- if (j > i or j == -1):
- return i + len(rtag)
- # another ltag found before rtag, use end of ltag as starting
- # point and search again
- j = block.find('>', j)
- start_index = self._recursive_tagfind(ltag, rtag, j + 1, block)
- if start_index == -1:
- # HTML potentially malformed- ltag has no corresponding
- # rtag
- return -1
-
- def _get_right_tag(self, left_tag, left_index, block):
- for p in self.right_tag_patterns:
- tag = p % left_tag
- i = self._recursive_tagfind(
- "<%s" % left_tag, tag, left_index, block
- )
- if i > 2:
- return tag.lstrip("<").rstrip(">"), i
- return block.rstrip()[-left_index:-1].lower(), len(block)
-
- def _equal_tags(self, left_tag, right_tag):
- if left_tag[0] in ['?', '@', '%']: # handle PHP, etc.
- return True
- if ("/" + left_tag) == right_tag:
- return True
- if (right_tag == "--" and left_tag == "--"):
- return True
- elif left_tag == right_tag[1:] and right_tag[0] == "/":
- return True
- else:
- return False
-
- def _is_oneliner(self, tag):
- return (tag in ['hr', 'hr/'])
-
- def _stringindex_to_listindex(self, stringindex, items):
- """
- Same effect as concatenating the strings in items,
- finding the character to which stringindex refers in that string,
- and returning the index of the item in which that character resides.
- """
- items.append('dummy')
- i, count = 0, 0
- while count <= stringindex:
- count += len(items[i])
- i += 1
- return i - 1
-
- def _nested_markdown_in_html(self, items):
- """Find and process html child elements of the given element block."""
- for i, item in enumerate(items):
- if self.left_tag_re.match(item):
- left_tag, left_index, attrs = \
- self._get_left_tag(''.join(items[i:]))
- right_tag, data_index = self._get_right_tag(
- left_tag, left_index, ''.join(items[i:]))
- right_listindex = \
- self._stringindex_to_listindex(data_index, items[i:]) + i
- if 'markdown' in attrs.keys():
- items[i] = items[i][left_index:] # remove opening tag
- placeholder = self.md.htmlStash.store_tag(
- left_tag, attrs, i + 1, right_listindex + 1)
- items.insert(i, placeholder)
- if len(items) - right_listindex <= 1: # last nest, no tail
- right_listindex -= 1
- items[right_listindex] = items[right_listindex][
- :-len(right_tag) - 2] # remove closing tag
- else: # raw html
- if len(items) - right_listindex <= 1: # last element
- right_listindex -= 1
- if right_listindex <= i:
- right_listindex = i + 1
- placeholder = self.md.htmlStash.store('\n\n'.join(
- items[i:right_listindex]))
- del items[i:right_listindex]
- items.insert(i, placeholder)
- return items
-
def run(self, lines):
- text = "\n".join(lines)
- new_blocks = []
- text = text.rsplit("\n\n")
- items = []
- left_tag = ''
- right_tag = ''
- in_tag = False # flag
-
- while text:
- block = text[0]
- if block.startswith("\n"):
- block = block[1:]
- text = text[1:]
-
- if block.startswith("\n"):
- block = block[1:]
-
- if not in_tag:
- if block.startswith("<") and len(block.strip()) > 1:
-
- if block[1:4] == "!--":
- # is a comment block
- left_tag, left_index, attrs = "--", 2, {}
- else:
- left_tag, left_index, attrs = self._get_left_tag(block)
- right_tag, data_index = self._get_right_tag(left_tag,
- left_index,
- block)
- # keep checking conditions below and maybe just append
-
- if data_index < len(block) and (self.md.is_block_level(left_tag) or left_tag == '--'):
- text.insert(0, block[data_index:])
- block = block[:data_index]
-
- if not (self.md.is_block_level(left_tag) or block[1] in ["!", "?", "@", "%"]):
- new_blocks.append(block)
- continue
-
- if self._is_oneliner(left_tag):
- new_blocks.append(block.strip())
- continue
-
- if block.rstrip().endswith(">") \
- and self._equal_tags(left_tag, right_tag):
- if self.markdown_in_raw and 'markdown' in attrs.keys():
- block = block[left_index:-len(right_tag) - 2]
- new_blocks.append(self.md.htmlStash.
- store_tag(left_tag, attrs, 0, 2))
- new_blocks.extend([block])
- else:
- new_blocks.append(
- self.md.htmlStash.store(block.strip()))
- continue
- else:
- # if is block level tag and is not complete
- if (not self._equal_tags(left_tag, right_tag)) and \
- (self.md.is_block_level(left_tag) or left_tag == "--"):
- items.append(block.strip())
- in_tag = True
- else:
- new_blocks.append(
- self.md.htmlStash.store(block.strip())
- )
- continue
-
- else:
- new_blocks.append(block)
-
- else:
- items.append(block)
-
- # Need to evaluate all items so we can calculate relative to the left index.
- right_tag, data_index = self._get_right_tag(left_tag, left_index, ''.join(items))
- # Adjust data_index: relative to items -> relative to last block
- prev_block_length = 0
- for item in items[:-1]:
- prev_block_length += len(item)
- data_index -= prev_block_length
-
- if self._equal_tags(left_tag, right_tag):
- # if find closing tag
-
- if data_index < len(block):
- # we have more text after right_tag
- items[-1] = block[:data_index]
- text.insert(0, block[data_index:])
-
- in_tag = False
- if self.markdown_in_raw and 'markdown' in attrs.keys():
- items[0] = items[0][left_index:]
- items[-1] = items[-1][:-len(right_tag) - 2]
- if items[len(items) - 1]: # not a newline/empty string
- right_index = len(items) + 3
- else:
- right_index = len(items) + 2
- new_blocks.append(self.md.htmlStash.store_tag(
- left_tag, attrs, 0, right_index))
- placeholderslen = len(self.md.htmlStash.tag_data)
- new_blocks.extend(
- self._nested_markdown_in_html(items))
- nests = len(self.md.htmlStash.tag_data) - \
- placeholderslen
- self.md.htmlStash.tag_data[-1 - nests][
- 'right_index'] += nests - 2
- else:
- new_blocks.append(
- self.md.htmlStash.store('\n\n'.join(items)))
- items = []
-
- if items:
- if self.markdown_in_raw and 'markdown' in attrs.keys():
- items[0] = items[0][left_index:]
- items[-1] = items[-1][:-len(right_tag) - 2]
- if items[len(items) - 1]: # not a newline/empty string
- right_index = len(items) + 3
- else:
- right_index = len(items) + 2
- new_blocks.append(
- self.md.htmlStash.store_tag(
- left_tag, attrs, 0, right_index))
- placeholderslen = len(self.md.htmlStash.tag_data)
- new_blocks.extend(self._nested_markdown_in_html(items))
- nests = len(self.md.htmlStash.tag_data) - placeholderslen
- self.md.htmlStash.tag_data[-1 - nests][
- 'right_index'] += nests - 2
- else:
- new_blocks.append(
- self.md.htmlStash.store('\n\n'.join(items)))
- new_blocks.append('\n')
-
- new_text = "\n\n".join(new_blocks)
- return new_text.split("\n")
-
-
-class ReferencePreprocessor(Preprocessor):
- """ Remove reference definitions from text and store for later use. """
-
- TITLE = r'[ ]*(\"(.*)\"|\'(.*)\'|\((.*)\))[ ]*'
- RE = re.compile(
- r'^[ ]{0,3}\[([^\]]*)\]:\s*([^ ]*)[ ]*(%s)?$' % TITLE, re.DOTALL
- )
- TITLE_RE = re.compile(r'^%s$' % TITLE)
-
- def run(self, lines):
- new_text = []
- while lines:
- line = lines.pop(0)
- m = self.RE.match(line)
- if m:
- id = m.group(1).strip().lower()
- link = m.group(2).lstrip('<').rstrip('>')
- t = m.group(5) or m.group(6) or m.group(7)
- if not t:
- # Check next line for title
- tm = self.TITLE_RE.match(lines[0])
- if tm:
- lines.pop(0)
- t = tm.group(2) or tm.group(3) or tm.group(4)
- self.md.references[id] = (link, t)
- # Preserve the line to prevent raw HTML indexing issue.
- # https://github.com/Python-Markdown/markdown/issues/584
- new_text.append('')
- else:
- new_text.append(line)
-
- return new_text # + "\n"
+ source = '\n'.join(lines)
+ parser = HTMLExtractor(self.md)
+ parser.feed(source)
+ parser.close()
+ return ''.join(parser.cleandoc).split('\n')
diff --git a/venv/lib/python3.8/site-packages/markdown/test_tools.py b/venv/lib/python3.8/site-packages/markdown/test_tools.py
index a42b14b..5f33619 100644
--- a/venv/lib/python3.8/site-packages/markdown/test_tools.py
+++ b/venv/lib/python3.8/site-packages/markdown/test_tools.py
@@ -20,9 +20,10 @@ License: BSD (see LICENSE.md for details).
"""
import os
+import sys
import unittest
import textwrap
-from . import markdown
+from . import markdown, util
try:
import tidylib
@@ -73,6 +74,32 @@ class TestCase(unittest.TestCase):
return textwrap.dedent(text).strip()
+class recursionlimit:
+ """
+ A context manager which temporarily modifies the Python recursion limit.
+
+ The testing framework, coverage, etc. may add an arbitrary number of levels to the depth. To maintain consistency
+ in the tests, the current stack depth is determined when called, then added to the provided limit.
+
+ Example usage:
+
+ with recursionlimit(20):
+ # test code here
+
+ See https://stackoverflow.com/a/50120316/866026
+ """
+
+ def __init__(self, limit):
+ self.limit = util._get_stack_depth() + limit
+ self.old_limit = sys.getrecursionlimit()
+
+ def __enter__(self):
+ sys.setrecursionlimit(self.limit)
+
+ def __exit__(self, type, value, tb):
+ sys.setrecursionlimit(self.old_limit)
+
+
#########################
# Legacy Test Framework #
#########################
@@ -113,8 +140,11 @@ class LegacyTestMeta(type):
expected = f.read().replace("\r\n", "\n")
output = markdown(input, **kwargs)
if tidylib and normalize:
- expected = _normalize_whitespace(expected)
- output = _normalize_whitespace(output)
+ try:
+ expected = _normalize_whitespace(expected)
+ output = _normalize_whitespace(output)
+ except OSError:
+ self.skipTest("Tidylib's c library not available.")
elif normalize:
self.skipTest('Tidylib not available.')
self.assertMultiLineEqual(output, expected)
@@ -167,7 +197,7 @@ class LegacyTestCase(unittest.TestCase, metaclass=LegacyTestMeta):
arguments for all test files in the directory.
In addition, properties can be defined for each individual set of test files within
- the directory. The property should be given the name of the file wihtout the file
+ the directory. The property should be given the name of the file without the file
extension. Any spaces and dashes in the filename should be replaced with
underscores. The value of the property should be a `Kwargs` instance which
contains the keyword arguments that should be passed to `Markdown` for that
diff --git a/venv/lib/python3.8/site-packages/markdown/treeprocessors.py b/venv/lib/python3.8/site-packages/markdown/treeprocessors.py
index 1089010..055d8ac 100644
--- a/venv/lib/python3.8/site-packages/markdown/treeprocessors.py
+++ b/venv/lib/python3.8/site-packages/markdown/treeprocessors.py
@@ -369,8 +369,8 @@ class InlineProcessor(Treeprocessor):
lst = self.__processPlaceholders(
self.__handleInline(text), child
)
- for l in lst:
- self.parent_map[l[0]] = child
+ for item in lst:
+ self.parent_map[item[0]] = child
stack += lst
insertQueue.append((child, lst))
self.ancestors.pop()
diff --git a/venv/lib/python3.8/site-packages/markdown/util.py b/venv/lib/python3.8/site-packages/markdown/util.py
index e7bc295..2cb2317 100644
--- a/venv/lib/python3.8/site-packages/markdown/util.py
+++ b/venv/lib/python3.8/site-packages/markdown/util.py
@@ -26,7 +26,13 @@ from functools import wraps
import warnings
import xml.etree.ElementTree
from .pep562 import Pep562
+from itertools import count
+try:
+ from importlib import metadata
+except ImportError:
+ # =2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*
-
-pip - The Python Package Installer
-==================================
-
-.. image:: https://img.shields.io/pypi/v/pip.svg
- :target: https://pypi.org/project/pip/
-
-.. image:: https://readthedocs.org/projects/pip/badge/?version=latest
- :target: https://pip.pypa.io/en/latest
-
-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`_
-
-Updates are released regularly, with a new version every 3 months. More details can be found 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`_
-* `Dev documentation`_
-* `Dev mailing list`_
-* `Dev IRC`_
-
-Code of Conduct
----------------
-
-Everyone interacting in the pip project's codebases, issue trackers, chat
-rooms, and mailing lists is expected to follow the `PyPA Code of Conduct`_.
-
-.. _package installer: https://packaging.python.org/en/latest/current/
-.. _Python Package Index: https://pypi.org
-.. _Installation: https://pip.pypa.io/en/stable/installing.html
-.. _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
-.. _Dev documentation: https://pip.pypa.io/en/latest/development
-.. _Issue tracking: https://github.com/pypa/pip/issues
-.. _Discourse channel: https://discuss.python.org/c/packaging
-.. _Dev mailing list: https://groups.google.com/forum/#!forum/pypa-dev
-.. _User IRC: https://webchat.freenode.net/?channels=%23pypa
-.. _Dev IRC: https://webchat.freenode.net/?channels=%23pypa-dev
-.. _PyPA Code of Conduct: https://www.pypa.io/en/latest/code-of-conduct/
-
-
diff --git a/venv/lib/python3.8/site-packages/pip-19.2.3.dist-info/RECORD b/venv/lib/python3.8/site-packages/pip-19.2.3.dist-info/RECORD
deleted file mode 100644
index cd6ddd1..0000000
--- a/venv/lib/python3.8/site-packages/pip-19.2.3.dist-info/RECORD
+++ /dev/null
@@ -1,668 +0,0 @@
-../../../bin/pip,sha256=6vRKXo7lKmO-fViyaql2GzFsv7YOEt8B810uc9_oEXo,241
-../../../bin/pip3,sha256=6vRKXo7lKmO-fViyaql2GzFsv7YOEt8B810uc9_oEXo,241
-../../../bin/pip3.8,sha256=6vRKXo7lKmO-fViyaql2GzFsv7YOEt8B810uc9_oEXo,241
-pip-19.2.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-pip-19.2.3.dist-info/LICENSE.txt,sha256=W6Ifuwlk-TatfRU2LR7W1JMcyMj5_y1NkRkOEJvnRDE,1090
-pip-19.2.3.dist-info/METADATA,sha256=uA6603UkWcOVSlssH5-xiouxIBqVvzVkNDCHNkzsJs4,3195
-pip-19.2.3.dist-info/RECORD,,
-pip-19.2.3.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110
-pip-19.2.3.dist-info/entry_points.txt,sha256=S_zfxY25QtQDVY1BiLAmOKSkkI5llzCKPLiYOSEupsY,98
-pip-19.2.3.dist-info/top_level.txt,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-pip/__init__.py,sha256=DY1edKuavmOCGCG4RY236CTl5tiT71KY6-ewGOCDIJU,23
-pip/__main__.py,sha256=L3IHqBeasELUHvwy5CT_izVEMhM12tve289qut49DvU,623
-pip/__pycache__/__init__.cpython-38.pyc,,
-pip/__pycache__/__main__.cpython-38.pyc,,
-pip/_internal/__init__.py,sha256=uGzk4m-m6lYf1mnYIRjjsvO35Qf6iAFatbY4oa9ifOU,2797
-pip/_internal/__pycache__/__init__.cpython-38.pyc,,
-pip/_internal/__pycache__/build_env.cpython-38.pyc,,
-pip/_internal/__pycache__/cache.cpython-38.pyc,,
-pip/_internal/__pycache__/configuration.cpython-38.pyc,,
-pip/_internal/__pycache__/download.cpython-38.pyc,,
-pip/_internal/__pycache__/exceptions.cpython-38.pyc,,
-pip/_internal/__pycache__/index.cpython-38.pyc,,
-pip/_internal/__pycache__/legacy_resolve.cpython-38.pyc,,
-pip/_internal/__pycache__/locations.cpython-38.pyc,,
-pip/_internal/__pycache__/pep425tags.cpython-38.pyc,,
-pip/_internal/__pycache__/pyproject.cpython-38.pyc,,
-pip/_internal/__pycache__/wheel.cpython-38.pyc,,
-pip/_internal/build_env.py,sha256=jZHTbyb4XqoaIoPaOJP2uOp1Hnmh0HfplXBgY0TBWyM,7405
-pip/_internal/cache.py,sha256=MzHv-Z0h8_n6XfBMxIatHcoiyAmzvX1zKtDGoJBWHk0,7658
-pip/_internal/cli/__init__.py,sha256=FkHBgpxxb-_gd6r1FjnNhfMOzAUYyXoXKJ6abijfcFU,132
-pip/_internal/cli/__pycache__/__init__.cpython-38.pyc,,
-pip/_internal/cli/__pycache__/autocompletion.cpython-38.pyc,,
-pip/_internal/cli/__pycache__/base_command.cpython-38.pyc,,
-pip/_internal/cli/__pycache__/cmdoptions.cpython-38.pyc,,
-pip/_internal/cli/__pycache__/main_parser.cpython-38.pyc,,
-pip/_internal/cli/__pycache__/parser.cpython-38.pyc,,
-pip/_internal/cli/__pycache__/status_codes.cpython-38.pyc,,
-pip/_internal/cli/autocompletion.py,sha256=ptvsMdGjq42pzoY4skABVF43u2xAtLJlXAulPi-A10Y,6083
-pip/_internal/cli/base_command.py,sha256=KF1S58E8yilcKkqPyeJKU-jqQBSxBI25b_sBoq3uEAo,13029
-pip/_internal/cli/cmdoptions.py,sha256=cILKSj3jrwpQY3Xl76erVPhxnWuAIOoeJUcVjxttyaE,27543
-pip/_internal/cli/main_parser.py,sha256=J_gG7JnoAeUhSDy2PFGqMEZLNm9oNYnuZunjVz94Lyw,2817
-pip/_internal/cli/parser.py,sha256=VZKUKJPbU6I2cHPLDOikin-aCx7OvLcZ3fzYp3xytd8,9378
-pip/_internal/cli/status_codes.py,sha256=F6uDG6Gj7RNKQJUDnd87QKqI16Us-t-B0wPF_4QMpWc,156
-pip/_internal/commands/__init__.py,sha256=KF-mqzngZMtbOxkX9M6ayyGyroCNz5xdlZEc4lItUMI,2295
-pip/_internal/commands/__pycache__/__init__.cpython-38.pyc,,
-pip/_internal/commands/__pycache__/check.cpython-38.pyc,,
-pip/_internal/commands/__pycache__/completion.cpython-38.pyc,,
-pip/_internal/commands/__pycache__/configuration.cpython-38.pyc,,
-pip/_internal/commands/__pycache__/debug.cpython-38.pyc,,
-pip/_internal/commands/__pycache__/download.cpython-38.pyc,,
-pip/_internal/commands/__pycache__/freeze.cpython-38.pyc,,
-pip/_internal/commands/__pycache__/hash.cpython-38.pyc,,
-pip/_internal/commands/__pycache__/help.cpython-38.pyc,,
-pip/_internal/commands/__pycache__/install.cpython-38.pyc,,
-pip/_internal/commands/__pycache__/list.cpython-38.pyc,,
-pip/_internal/commands/__pycache__/search.cpython-38.pyc,,
-pip/_internal/commands/__pycache__/show.cpython-38.pyc,,
-pip/_internal/commands/__pycache__/uninstall.cpython-38.pyc,,
-pip/_internal/commands/__pycache__/wheel.cpython-38.pyc,,
-pip/_internal/commands/check.py,sha256=liigNVif0iz2mBfhvsajrLZT5zM5KIvgmKvhAW91EzA,1430
-pip/_internal/commands/completion.py,sha256=hqvCvoxsIHjysiD7olHKTqK2lzE1_lS6LWn69kN5qyI,2929
-pip/_internal/commands/configuration.py,sha256=c22362Rk7dAwvHFja9py4sSaV0Sryqo_PzuadI1mm0w,8156
-pip/_internal/commands/debug.py,sha256=0NJZT3Zz9vjqUqeKdPPbr_jUZubnHYp7Cmk--zlZiPs,3360
-pip/_internal/commands/download.py,sha256=zAyNBo0zwHixos6O-S6Kd9SAH1L_74filOoR83_Fa7U,6375
-pip/_internal/commands/freeze.py,sha256=lDrob-AG-qT2DyZTNWlYa9F4BqJQTy_F9h9KakBMnG0,3441
-pip/_internal/commands/hash.py,sha256=K1JycsD-rpjqrRcL_ijacY9UKmI82pQcLYq4kCM4Pv0,1681
-pip/_internal/commands/help.py,sha256=MwBhPJpW1Dt3GfJV3V8V6kgAy_pXT0jGrZJB1wCTW-E,1090
-pip/_internal/commands/install.py,sha256=cGXbByOjrJWKIv5myy7ZflX4jYMyjT6-w85tGhnI-Nw,22646
-pip/_internal/commands/list.py,sha256=MMiJnQJCfMwA1Qf0lSru7Nzm19otm49MFmbx8y01rwA,10497
-pip/_internal/commands/search.py,sha256=R2N1-r3RaxZqX5YeNL9QaYWnILsUn4MtPKZ1ji1i1sU,4972
-pip/_internal/commands/show.py,sha256=bE-ucu8fAjTTENpRRKhwD3QSWR8Rss7YgKAbMJoxock,6273
-pip/_internal/commands/uninstall.py,sha256=h0gfPF5jylDESx_IHgF6bZME7QAEOHzQHdn65GP-jrE,2963
-pip/_internal/commands/wheel.py,sha256=G2dOwQkDCH0-x6nlf9MvbMY2GUf-pqAG5epV4fjMGM0,6977
-pip/_internal/configuration.py,sha256=dKsnJZN9r4jVsl9IcoKTU0iI9s6XZQu3FzOsqTNElk0,14076
-pip/_internal/distributions/__init__.py,sha256=ydMdQRMM1DV6BdomjeP1em-YKikg90LZ9Tg5sJRhNF4,861
-pip/_internal/distributions/__pycache__/__init__.cpython-38.pyc,,
-pip/_internal/distributions/__pycache__/base.cpython-38.pyc,,
-pip/_internal/distributions/__pycache__/installed.cpython-38.pyc,,
-pip/_internal/distributions/__pycache__/source.cpython-38.pyc,,
-pip/_internal/distributions/__pycache__/wheel.cpython-38.pyc,,
-pip/_internal/distributions/base.py,sha256=Js_vmU-MKOONF_u-k5vmu3vTJnrOk3cLD_rPRB8r7-w,1000
-pip/_internal/distributions/installed.py,sha256=uwB2CPqseB8rPv0ICBCIB1LMs8yQnd8h-JZe9B9oOB0,434
-pip/_internal/distributions/source.py,sha256=L4SEZsTtqx6F3D39P7yJDgqqrnc4dGMZr3BTWgA05jg,3514
-pip/_internal/distributions/wheel.py,sha256=lWaa9l-REefNSL9E3A0zf8h2bZRLBOlTSBqHhPTYE7M,508
-pip/_internal/download.py,sha256=Zd5EtNjqJct5tOzZ5DfmiR9zaWV2UbE24omoZcNsLd4,43323
-pip/_internal/exceptions.py,sha256=_mDPdvO9EFMxUX4VEjzw3qic0PRqPH8EPOx__-MBNb4,10168
-pip/_internal/index.py,sha256=RE8HCh8MjJPgO2EhW7hww4Jr0QWFaA3GiUgxhTPs59c,56017
-pip/_internal/legacy_resolve.py,sha256=GDWmB6KtWAIcTX4gvwFrU8Xc2w4X0KBEkbW8fGU24Fk,17303
-pip/_internal/locations.py,sha256=Tv1TotkC1brrTgqG8pvLhJGvwRfiDwAlXTOdzk7hYio,5045
-pip/_internal/models/__init__.py,sha256=3DHUd_qxpPozfzouoqa9g9ts1Czr5qaHfFxbnxriepM,63
-pip/_internal/models/__pycache__/__init__.cpython-38.pyc,,
-pip/_internal/models/__pycache__/candidate.cpython-38.pyc,,
-pip/_internal/models/__pycache__/format_control.cpython-38.pyc,,
-pip/_internal/models/__pycache__/index.cpython-38.pyc,,
-pip/_internal/models/__pycache__/link.cpython-38.pyc,,
-pip/_internal/models/__pycache__/search_scope.cpython-38.pyc,,
-pip/_internal/models/__pycache__/selection_prefs.cpython-38.pyc,,
-pip/_internal/models/__pycache__/target_python.cpython-38.pyc,,
-pip/_internal/models/candidate.py,sha256=IV7B5Rj-FjQKh5Shbv8CenuNekxdpb_chrJMEID4ouU,1169
-pip/_internal/models/format_control.py,sha256=ap8Swa26ocSXBxIuCvaDBRZjxdKUFuwC-bfqXQHWtKw,2250
-pip/_internal/models/index.py,sha256=K59A8-hVhBM20Xkahr4dTwP7OjkJyEqXH11UwHFVgqM,1060
-pip/_internal/models/link.py,sha256=fj3Hg4xrPo8ucOVyJvYrq1AgJjh56D2Z8F1liDoW-TM,6553
-pip/_internal/models/search_scope.py,sha256=JxPlngW2ecVoYrF8dr2b0oYf8XrZ-yAQ1U19uEM8Lgo,3875
-pip/_internal/models/selection_prefs.py,sha256=rPeif2KKjhTPXeMoQYffjqh10oWpXhdkxRDaPT1HO8k,1908
-pip/_internal/models/target_python.py,sha256=d66ljdpZZtAAQsuOytiZ7yq6spCa8GOmz5Vf7uoVZT0,3820
-pip/_internal/operations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-pip/_internal/operations/__pycache__/__init__.cpython-38.pyc,,
-pip/_internal/operations/__pycache__/check.cpython-38.pyc,,
-pip/_internal/operations/__pycache__/freeze.cpython-38.pyc,,
-pip/_internal/operations/__pycache__/prepare.cpython-38.pyc,,
-pip/_internal/operations/check.py,sha256=EkjtpXpOCTvt_VG0gRnlSBBj5SGWsoVYzbAMpepI8JU,5224
-pip/_internal/operations/freeze.py,sha256=rKAeXdh1HbK92Z5YtmLyil8IYkcC076lahNJMyxqbVM,9680
-pip/_internal/operations/prepare.py,sha256=z27rAvMEtlpake5OI1-SIzp-EBjjwyf8PEikO0KmJ8w,11728
-pip/_internal/pep425tags.py,sha256=e3VijBWZOCLV1_iqXuCvlCswbJ16Ug4eYhR3Vz5MAmk,13220
-pip/_internal/pyproject.py,sha256=OlCw7pSqST68hUF_eV-YVaqJ4I7z_ROJwvgra-2C_5I,6464
-pip/_internal/req/__init__.py,sha256=Y2SjAuMFsSt3dkiK8kkiQAfv8sHrjl0PAT63FKFT0tM,2364
-pip/_internal/req/__pycache__/__init__.cpython-38.pyc,,
-pip/_internal/req/__pycache__/constructors.cpython-38.pyc,,
-pip/_internal/req/__pycache__/req_file.cpython-38.pyc,,
-pip/_internal/req/__pycache__/req_install.cpython-38.pyc,,
-pip/_internal/req/__pycache__/req_set.cpython-38.pyc,,
-pip/_internal/req/__pycache__/req_tracker.cpython-38.pyc,,
-pip/_internal/req/__pycache__/req_uninstall.cpython-38.pyc,,
-pip/_internal/req/constructors.py,sha256=tC7fNxKrvF3gbxI2IcA6uQiXJ5sPFQvulHPQnM5Ldgg,11858
-pip/_internal/req/req_file.py,sha256=VNC-G_JYy6JmGipezb9n5hAzZ470mvesSx3DBFtfIVM,14180
-pip/_internal/req/req_install.py,sha256=i21e6wHfTko7mQGziFoXqPbdByZ9Bnrz_bC6ZIJOwl8,40296
-pip/_internal/req/req_set.py,sha256=PaDc5EswLQhxBMFbuKbJ0frZbMNKocmA8OGqIWT-9EY,7860
-pip/_internal/req/req_tracker.py,sha256=wBpDzSDSYwpUfW4K43NrEOCCp1r6stuubfLc65Y95EM,3129
-pip/_internal/req/req_uninstall.py,sha256=rVOk8BRM_L9rsUUr9lmkV6Lm9N1Os7TEIDir6tT1Q7U,23105
-pip/_internal/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-pip/_internal/utils/__pycache__/__init__.cpython-38.pyc,,
-pip/_internal/utils/__pycache__/appdirs.cpython-38.pyc,,
-pip/_internal/utils/__pycache__/compat.cpython-38.pyc,,
-pip/_internal/utils/__pycache__/deprecation.cpython-38.pyc,,
-pip/_internal/utils/__pycache__/encoding.cpython-38.pyc,,
-pip/_internal/utils/__pycache__/filesystem.cpython-38.pyc,,
-pip/_internal/utils/__pycache__/glibc.cpython-38.pyc,,
-pip/_internal/utils/__pycache__/hashes.cpython-38.pyc,,
-pip/_internal/utils/__pycache__/logging.cpython-38.pyc,,
-pip/_internal/utils/__pycache__/marker_files.cpython-38.pyc,,
-pip/_internal/utils/__pycache__/misc.cpython-38.pyc,,
-pip/_internal/utils/__pycache__/models.cpython-38.pyc,,
-pip/_internal/utils/__pycache__/outdated.cpython-38.pyc,,
-pip/_internal/utils/__pycache__/packaging.cpython-38.pyc,,
-pip/_internal/utils/__pycache__/setuptools_build.cpython-38.pyc,,
-pip/_internal/utils/__pycache__/temp_dir.cpython-38.pyc,,
-pip/_internal/utils/__pycache__/typing.cpython-38.pyc,,
-pip/_internal/utils/__pycache__/ui.cpython-38.pyc,,
-pip/_internal/utils/__pycache__/virtualenv.cpython-38.pyc,,
-pip/_internal/utils/appdirs.py,sha256=r9i0BZLK9KcvrzI5tqlw8ehRTtSehWGERFLy7YppG3g,9398
-pip/_internal/utils/compat.py,sha256=4mi-czTysz5Ocuq-5K6BvISCii6_agyNwkBPNtKgYfM,9596
-pip/_internal/utils/deprecation.py,sha256=zcC388qvHnBLY1GalWEYnHyh3MXHQRe4-fOoyyZeQNQ,3209
-pip/_internal/utils/encoding.py,sha256=tudXCoAPe9fZvNK4cmWQs2frREZ-QuGCwF_SlTyz6cI,1218
-pip/_internal/utils/filesystem.py,sha256=ojaIDvOFOtkpKme5se6X2N8ARmQxu8cxvaaI-NFqVtk,990
-pip/_internal/utils/glibc.py,sha256=di3treHUThyeXCxqgRgp-72nTizWpC8skE7RLbewKv4,4295
-pip/_internal/utils/hashes.py,sha256=lF1VlTk2hOqnbmbiMN6GxJHTNQEDI9RzkBCUqBgSHok,3904
-pip/_internal/utils/logging.py,sha256=k-7sr-yFTLDCgcrmrErlwBp2dYMhq157vT3P-xzrB0U,12883
-pip/_internal/utils/marker_files.py,sha256=B-xFm0JZnrDStnA1jbQgKfDaMdXn53PqpZhtOJ-FWCc,595
-pip/_internal/utils/misc.py,sha256=3tmhB5Zojxswgg1zGdPgAdGvu2sYU6g0BLiAbc2vhZY,38796
-pip/_internal/utils/models.py,sha256=b7vdfIZrobxERktz8xZ7BqYnFLxoJzkWSeuq0JO9JYI,1041
-pip/_internal/utils/outdated.py,sha256=C7TK-XuCmBQ5DUpHBzq2jL-1p7DQft84foQziUyX2Ms,6292
-pip/_internal/utils/packaging.py,sha256=VtiwcAAL7LBi7tGL2je7LeW4bE11KMHGCsJ1NZY5XtM,3035
-pip/_internal/utils/setuptools_build.py,sha256=Jjf0MRzSG60UvDnWwWixg1rWM5dEuQ5sE8kb-5KwYFI,1239
-pip/_internal/utils/temp_dir.py,sha256=0Xq5ZlOd2OOeHwKM6hGy66gnMGAbyhio7DtjLHd7DFg,5339
-pip/_internal/utils/typing.py,sha256=bF73ImJzIaxLLEVwfEaSJzFGqV9LaxkQBvDULIyr1jI,1125
-pip/_internal/utils/ui.py,sha256=I2F3wRhWE9aere-cpCE0g9VPvgJRRLL8OC3FxXdj6_k,13768
-pip/_internal/utils/virtualenv.py,sha256=oSTrUMQUqmuXcDvQZGwV65w-hlvhBAqyQiWRxLf8fN0,891
-pip/_internal/vcs/__init__.py,sha256=9p9dzJZy7PR6TkHhqr-DnJTFIo6JopLgtHjHNrt85h4,597
-pip/_internal/vcs/__pycache__/__init__.cpython-38.pyc,,
-pip/_internal/vcs/__pycache__/bazaar.cpython-38.pyc,,
-pip/_internal/vcs/__pycache__/git.cpython-38.pyc,,
-pip/_internal/vcs/__pycache__/mercurial.cpython-38.pyc,,
-pip/_internal/vcs/__pycache__/subversion.cpython-38.pyc,,
-pip/_internal/vcs/__pycache__/versioncontrol.cpython-38.pyc,,
-pip/_internal/vcs/bazaar.py,sha256=wI5WdFt_Mmnqcm0c7zn5wM3R44s7s28DNx5Yg7CJlSw,3182
-pip/_internal/vcs/git.py,sha256=pgTaCyWNBBfz6d0AxVnsLhft2i4XRe_hSTI_Xs7nkZg,12814
-pip/_internal/vcs/mercurial.py,sha256=YzJx76Q4Nveqf8s80g-AocnfpKwCoVeHy77c95aTBO4,3335
-pip/_internal/vcs/subversion.py,sha256=RuQJeToLicFp2itahUftlHKjyvDFWuCWuhHfdsP9oGs,11697
-pip/_internal/vcs/versioncontrol.py,sha256=NifBlL90ovO8WNzlt4r6HGlGbPqxNI5fUMfwLC-gMkE,19010
-pip/_internal/wheel.py,sha256=H3bdufsutvlXcLV0t3prIOTvq9m_Uc0JkLDoISZelD8,42309
-pip/_vendor/__init__.py,sha256=iip2nWwH_riYqnDnM0q4BJFrWE-XWjYfxCejJKct0WM,4654
-pip/_vendor/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/__pycache__/appdirs.cpython-38.pyc,,
-pip/_vendor/__pycache__/distro.cpython-38.pyc,,
-pip/_vendor/__pycache__/ipaddress.cpython-38.pyc,,
-pip/_vendor/__pycache__/pyparsing.cpython-38.pyc,,
-pip/_vendor/__pycache__/retrying.cpython-38.pyc,,
-pip/_vendor/__pycache__/six.cpython-38.pyc,,
-pip/_vendor/appdirs.py,sha256=BENKsvcA08IpccD9345-rMrg3aXWFA1q6BFEglnHg6I,24547
-pip/_vendor/cachecontrol/__init__.py,sha256=6cRPchVqkAkeUtYTSW8qCetjSqJo-GxP-n4VMVDbvmc,302
-pip/_vendor/cachecontrol/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-38.pyc,,
-pip/_vendor/cachecontrol/__pycache__/adapter.cpython-38.pyc,,
-pip/_vendor/cachecontrol/__pycache__/cache.cpython-38.pyc,,
-pip/_vendor/cachecontrol/__pycache__/compat.cpython-38.pyc,,
-pip/_vendor/cachecontrol/__pycache__/controller.cpython-38.pyc,,
-pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-38.pyc,,
-pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-38.pyc,,
-pip/_vendor/cachecontrol/__pycache__/serialize.cpython-38.pyc,,
-pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-38.pyc,,
-pip/_vendor/cachecontrol/_cmd.py,sha256=URGE0KrA87QekCG3SGPatlSPT571dZTDjNa-ZXX3pDc,1295
-pip/_vendor/cachecontrol/adapter.py,sha256=eBGAtVNRZgtl_Kj5JV54miqL9YND-D0JZPahwY8kFtY,4863
-pip/_vendor/cachecontrol/cache.py,sha256=1fc4wJP8HYt1ycnJXeEw5pCpeBL2Cqxx6g9Fb0AYDWQ,805
-pip/_vendor/cachecontrol/caches/__init__.py,sha256=-gHNKYvaeD0kOk5M74eOrsSgIKUtC6i6GfbmugGweEo,86
-pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-38.pyc,,
-pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-38.pyc,,
-pip/_vendor/cachecontrol/caches/file_cache.py,sha256=8vrSzzGcdfEfICago1uSFbkumNJMGLbCdEkXsmUIExw,4177
-pip/_vendor/cachecontrol/caches/redis_cache.py,sha256=HxelMpNCo-dYr2fiJDwM3hhhRmxUYtB5tXm1GpAAT4Y,856
-pip/_vendor/cachecontrol/compat.py,sha256=kHNvMRdt6s_Xwqq_9qJmr9ou3wYMOMUMxPPcwNxT8Mc,695
-pip/_vendor/cachecontrol/controller.py,sha256=U7g-YwizQ2O5NRgK_MZreF1ntM4E49C3PuF3od-Vwz4,13698
-pip/_vendor/cachecontrol/filewrapper.py,sha256=vACKO8Llzu_ZWyjV1Fxn1MA4TGU60N5N3GSrAFdAY2Q,2533
-pip/_vendor/cachecontrol/heuristics.py,sha256=BFGHJ3yQcxvZizfo90LLZ04T_Z5XSCXvFotrp7Us0sc,4070
-pip/_vendor/cachecontrol/serialize.py,sha256=GebE34fgToyWwAsRPguh8hEPN6CqoG-5hRMXRsjVABQ,6954
-pip/_vendor/cachecontrol/wrapper.py,sha256=sfr9YHWx-5TwNz1H5rT6QOo8ggII6v3vbEDjQFwR6wc,671
-pip/_vendor/certifi/__init__.py,sha256=phsMyKTQP7MMe1wAHfhXPbQVxL3wXixOomxzNh5Cwa4,52
-pip/_vendor/certifi/__main__.py,sha256=NaCn6WtWME-zzVWQ2j4zFyl8cY4knDa9CwtHNIeFPhM,53
-pip/_vendor/certifi/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/certifi/__pycache__/__main__.cpython-38.pyc,,
-pip/_vendor/certifi/__pycache__/core.cpython-38.pyc,,
-pip/_vendor/certifi/cacert.pem,sha256=DddOv7pQyMB8zNNgiXSSFrPVn7EN8qbe7P6h_IYyuek,282085
-pip/_vendor/certifi/core.py,sha256=EuFc2BsToG5O1-qsx4BSjQ1r1-7WRtH87b1WflZOWhI,218
-pip/_vendor/chardet/__init__.py,sha256=YsP5wQlsHJ2auF1RZJfypiSrCA7_bQiRm3ES_NI76-Y,1559
-pip/_vendor/chardet/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/big5freq.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/big5prober.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/chardistribution.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/charsetgroupprober.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/charsetprober.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/codingstatemachine.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/compat.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/cp949prober.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/enums.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/escprober.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/escsm.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/eucjpprober.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/euckrfreq.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/euckrprober.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/euctwfreq.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/euctwprober.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/gb2312freq.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/gb2312prober.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/hebrewprober.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/jisfreq.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/jpcntx.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/langbulgarianmodel.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/langcyrillicmodel.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/langgreekmodel.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/langhebrewmodel.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/langhungarianmodel.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/langthaimodel.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/langturkishmodel.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/latin1prober.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/mbcharsetprober.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/mbcsgroupprober.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/mbcssm.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/sbcharsetprober.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/sbcsgroupprober.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/sjisprober.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/universaldetector.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/utf8prober.cpython-38.pyc,,
-pip/_vendor/chardet/__pycache__/version.cpython-38.pyc,,
-pip/_vendor/chardet/big5freq.py,sha256=D_zK5GyzoVsRes0HkLJziltFQX0bKCLOrFe9_xDvO_8,31254
-pip/_vendor/chardet/big5prober.py,sha256=kBxHbdetBpPe7xrlb-e990iot64g_eGSLd32lB7_h3M,1757
-pip/_vendor/chardet/chardistribution.py,sha256=3woWS62KrGooKyqz4zQSnjFbJpa6V7g02daAibTwcl8,9411
-pip/_vendor/chardet/charsetgroupprober.py,sha256=6bDu8YIiRuScX4ca9Igb0U69TA2PGXXDej6Cc4_9kO4,3787
-pip/_vendor/chardet/charsetprober.py,sha256=KSmwJErjypyj0bRZmC5F5eM7c8YQgLYIjZXintZNstg,5110
-pip/_vendor/chardet/cli/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
-pip/_vendor/chardet/cli/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/chardet/cli/__pycache__/chardetect.cpython-38.pyc,,
-pip/_vendor/chardet/cli/chardetect.py,sha256=DI8dlV3FBD0c0XA_y3sQ78z754DUv1J8n34RtDjOXNw,2774
-pip/_vendor/chardet/codingstatemachine.py,sha256=VYp_6cyyki5sHgXDSZnXW4q1oelHc3cu9AyQTX7uug8,3590
-pip/_vendor/chardet/compat.py,sha256=PKTzHkSbtbHDqS9PyujMbX74q1a8mMpeQTDVsQhZMRw,1134
-pip/_vendor/chardet/cp949prober.py,sha256=TZ434QX8zzBsnUvL_8wm4AQVTZ2ZkqEEQL_lNw9f9ow,1855
-pip/_vendor/chardet/enums.py,sha256=Aimwdb9as1dJKZaFNUH2OhWIVBVd6ZkJJ_WK5sNY8cU,1661
-pip/_vendor/chardet/escprober.py,sha256=kkyqVg1Yw3DIOAMJ2bdlyQgUFQhuHAW8dUGskToNWSc,3950
-pip/_vendor/chardet/escsm.py,sha256=RuXlgNvTIDarndvllNCk5WZBIpdCxQ0kcd9EAuxUh84,10510
-pip/_vendor/chardet/eucjpprober.py,sha256=iD8Jdp0ISRjgjiVN7f0e8xGeQJ5GM2oeZ1dA8nbSeUw,3749
-pip/_vendor/chardet/euckrfreq.py,sha256=-7GdmvgWez4-eO4SuXpa7tBiDi5vRXQ8WvdFAzVaSfo,13546
-pip/_vendor/chardet/euckrprober.py,sha256=MqFMTQXxW4HbzIpZ9lKDHB3GN8SP4yiHenTmf8g_PxY,1748
-pip/_vendor/chardet/euctwfreq.py,sha256=No1WyduFOgB5VITUA7PLyC5oJRNzRyMbBxaKI1l16MA,31621
-pip/_vendor/chardet/euctwprober.py,sha256=13p6EP4yRaxqnP4iHtxHOJ6R2zxHq1_m8hTRjzVZ95c,1747
-pip/_vendor/chardet/gb2312freq.py,sha256=JX8lsweKLmnCwmk8UHEQsLgkr_rP_kEbvivC4qPOrlc,20715
-pip/_vendor/chardet/gb2312prober.py,sha256=gGvIWi9WhDjE-xQXHvNIyrnLvEbMAYgyUSZ65HUfylw,1754
-pip/_vendor/chardet/hebrewprober.py,sha256=c3SZ-K7hvyzGY6JRAZxJgwJ_sUS9k0WYkvMY00YBYFo,13838
-pip/_vendor/chardet/jisfreq.py,sha256=vpmJv2Bu0J8gnMVRPHMFefTRvo_ha1mryLig8CBwgOg,25777
-pip/_vendor/chardet/jpcntx.py,sha256=PYlNqRUQT8LM3cT5FmHGP0iiscFlTWED92MALvBungo,19643
-pip/_vendor/chardet/langbulgarianmodel.py,sha256=1HqQS9Pbtnj1xQgxitJMvw8X6kKr5OockNCZWfEQrPE,12839
-pip/_vendor/chardet/langcyrillicmodel.py,sha256=LODajvsetH87yYDDQKA2CULXUH87tI223dhfjh9Zx9c,17948
-pip/_vendor/chardet/langgreekmodel.py,sha256=8YAW7bU8YwSJap0kIJSbPMw1BEqzGjWzqcqf0WgUKAA,12688
-pip/_vendor/chardet/langhebrewmodel.py,sha256=JSnqmE5E62tDLTPTvLpQsg5gOMO4PbdWRvV7Avkc0HA,11345
-pip/_vendor/chardet/langhungarianmodel.py,sha256=RhapYSG5l0ZaO-VV4Fan5sW0WRGQqhwBM61yx3yxyOA,12592
-pip/_vendor/chardet/langthaimodel.py,sha256=8l0173Gu_W6G8mxmQOTEF4ls2YdE7FxWf3QkSxEGXJQ,11290
-pip/_vendor/chardet/langturkishmodel.py,sha256=W22eRNJsqI6uWAfwXSKVWWnCerYqrI8dZQTm_M0lRFk,11102
-pip/_vendor/chardet/latin1prober.py,sha256=S2IoORhFk39FEFOlSFWtgVybRiP6h7BlLldHVclNkU8,5370
-pip/_vendor/chardet/mbcharsetprober.py,sha256=AR95eFH9vuqSfvLQZN-L5ijea25NOBCoXqw8s5O9xLQ,3413
-pip/_vendor/chardet/mbcsgroupprober.py,sha256=h6TRnnYq2OxG1WdD5JOyxcdVpn7dG0q-vB8nWr5mbh4,2012
-pip/_vendor/chardet/mbcssm.py,sha256=SY32wVIF3HzcjY3BaEspy9metbNSKxIIB0RKPn7tjpI,25481
-pip/_vendor/chardet/sbcharsetprober.py,sha256=LDSpCldDCFlYwUkGkwD2oFxLlPWIWXT09akH_2PiY74,5657
-pip/_vendor/chardet/sbcsgroupprober.py,sha256=1IprcCB_k1qfmnxGC6MBbxELlKqD3scW6S8YIwdeyXA,3546
-pip/_vendor/chardet/sjisprober.py,sha256=IIt-lZj0WJqK4rmUZzKZP4GJlE8KUEtFYVuY96ek5MQ,3774
-pip/_vendor/chardet/universaldetector.py,sha256=qL0174lSZE442eB21nnktT9_VcAye07laFWUeUrjttY,12485
-pip/_vendor/chardet/utf8prober.py,sha256=IdD8v3zWOsB8OLiyPi-y_fqwipRFxV9Nc1eKBLSuIEw,2766
-pip/_vendor/chardet/version.py,sha256=sp3B08mrDXB-pf3K9fqJ_zeDHOCLC8RrngQyDFap_7g,242
-pip/_vendor/colorama/__init__.py,sha256=lJdY6COz9uM_pXwuk9oLr0fp8H8q2RrUqN16GKabvq4,239
-pip/_vendor/colorama/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/colorama/__pycache__/ansi.cpython-38.pyc,,
-pip/_vendor/colorama/__pycache__/ansitowin32.cpython-38.pyc,,
-pip/_vendor/colorama/__pycache__/initialise.cpython-38.pyc,,
-pip/_vendor/colorama/__pycache__/win32.cpython-38.pyc,,
-pip/_vendor/colorama/__pycache__/winterm.cpython-38.pyc,,
-pip/_vendor/colorama/ansi.py,sha256=Fi0un-QLqRm-v7o_nKiOqyC8PapBJK7DLV_q9LKtTO0,2524
-pip/_vendor/colorama/ansitowin32.py,sha256=u8QaqdqS_xYSfNkPM1eRJLHz6JMWPodaJaP0mxgHCDc,10462
-pip/_vendor/colorama/initialise.py,sha256=PprovDNxMTrvoNHFcL2NZjpH2XzDc8BLxLxiErfUl4k,1915
-pip/_vendor/colorama/win32.py,sha256=bJ8Il9jwaBN5BJ8bmN6FoYZ1QYuMKv2j8fGrXh7TJjw,5404
-pip/_vendor/colorama/winterm.py,sha256=2y_2b7Zsv34feAsP67mLOVc-Bgq51mdYGo571VprlrM,6438
-pip/_vendor/distlib/__init__.py,sha256=SkHYPuEQNQF2a2Cr18rfZ-LQyDqwwizn8tJE4seXPgU,587
-pip/_vendor/distlib/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/distlib/__pycache__/compat.cpython-38.pyc,,
-pip/_vendor/distlib/__pycache__/database.cpython-38.pyc,,
-pip/_vendor/distlib/__pycache__/index.cpython-38.pyc,,
-pip/_vendor/distlib/__pycache__/locators.cpython-38.pyc,,
-pip/_vendor/distlib/__pycache__/manifest.cpython-38.pyc,,
-pip/_vendor/distlib/__pycache__/markers.cpython-38.pyc,,
-pip/_vendor/distlib/__pycache__/metadata.cpython-38.pyc,,
-pip/_vendor/distlib/__pycache__/resources.cpython-38.pyc,,
-pip/_vendor/distlib/__pycache__/scripts.cpython-38.pyc,,
-pip/_vendor/distlib/__pycache__/util.cpython-38.pyc,,
-pip/_vendor/distlib/__pycache__/version.cpython-38.pyc,,
-pip/_vendor/distlib/__pycache__/wheel.cpython-38.pyc,,
-pip/_vendor/distlib/_backport/__init__.py,sha256=bqS_dTOH6uW9iGgd0uzfpPjo6vZ4xpPZ7kyfZJ2vNaw,274
-pip/_vendor/distlib/_backport/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/distlib/_backport/__pycache__/misc.cpython-38.pyc,,
-pip/_vendor/distlib/_backport/__pycache__/shutil.cpython-38.pyc,,
-pip/_vendor/distlib/_backport/__pycache__/sysconfig.cpython-38.pyc,,
-pip/_vendor/distlib/_backport/__pycache__/tarfile.cpython-38.pyc,,
-pip/_vendor/distlib/_backport/misc.py,sha256=KWecINdbFNOxSOP1fGF680CJnaC6S4fBRgEtaYTw0ig,971
-pip/_vendor/distlib/_backport/shutil.py,sha256=VW1t3uYqUjWZH7jV-6QiimLhnldoV5uIpH4EuiT1jfw,25647
-pip/_vendor/distlib/_backport/sysconfig.cfg,sha256=swZKxq9RY5e9r3PXCrlvQPMsvOdiWZBTHLEbqS8LJLU,2617
-pip/_vendor/distlib/_backport/sysconfig.py,sha256=JdJ9ztRy4Hc-b5-VS74x3nUtdEIVr_OBvMsIb8O2sjc,26964
-pip/_vendor/distlib/_backport/tarfile.py,sha256=Ihp7rXRcjbIKw8COm9wSePV9ARGXbSF9gGXAMn2Q-KU,92628
-pip/_vendor/distlib/compat.py,sha256=xdNZmqFN5HwF30HjRn5M415pcC2kgXRBXn767xS8v-M,41404
-pip/_vendor/distlib/database.py,sha256=-KJH63AJ7hqjLtGCwOTrionhKr2Vsytdwkjyo8UdEco,51029
-pip/_vendor/distlib/index.py,sha256=SXKzpQCERctxYDMp_OLee2f0J0e19ZhGdCIoMlUfUQM,21066
-pip/_vendor/distlib/locators.py,sha256=bqzEWP3Ad8UE3D1rmzW1pgzVTKkY4rDUA_EWIVYli54,51807
-pip/_vendor/distlib/manifest.py,sha256=nQEhYmgoreaBZzyFzwYsXxJARu3fo4EkunU163U16iE,14811
-pip/_vendor/distlib/markers.py,sha256=6Ac3cCfFBERexiESWIOXmg-apIP8l2esafNSX3KMy-8,4387
-pip/_vendor/distlib/metadata.py,sha256=OhbCKmf5lswE8unWBopI1hj7tRpHp4ZbFvU4d6aAEMM,40234
-pip/_vendor/distlib/resources.py,sha256=2FGv0ZHF14KXjLIlL0R991lyQQGcewOS4mJ-5n-JVnc,10766
-pip/_vendor/distlib/scripts.py,sha256=W24OXnZUmgRX_XtDrVZdfc-Frf4X4_cybvhP87iR-QU,16290
-pip/_vendor/distlib/t32.exe,sha256=y8Yu3yao6zZrELYGIisxkhnQLOAOvpiXft8_Y9I8vyU,92672
-pip/_vendor/distlib/t64.exe,sha256=qt1MpKO2NLqU8t1lD1T0frfFm5zwHm3mz7pLvmJ2kMI,102912
-pip/_vendor/distlib/util.py,sha256=TvdqcwncBHaQbNw0jkXRvSZvt1fbdgE8HQW5wJwzvv4,59790
-pip/_vendor/distlib/version.py,sha256=_n7F6juvQGAcn769E_SHa7fOcf5ERlEVymJ_EjPRwGw,23391
-pip/_vendor/distlib/w32.exe,sha256=f98Etq_1giFgIQxrEh-sOAeO8qVtWqpDbGxdUucJ6pw,89088
-pip/_vendor/distlib/w64.exe,sha256=6Hs-Wn0vXBHA6Qd76IlalqYXqrN80DCPpdoeIQzPRms,99840
-pip/_vendor/distlib/wheel.py,sha256=2lviV6L4IvTP5DRkKE0HGpClvdoTJQHZJLfTQ6dfn2A,40437
-pip/_vendor/distro.py,sha256=X2So5kjrRKyMbQJ90Xgy93HU5eFtujCzKaYNeoy1k1c,43251
-pip/_vendor/html5lib/__init__.py,sha256=Ztrn7UvF-wIFAgRBBa0ML-Gu5AffH3BPX_INJx4SaBI,1162
-pip/_vendor/html5lib/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/html5lib/__pycache__/_ihatexml.cpython-38.pyc,,
-pip/_vendor/html5lib/__pycache__/_inputstream.cpython-38.pyc,,
-pip/_vendor/html5lib/__pycache__/_tokenizer.cpython-38.pyc,,
-pip/_vendor/html5lib/__pycache__/_utils.cpython-38.pyc,,
-pip/_vendor/html5lib/__pycache__/constants.cpython-38.pyc,,
-pip/_vendor/html5lib/__pycache__/html5parser.cpython-38.pyc,,
-pip/_vendor/html5lib/__pycache__/serializer.cpython-38.pyc,,
-pip/_vendor/html5lib/_ihatexml.py,sha256=3LBtJMlzgwM8vpQiU1TvGmEEmNH72sV0yD8yS53y07A,16705
-pip/_vendor/html5lib/_inputstream.py,sha256=bPUWcAfJScK4xkjQQaG_HsI2BvEVbFvI0AsodDYPQj0,32552
-pip/_vendor/html5lib/_tokenizer.py,sha256=YAaOEBD6qc5ISq9Xt9Nif1OFgcybTTfMdwqBkZhpAq4,76580
-pip/_vendor/html5lib/_trie/__init__.py,sha256=8VR1bcgD2OpeS2XExpu5yBhP_Q1K-lwKbBKICBPf1kU,289
-pip/_vendor/html5lib/_trie/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/html5lib/_trie/__pycache__/_base.cpython-38.pyc,,
-pip/_vendor/html5lib/_trie/__pycache__/datrie.cpython-38.pyc,,
-pip/_vendor/html5lib/_trie/__pycache__/py.cpython-38.pyc,,
-pip/_vendor/html5lib/_trie/_base.py,sha256=CaybYyMro8uERQYjby2tTeSUatnWDfWroUN9N7ety5w,1013
-pip/_vendor/html5lib/_trie/datrie.py,sha256=EQpqSfkZRuTbE-DuhW7xMdVDxdZNZ0CfmnYfHA_3zxM,1178
-pip/_vendor/html5lib/_trie/py.py,sha256=wXmQLrZRf4MyWNyg0m3h81m9InhLR7GJ002mIIZh-8o,1775
-pip/_vendor/html5lib/_utils.py,sha256=ismpASeqa2jqEPQjHUj8vReAf7yIoKnvLN5fuOw6nv0,4015
-pip/_vendor/html5lib/constants.py,sha256=4lmZWLtEPRLnl8NzftOoYTJdo6jpeMtP6dqQC0g_bWQ,83518
-pip/_vendor/html5lib/filters/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-pip/_vendor/html5lib/filters/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/html5lib/filters/__pycache__/alphabeticalattributes.cpython-38.pyc,,
-pip/_vendor/html5lib/filters/__pycache__/base.cpython-38.pyc,,
-pip/_vendor/html5lib/filters/__pycache__/inject_meta_charset.cpython-38.pyc,,
-pip/_vendor/html5lib/filters/__pycache__/lint.cpython-38.pyc,,
-pip/_vendor/html5lib/filters/__pycache__/optionaltags.cpython-38.pyc,,
-pip/_vendor/html5lib/filters/__pycache__/sanitizer.cpython-38.pyc,,
-pip/_vendor/html5lib/filters/__pycache__/whitespace.cpython-38.pyc,,
-pip/_vendor/html5lib/filters/alphabeticalattributes.py,sha256=lViZc2JMCclXi_5gduvmdzrRxtO5Xo9ONnbHBVCsykU,919
-pip/_vendor/html5lib/filters/base.py,sha256=z-IU9ZAYjpsVsqmVt7kuWC63jR11hDMr6CVrvuao8W0,286
-pip/_vendor/html5lib/filters/inject_meta_charset.py,sha256=egDXUEHXmAG9504xz0K6ALDgYkvUrC2q15YUVeNlVQg,2945
-pip/_vendor/html5lib/filters/lint.py,sha256=jk6q56xY0ojiYfvpdP-OZSm9eTqcAdRqhCoPItemPYA,3643
-pip/_vendor/html5lib/filters/optionaltags.py,sha256=8lWT75J0aBOHmPgfmqTHSfPpPMp01T84NKu0CRedxcE,10588
-pip/_vendor/html5lib/filters/sanitizer.py,sha256=4ON02KNjuqda1lCw5_JCUZxb0BzWR5M7ON84dtJ7dm0,26248
-pip/_vendor/html5lib/filters/whitespace.py,sha256=8eWqZxd4UC4zlFGW6iyY6f-2uuT8pOCSALc3IZt7_t4,1214
-pip/_vendor/html5lib/html5parser.py,sha256=g5g2ezkusHxhi7b23vK_-d6K6BfIJRbqIQmvQ9z4EgI,118963
-pip/_vendor/html5lib/serializer.py,sha256=yfcfBHse2wDs6ojxn-kieJjLT5s1ipilQJ0gL3-rJis,15758
-pip/_vendor/html5lib/treeadapters/__init__.py,sha256=A0rY5gXIe4bJOiSGRO_j_tFhngRBO8QZPzPtPw5dFzo,679
-pip/_vendor/html5lib/treeadapters/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/html5lib/treeadapters/__pycache__/genshi.cpython-38.pyc,,
-pip/_vendor/html5lib/treeadapters/__pycache__/sax.cpython-38.pyc,,
-pip/_vendor/html5lib/treeadapters/genshi.py,sha256=CH27pAsDKmu4ZGkAUrwty7u0KauGLCZRLPMzaO3M5vo,1715
-pip/_vendor/html5lib/treeadapters/sax.py,sha256=BKS8woQTnKiqeffHsxChUqL4q2ZR_wb5fc9MJ3zQC8s,1776
-pip/_vendor/html5lib/treebuilders/__init__.py,sha256=AysSJyvPfikCMMsTVvaxwkgDieELD5dfR8FJIAuq7hY,3592
-pip/_vendor/html5lib/treebuilders/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/html5lib/treebuilders/__pycache__/base.cpython-38.pyc,,
-pip/_vendor/html5lib/treebuilders/__pycache__/dom.cpython-38.pyc,,
-pip/_vendor/html5lib/treebuilders/__pycache__/etree.cpython-38.pyc,,
-pip/_vendor/html5lib/treebuilders/__pycache__/etree_lxml.cpython-38.pyc,,
-pip/_vendor/html5lib/treebuilders/base.py,sha256=wQGp5yy22TNG8tJ6aREe4UUeTR7A99dEz0BXVaedWb4,14579
-pip/_vendor/html5lib/treebuilders/dom.py,sha256=22whb0C71zXIsai5mamg6qzBEiigcBIvaDy4Asw3at0,8925
-pip/_vendor/html5lib/treebuilders/etree.py,sha256=aqIBOGj_dFYqBURIcTegGNBhAIJOw5iFDHb4jrkYH-8,12764
-pip/_vendor/html5lib/treebuilders/etree_lxml.py,sha256=9V0dXxbJYYq-Skgb5-_OL2NkVYpjioEb4CHajo0e9yI,14122
-pip/_vendor/html5lib/treewalkers/__init__.py,sha256=yhXxHpjlSqfQyUag3v8-vWjMPriFBU8YRAPNpDgBTn8,5714
-pip/_vendor/html5lib/treewalkers/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/html5lib/treewalkers/__pycache__/base.cpython-38.pyc,,
-pip/_vendor/html5lib/treewalkers/__pycache__/dom.cpython-38.pyc,,
-pip/_vendor/html5lib/treewalkers/__pycache__/etree.cpython-38.pyc,,
-pip/_vendor/html5lib/treewalkers/__pycache__/etree_lxml.cpython-38.pyc,,
-pip/_vendor/html5lib/treewalkers/__pycache__/genshi.cpython-38.pyc,,
-pip/_vendor/html5lib/treewalkers/base.py,sha256=ouiOsuSzvI0KgzdWP8PlxIaSNs9falhbiinAEc_UIJY,7476
-pip/_vendor/html5lib/treewalkers/dom.py,sha256=EHyFR8D8lYNnyDU9lx_IKigVJRyecUGua0mOi7HBukc,1413
-pip/_vendor/html5lib/treewalkers/etree.py,sha256=sz1o6mmE93NQ53qJFDO7HKyDtuwgK-Ay3qSFZPC6u00,4550
-pip/_vendor/html5lib/treewalkers/etree_lxml.py,sha256=sY6wfRshWTllu6n48TPWpKsQRPp-0CQrT0hj_AdzHSU,6309
-pip/_vendor/html5lib/treewalkers/genshi.py,sha256=4D2PECZ5n3ZN3qu3jMl9yY7B81jnQApBQSVlfaIuYbA,2309
-pip/_vendor/idna/__init__.py,sha256=9Nt7xpyet3DmOrPUGooDdAwmHZZu1qUAy2EaJ93kGiQ,58
-pip/_vendor/idna/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/idna/__pycache__/codec.cpython-38.pyc,,
-pip/_vendor/idna/__pycache__/compat.cpython-38.pyc,,
-pip/_vendor/idna/__pycache__/core.cpython-38.pyc,,
-pip/_vendor/idna/__pycache__/idnadata.cpython-38.pyc,,
-pip/_vendor/idna/__pycache__/intranges.cpython-38.pyc,,
-pip/_vendor/idna/__pycache__/package_data.cpython-38.pyc,,
-pip/_vendor/idna/__pycache__/uts46data.cpython-38.pyc,,
-pip/_vendor/idna/codec.py,sha256=lvYb7yu7PhAqFaAIAdWcwgaWI2UmgseUua-1c0AsG0A,3299
-pip/_vendor/idna/compat.py,sha256=R-h29D-6mrnJzbXxymrWUW7iZUvy-26TQwZ0ij57i4U,232
-pip/_vendor/idna/core.py,sha256=JDCZZ_PLESqIgEbU8mPyoEufWwoOiIqygA17-QZIe3s,11733
-pip/_vendor/idna/idnadata.py,sha256=HXaPFw6_YAJ0qppACPu0YLAULtRs3QovRM_CCZHGdY0,40899
-pip/_vendor/idna/intranges.py,sha256=TY1lpxZIQWEP6tNqjZkFA5hgoMWOj1OBmnUG8ihT87E,1749
-pip/_vendor/idna/package_data.py,sha256=kIzeKKXEouXLR4srqwf9Q3zv-NffKSOz5aSDOJARPB0,21
-pip/_vendor/idna/uts46data.py,sha256=oLyNZ1pBaiBlj9zFzLFRd_P7J8MkRcgDisjExZR_4MY,198292
-pip/_vendor/ipaddress.py,sha256=2OgbkeAD2rLkcXqbcvof3J5R7lRwjNLoBySyTkBtKnc,79852
-pip/_vendor/lockfile/__init__.py,sha256=Tqpz90DwKYfhPsfzVOJl84TL87pdFE5ePNHdXAxs4Tk,9371
-pip/_vendor/lockfile/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/lockfile/__pycache__/linklockfile.cpython-38.pyc,,
-pip/_vendor/lockfile/__pycache__/mkdirlockfile.cpython-38.pyc,,
-pip/_vendor/lockfile/__pycache__/pidlockfile.cpython-38.pyc,,
-pip/_vendor/lockfile/__pycache__/sqlitelockfile.cpython-38.pyc,,
-pip/_vendor/lockfile/__pycache__/symlinklockfile.cpython-38.pyc,,
-pip/_vendor/lockfile/linklockfile.py,sha256=C7OH3H4GdK68u4FQgp8fkP2kO4fyUTSyj3X6blgfobc,2652
-pip/_vendor/lockfile/mkdirlockfile.py,sha256=e3qgIL-etZMLsS-3ft19iW_8IQ360HNkGOqE3yBKsUw,3096
-pip/_vendor/lockfile/pidlockfile.py,sha256=ukH9uk6NFuxyVmG5QiWw4iKq3fT7MjqUguX95avYPIY,6090
-pip/_vendor/lockfile/sqlitelockfile.py,sha256=o2TMkMRY0iwn-iL1XMRRIFStMUkS4i3ajceeYNntKFg,5506
-pip/_vendor/lockfile/symlinklockfile.py,sha256=ABwXXmvTHvCl5viPblShL3PG-gGsLiT1roAMfDRwhi8,2616
-pip/_vendor/msgpack/__init__.py,sha256=TF3o2_Ao3xbsvpOlmVZdthtsb7TkMW9seSJkXlW0dHE,1630
-pip/_vendor/msgpack/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/msgpack/__pycache__/_version.cpython-38.pyc,,
-pip/_vendor/msgpack/__pycache__/exceptions.cpython-38.pyc,,
-pip/_vendor/msgpack/__pycache__/fallback.cpython-38.pyc,,
-pip/_vendor/msgpack/_version.py,sha256=ldul7tIj_IHxvYxbEiEX1QhElrhQsA2ikYSM987iw1U,20
-pip/_vendor/msgpack/exceptions.py,sha256=dCTWei8dpkrMsQDcjQk74ATl9HsIBH0ybt8zOPNqMYc,1081
-pip/_vendor/msgpack/fallback.py,sha256=-FKXOBCF4CUs9QEOqAlssI-IZA0jBRa27VieFCngMC4,37491
-pip/_vendor/packaging/__about__.py,sha256=Wg0-hNgTU2_lBZcGBh5pm1R9yroQ3rv-X0rig8KjA6o,744
-pip/_vendor/packaging/__init__.py,sha256=6enbp5XgRfjBjsI9-bn00HjHf5TH21PDMOKkJW8xw-w,562
-pip/_vendor/packaging/__pycache__/__about__.cpython-38.pyc,,
-pip/_vendor/packaging/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/packaging/__pycache__/_compat.cpython-38.pyc,,
-pip/_vendor/packaging/__pycache__/_structures.cpython-38.pyc,,
-pip/_vendor/packaging/__pycache__/markers.cpython-38.pyc,,
-pip/_vendor/packaging/__pycache__/requirements.cpython-38.pyc,,
-pip/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc,,
-pip/_vendor/packaging/__pycache__/utils.cpython-38.pyc,,
-pip/_vendor/packaging/__pycache__/version.cpython-38.pyc,,
-pip/_vendor/packaging/_compat.py,sha256=Ugdm-qcneSchW25JrtMIKgUxfEEBcCAz6WrEeXeqz9o,865
-pip/_vendor/packaging/_structures.py,sha256=pVd90XcXRGwpZRB_qdFuVEibhCHpX_bL5zYr9-N0mc8,1416
-pip/_vendor/packaging/markers.py,sha256=-QjvJkhSJBxBogO9J_EpPQudHaaLV3rgVYsBDqn-ZLc,8234
-pip/_vendor/packaging/requirements.py,sha256=grcnFU8x7KD230JaFLXtWl3VClLuOmsOy4c-m55tOWs,4700
-pip/_vendor/packaging/specifiers.py,sha256=0ZzQpcUnvrQ6LjR-mQRLzMr8G6hdRv-mY0VSf_amFtI,27778
-pip/_vendor/packaging/utils.py,sha256=VaTC0Ei7zO2xl9ARiWmz2YFLFt89PuuhLbAlXMyAGms,1520
-pip/_vendor/packaging/version.py,sha256=Npdwnb8OHedj_2L86yiUqscujb7w_i5gmSK1PhOAFzg,11978
-pip/_vendor/pep517/__init__.py,sha256=nOY747zTld3oTdEetBG6DWxEcZXTeOQk0aHvbR-sa5w,84
-pip/_vendor/pep517/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/pep517/__pycache__/_in_process.cpython-38.pyc,,
-pip/_vendor/pep517/__pycache__/build.cpython-38.pyc,,
-pip/_vendor/pep517/__pycache__/check.cpython-38.pyc,,
-pip/_vendor/pep517/__pycache__/colorlog.cpython-38.pyc,,
-pip/_vendor/pep517/__pycache__/compat.cpython-38.pyc,,
-pip/_vendor/pep517/__pycache__/envbuild.cpython-38.pyc,,
-pip/_vendor/pep517/__pycache__/wrappers.cpython-38.pyc,,
-pip/_vendor/pep517/_in_process.py,sha256=xMY2kLutkjCti5WqTmKOLRRL3o8Ds_k-fObFyuMv1tk,6061
-pip/_vendor/pep517/build.py,sha256=-n8PT-ugS1TdqoTUY1vatDQjrLtx48K_-Quu2MuQBiA,2699
-pip/_vendor/pep517/check.py,sha256=Lu7nMdYu1JVV58fE3hv-d_avTy5h0yO9LsIzAt82Clk,5885
-pip/_vendor/pep517/colorlog.py,sha256=Tk9AuYm_cLF3BKTBoSTJt9bRryn0aFojIQOwbfVUTxQ,4098
-pip/_vendor/pep517/compat.py,sha256=4SFG4QN-cNj8ebSa0wV0HUtEEQWwmbok2a0uk1gYEOM,631
-pip/_vendor/pep517/envbuild.py,sha256=9-u4KffexPMEm52rTaIjEOxsCAd2DMByxzv5H566QLw,5763
-pip/_vendor/pep517/wrappers.py,sha256=9dZn-q7F5KyQKUJMie2uKwur2FG0CLXz_kLZzkJOhZc,5912
-pip/_vendor/pkg_resources/__init__.py,sha256=ZVHzk7ZiFIIgE2RTJj8F7wwjdMGrAngMWtQo-rGNsm4,107910
-pip/_vendor/pkg_resources/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/pkg_resources/__pycache__/py31compat.cpython-38.pyc,,
-pip/_vendor/pkg_resources/py31compat.py,sha256=CRk8fkiPRDLsbi5pZcKsHI__Pbmh_94L8mr9Qy9Ab2U,562
-pip/_vendor/progress/__init__.py,sha256=fcbQQXo5np2CoQyhSH5XprkicwLZNLePR3uIahznSO0,4857
-pip/_vendor/progress/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/progress/__pycache__/bar.cpython-38.pyc,,
-pip/_vendor/progress/__pycache__/counter.cpython-38.pyc,,
-pip/_vendor/progress/__pycache__/spinner.cpython-38.pyc,,
-pip/_vendor/progress/bar.py,sha256=QuDuVNcmXgpxtNtxO0Fq72xKigxABaVmxYGBw4J3Z_E,2854
-pip/_vendor/progress/counter.py,sha256=MznyBrvPWrOlGe4MZAlGUb9q3aODe6_aNYeAE_VNoYA,1372
-pip/_vendor/progress/spinner.py,sha256=k8JbDW94T0-WXuXfxZIFhdoNPYp3jfnpXqBnfRv5fGs,1380
-pip/_vendor/pyparsing.py,sha256=sxGUe_YcWBB5ZoHec0m1iJtgcj4iKv_SGfdA_zVCYII,245385
-pip/_vendor/pytoml/__init__.py,sha256=W_SKx36Hsew-Fty36BOpreLm4uF4V_Tgkm_z9rIoOE8,127
-pip/_vendor/pytoml/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/pytoml/__pycache__/core.cpython-38.pyc,,
-pip/_vendor/pytoml/__pycache__/parser.cpython-38.pyc,,
-pip/_vendor/pytoml/__pycache__/test.cpython-38.pyc,,
-pip/_vendor/pytoml/__pycache__/utils.cpython-38.pyc,,
-pip/_vendor/pytoml/__pycache__/writer.cpython-38.pyc,,
-pip/_vendor/pytoml/core.py,sha256=9CrLLTs1PdWjEwRnYzt_i4dhHcZvGxs_GsMlYAX3iY4,509
-pip/_vendor/pytoml/parser.py,sha256=2tDXkldqPQJhyadXzL2rGhVbjUyBNeXXhaEfncHl2iQ,10326
-pip/_vendor/pytoml/test.py,sha256=2nQs4aX3XQEaaQCx6x_OJTS2Hb0_IiTZRqNOeDmLCzo,1021
-pip/_vendor/pytoml/utils.py,sha256=JCLHx77Hu1R3F-bRgiROIiKyCzLwyebnp5P35cRJxWs,1665
-pip/_vendor/pytoml/writer.py,sha256=WbNNQg3sh_V-s3kt88LkNNbxEq6pPDdhRE-daJzArcI,3198
-pip/_vendor/requests/__init__.py,sha256=ONVsH6kJuPTV9nf-XVoubWsVX3qVtjCyju42kTW6Uug,4074
-pip/_vendor/requests/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/requests/__pycache__/__version__.cpython-38.pyc,,
-pip/_vendor/requests/__pycache__/_internal_utils.cpython-38.pyc,,
-pip/_vendor/requests/__pycache__/adapters.cpython-38.pyc,,
-pip/_vendor/requests/__pycache__/api.cpython-38.pyc,,
-pip/_vendor/requests/__pycache__/auth.cpython-38.pyc,,
-pip/_vendor/requests/__pycache__/certs.cpython-38.pyc,,
-pip/_vendor/requests/__pycache__/compat.cpython-38.pyc,,
-pip/_vendor/requests/__pycache__/cookies.cpython-38.pyc,,
-pip/_vendor/requests/__pycache__/exceptions.cpython-38.pyc,,
-pip/_vendor/requests/__pycache__/help.cpython-38.pyc,,
-pip/_vendor/requests/__pycache__/hooks.cpython-38.pyc,,
-pip/_vendor/requests/__pycache__/models.cpython-38.pyc,,
-pip/_vendor/requests/__pycache__/packages.cpython-38.pyc,,
-pip/_vendor/requests/__pycache__/sessions.cpython-38.pyc,,
-pip/_vendor/requests/__pycache__/status_codes.cpython-38.pyc,,
-pip/_vendor/requests/__pycache__/structures.cpython-38.pyc,,
-pip/_vendor/requests/__pycache__/utils.cpython-38.pyc,,
-pip/_vendor/requests/__version__.py,sha256=Bm-GFstQaFezsFlnmEMrJDe8JNROz9n2XXYtODdvjjc,436
-pip/_vendor/requests/_internal_utils.py,sha256=Zx3PnEUccyfsB-ie11nZVAW8qClJy0gx1qNME7rgT18,1096
-pip/_vendor/requests/adapters.py,sha256=e-bmKEApNVqFdylxuMJJfiaHdlmS_zhWhIMEzlHvGuc,21548
-pip/_vendor/requests/api.py,sha256=fbUo11QoLOoNgWU6FfvNz8vMj9bE_cMmICXBa7TZHJs,6271
-pip/_vendor/requests/auth.py,sha256=QB2-cSUj1jrvWZfPXttsZpyAacQgtKLVk14vQW9TpSE,10206
-pip/_vendor/requests/certs.py,sha256=nXRVq9DtGmv_1AYbwjTu9UrgAcdJv05ZvkNeaoLOZxY,465
-pip/_vendor/requests/compat.py,sha256=FZX4Q_EMKiMnhZpZ3g_gOsT-j2ca9ij2gehDx1cwYeo,1941
-pip/_vendor/requests/cookies.py,sha256=Y-bKX6TvW3FnYlE6Au0SXtVVWcaNdFvuAwQxw-G0iTI,18430
-pip/_vendor/requests/exceptions.py,sha256=-mLam3TAx80V09EaH3H-ZxR61eAVuLRZ8zgBBSLjK44,3197
-pip/_vendor/requests/help.py,sha256=SJPVcoXeo7KfK4AxJN5eFVQCjr0im87tU2n7ubLsksU,3578
-pip/_vendor/requests/hooks.py,sha256=QReGyy0bRcr5rkwCuObNakbYsc7EkiKeBwG4qHekr2Q,757
-pip/_vendor/requests/models.py,sha256=6s-37iAqXVptq8z7U_LoH_pbIPrCQUm_Z8QuIGE29Q0,34275
-pip/_vendor/requests/packages.py,sha256=njJmVifY4aSctuW3PP5EFRCxjEwMRDO6J_feG2dKWsI,695
-pip/_vendor/requests/sessions.py,sha256=DjbCotDW6xSAaBsjbW-L8l4N0UcwmrxVNgSrZgIjGWM,29332
-pip/_vendor/requests/status_codes.py,sha256=XWlcpBjbCtq9sSqpH9_KKxgnLTf9Z__wCWolq21ySlg,4129
-pip/_vendor/requests/structures.py,sha256=zoP8qly2Jak5e89HwpqjN1z2diztI-_gaqts1raJJBc,2981
-pip/_vendor/requests/utils.py,sha256=LtPJ1db6mJff2TJSJWKi7rBpzjPS3mSOrjC9zRhoD3A,30049
-pip/_vendor/retrying.py,sha256=k3fflf5_Mm0XcIJYhB7Tj34bqCCPhUDkYbx1NvW2FPE,9972
-pip/_vendor/six.py,sha256=h9jch2pS86y4R36pKRS3LOYUCVFNIJMRwjZ4fJDtJ44,32452
-pip/_vendor/urllib3/__init__.py,sha256=dW1kWCz7bYGr-1q7xbDvJ_0_GwfyJtWq4VaLIzMcviA,2721
-pip/_vendor/urllib3/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/urllib3/__pycache__/_collections.cpython-38.pyc,,
-pip/_vendor/urllib3/__pycache__/connection.cpython-38.pyc,,
-pip/_vendor/urllib3/__pycache__/connectionpool.cpython-38.pyc,,
-pip/_vendor/urllib3/__pycache__/exceptions.cpython-38.pyc,,
-pip/_vendor/urllib3/__pycache__/fields.cpython-38.pyc,,
-pip/_vendor/urllib3/__pycache__/filepost.cpython-38.pyc,,
-pip/_vendor/urllib3/__pycache__/poolmanager.cpython-38.pyc,,
-pip/_vendor/urllib3/__pycache__/request.cpython-38.pyc,,
-pip/_vendor/urllib3/__pycache__/response.cpython-38.pyc,,
-pip/_vendor/urllib3/_collections.py,sha256=-CAKsDE-WdubAjlBSZLx7b0e7WKenaNGwWvGLDEF1TM,10746
-pip/_vendor/urllib3/connection.py,sha256=hdUK2hwFNWlKxpm7JbY_YxGYJWbe6s0AYUSt9wguHk0,15001
-pip/_vendor/urllib3/connectionpool.py,sha256=jkmLBXUD8wB0exYjDoEsg_cXVZUv-iDbhC3vAUUH82Q,35307
-pip/_vendor/urllib3/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-38.pyc,,
-pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-38.pyc,,
-pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-38.pyc,,
-pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-38.pyc,,
-pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-38.pyc,,
-pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-38.pyc,,
-pip/_vendor/urllib3/contrib/_appengine_environ.py,sha256=lhYXvB5_oGKSeurX7za3XhcGyERvNjXRQ3eJp2GmQ3M,717
-pip/_vendor/urllib3/contrib/_securetransport/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-38.pyc,,
-pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-38.pyc,,
-pip/_vendor/urllib3/contrib/_securetransport/bindings.py,sha256=6ZRejHBpquHtJaXPDm0cBsEwOBe2l9bTnDvVzd0HwJw,17576
-pip/_vendor/urllib3/contrib/_securetransport/low_level.py,sha256=Umy5u-3Z957GirdapnicXVOpHaM4xdOZABJuJxfaeJA,12162
-pip/_vendor/urllib3/contrib/appengine.py,sha256=VvDpkc5gf9dTXNxXmyG1mPdON_3DrYG_eW4uOqN98oQ,10938
-pip/_vendor/urllib3/contrib/ntlmpool.py,sha256=5ZpMF7N9B6NEjVU-r-xjDOV_-hkNvsDoNc84J2yqauI,4459
-pip/_vendor/urllib3/contrib/pyopenssl.py,sha256=raR9jRVPK485CjBp9emmWfoZIyMA1b3vcYJ2-CLg03A,16468
-pip/_vendor/urllib3/contrib/securetransport.py,sha256=IfPZ2wA3x3NXxHjKr--Q7Xz4A37ZSyWHn_1WvGxvTKQ,32826
-pip/_vendor/urllib3/contrib/socks.py,sha256=ZJ7lEUlErvAgQkd4xo_xvfx-acym2tDtJqyE0It4VRI,7012
-pip/_vendor/urllib3/exceptions.py,sha256=rFeIfBNKC8KJ61ux-MtJyJlEC9G9ggkmCeF751JwVR4,6604
-pip/_vendor/urllib3/fields.py,sha256=0EYvHsgnUflhb-UhMMVjAwiRp1InCe-uy1McDD6nhPU,8575
-pip/_vendor/urllib3/filepost.py,sha256=40CROlpRKVBpFUkD0R6wJf_PpvbcRQRFUu0OOQlFkKM,2436
-pip/_vendor/urllib3/packages/__init__.py,sha256=nlChrGzkjCkmhCX9HrF_qHPUgosfsPQkVIJxiiLhk9g,109
-pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/urllib3/packages/__pycache__/six.cpython-38.pyc,,
-pip/_vendor/urllib3/packages/backports/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-38.pyc,,
-pip/_vendor/urllib3/packages/backports/makefile.py,sha256=so2z9BiNM8kh38Ve5tomQP_mp2_ubEqzdlCpLZKzzCI,1456
-pip/_vendor/urllib3/packages/rfc3986/__init__.py,sha256=Y2dGb08ZJuqIrAqfmrGMpNi2zjzKVTxfeZ8iF-Db338,1562
-pip/_vendor/urllib3/packages/rfc3986/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/urllib3/packages/rfc3986/__pycache__/_mixin.cpython-38.pyc,,
-pip/_vendor/urllib3/packages/rfc3986/__pycache__/abnf_regexp.cpython-38.pyc,,
-pip/_vendor/urllib3/packages/rfc3986/__pycache__/api.cpython-38.pyc,,
-pip/_vendor/urllib3/packages/rfc3986/__pycache__/builder.cpython-38.pyc,,
-pip/_vendor/urllib3/packages/rfc3986/__pycache__/compat.cpython-38.pyc,,
-pip/_vendor/urllib3/packages/rfc3986/__pycache__/exceptions.cpython-38.pyc,,
-pip/_vendor/urllib3/packages/rfc3986/__pycache__/iri.cpython-38.pyc,,
-pip/_vendor/urllib3/packages/rfc3986/__pycache__/misc.cpython-38.pyc,,
-pip/_vendor/urllib3/packages/rfc3986/__pycache__/normalizers.cpython-38.pyc,,
-pip/_vendor/urllib3/packages/rfc3986/__pycache__/parseresult.cpython-38.pyc,,
-pip/_vendor/urllib3/packages/rfc3986/__pycache__/uri.cpython-38.pyc,,
-pip/_vendor/urllib3/packages/rfc3986/__pycache__/validators.cpython-38.pyc,,
-pip/_vendor/urllib3/packages/rfc3986/_mixin.py,sha256=fnxYtuAQwo6RlGZzsawcICxUhLqQ_Tyob_Kamy-92QU,13214
-pip/_vendor/urllib3/packages/rfc3986/abnf_regexp.py,sha256=0cPq-UrpihByHkDsZd_7p6ruqYh2MuqCqIjc67PFHCs,9081
-pip/_vendor/urllib3/packages/rfc3986/api.py,sha256=5wYJ3IvszICEY5cgeLTtLRWCyc9mJhgZ_4QZVtYoSKI,3887
-pip/_vendor/urllib3/packages/rfc3986/builder.py,sha256=BFbuFFZUcAnGJzvtQ0n7ffHqgG-CBf-Xi_6aU68n-OA,9577
-pip/_vendor/urllib3/packages/rfc3986/compat.py,sha256=jnSGxU4M13w5vuLldgKmXmpxcZBxmUwg8dBzNQEWzYc,1513
-pip/_vendor/urllib3/packages/rfc3986/exceptions.py,sha256=dadexlPfwsYbcbFdbR1lp5WyuF8PMsSmx2gA3nrger4,3775
-pip/_vendor/urllib3/packages/rfc3986/iri.py,sha256=UWHdKI_aOiK_SC3oE_nTrxsgiS8shJQRkmKn_AAxyms,5483
-pip/_vendor/urllib3/packages/rfc3986/misc.py,sha256=MbL7MgqbTef5VddkaaPKkLpe0hPRNCEx0-kKhJfRyk8,4094
-pip/_vendor/urllib3/packages/rfc3986/normalizers.py,sha256=L6DOXDi7vZ_BDoXS8IUl9CW21E-siDJluK2mmImljtY,5259
-pip/_vendor/urllib3/packages/rfc3986/parseresult.py,sha256=cdmsiBExo5o2A2jWI-TtGFeXTPenyXQbGf5Nmv7nh6M,14654
-pip/_vendor/urllib3/packages/rfc3986/uri.py,sha256=r_KhSNmvWfoBGRPBf1dnlwWnCwuM-JHFtGa-6DH_jH4,5227
-pip/_vendor/urllib3/packages/rfc3986/validators.py,sha256=jbJGdqUcoeSD2E_gmuFbrujLsVtEpjhJg7oxpiFeyY4,13854
-pip/_vendor/urllib3/packages/six.py,sha256=A6hdJZVjI3t_geebZ9BzUvwRrIXo0lfwzQlM2LcKyas,30098
-pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py,sha256=WBVbxQBojNAxfZwNavkox3BgJiMA9BJmm-_fwd0jD_o,688
-pip/_vendor/urllib3/packages/ssl_match_hostname/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/urllib3/packages/ssl_match_hostname/__pycache__/_implementation.cpython-38.pyc,,
-pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py,sha256=E-9J-kAaUn76WMZ4PpzKUxM4C3yjY7mopOpbPIy3Dso,5700
-pip/_vendor/urllib3/poolmanager.py,sha256=GrUSFRcQbhxPMRlePxOUbXvmsOgGTiNrxQpICmXd30I,17050
-pip/_vendor/urllib3/request.py,sha256=OfelFYzPnxGlU3amEz9uBLjCBOriwgJh4QC_aW9SF3U,5991
-pip/_vendor/urllib3/response.py,sha256=GxiW6sI0NZgdlDL4hzPfKDZmH7OFTiGZosaXu2DMG7k,27171
-pip/_vendor/urllib3/util/__init__.py,sha256=P-VlwgBFaga7i1BTWPNHGK4TN-SES0VoexbeIPIKs_0,1082
-pip/_vendor/urllib3/util/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/urllib3/util/__pycache__/connection.cpython-38.pyc,,
-pip/_vendor/urllib3/util/__pycache__/queue.cpython-38.pyc,,
-pip/_vendor/urllib3/util/__pycache__/request.cpython-38.pyc,,
-pip/_vendor/urllib3/util/__pycache__/response.cpython-38.pyc,,
-pip/_vendor/urllib3/util/__pycache__/retry.cpython-38.pyc,,
-pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-38.pyc,,
-pip/_vendor/urllib3/util/__pycache__/timeout.cpython-38.pyc,,
-pip/_vendor/urllib3/util/__pycache__/url.cpython-38.pyc,,
-pip/_vendor/urllib3/util/__pycache__/wait.cpython-38.pyc,,
-pip/_vendor/urllib3/util/connection.py,sha256=-AyqcRTuNUHuo5ndtsU0Og_nMyCGATC-kYqOUdBHwIQ,4639
-pip/_vendor/urllib3/util/queue.py,sha256=myTX3JDHntglKQNBf3b6dasHH-uF-W59vzGSQiFdAfI,497
-pip/_vendor/urllib3/util/request.py,sha256=_pmOHJWpOHk7w8BDz6WZkmMunNmplEPBmh2-5bl3Do4,3832
-pip/_vendor/urllib3/util/response.py,sha256=028PNXDZhwBtnm2uXvnAHi_l9_AAGrAMH2Igh2AbgWg,2586
-pip/_vendor/urllib3/util/retry.py,sha256=1m-XI9_LORj1FLbwOzgWC6pTt2deycyGl4BWRI9r4Zc,15150
-pip/_vendor/urllib3/util/ssl_.py,sha256=bYkkcBpWIbtFL3WCiX2pgTRjS2Ukdpv0oTtHHK0g8Mw,13798
-pip/_vendor/urllib3/util/timeout.py,sha256=dTF-iEp8DZiPd-8g2X7CVucDoBWJBn221T8ghg-tjkQ,9768
-pip/_vendor/urllib3/util/url.py,sha256=DyEkFjkLo4C82N1elJgpePfccgLb6IHMjBTnPgs9QmU,9827
-pip/_vendor/urllib3/util/wait.py,sha256=p4BZo_Ukp5JF0Dn6jro7cUfqIjnU6WFtuoA6poaV5Jk,5403
-pip/_vendor/webencodings/__init__.py,sha256=qOBJIuPy_4ByYH6W_bNgJF-qYQ2DoU-dKsDu5yRWCXg,10579
-pip/_vendor/webencodings/__pycache__/__init__.cpython-38.pyc,,
-pip/_vendor/webencodings/__pycache__/labels.cpython-38.pyc,,
-pip/_vendor/webencodings/__pycache__/mklabels.cpython-38.pyc,,
-pip/_vendor/webencodings/__pycache__/tests.cpython-38.pyc,,
-pip/_vendor/webencodings/__pycache__/x_user_defined.cpython-38.pyc,,
-pip/_vendor/webencodings/labels.py,sha256=4AO_KxTddqGtrL9ns7kAPjb0CcN6xsCIxbK37HY9r3E,8979
-pip/_vendor/webencodings/mklabels.py,sha256=GYIeywnpaLnP0GSic8LFWgd0UVvO_l1Nc6YoF-87R_4,1305
-pip/_vendor/webencodings/tests.py,sha256=OtGLyjhNY1fvkW1GvLJ_FV9ZoqC9Anyjr7q3kxTbzNs,6563
-pip/_vendor/webencodings/x_user_defined.py,sha256=yOqWSdmpytGfUgh_Z6JYgDNhoc-BAHyyeeT15Fr42tM,4307
diff --git a/venv/lib/python3.8/site-packages/pip-19.2.3.dist-info/WHEEL b/venv/lib/python3.8/site-packages/pip-19.2.3.dist-info/WHEEL
deleted file mode 100644
index 8b701e9..0000000
--- a/venv/lib/python3.8/site-packages/pip-19.2.3.dist-info/WHEEL
+++ /dev/null
@@ -1,6 +0,0 @@
-Wheel-Version: 1.0
-Generator: bdist_wheel (0.33.6)
-Root-Is-Purelib: true
-Tag: py2-none-any
-Tag: py3-none-any
-
diff --git a/venv/lib/python3.8/site-packages/pip-19.2.3.dist-info/entry_points.txt b/venv/lib/python3.8/site-packages/pip-19.2.3.dist-info/entry_points.txt
deleted file mode 100644
index f5809cb..0000000
--- a/venv/lib/python3.8/site-packages/pip-19.2.3.dist-info/entry_points.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-[console_scripts]
-pip = pip._internal:main
-pip3 = pip._internal:main
-pip3.7 = pip._internal:main
-
diff --git a/venv/lib/python3.8/site-packages/pip-19.2.3.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/pip-19.2.3.dist-info/top_level.txt
deleted file mode 100644
index a1b589e..0000000
--- a/venv/lib/python3.8/site-packages/pip-19.2.3.dist-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/venv/lib/python3.8/site-packages/pip/__init__.py b/venv/lib/python3.8/site-packages/pip/__init__.py
index 0803e00..b2e0514 100644
--- a/venv/lib/python3.8/site-packages/pip/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/__init__.py
@@ -1 +1,18 @@
-__version__ = "19.2.3"
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+
+if MYPY_CHECK_RUNNING:
+ from typing import List, Optional
+
+
+__version__ = "20.2.4"
+
+
+def main(args=None):
+ # type: (Optional[List[str]]) -> 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)
diff --git a/venv/lib/python3.8/site-packages/pip/__main__.py b/venv/lib/python3.8/site-packages/pip/__main__.py
index 0c223f8..7c2505f 100644
--- a/venv/lib/python3.8/site-packages/pip/__main__.py
+++ b/venv/lib/python3.8/site-packages/pip/__main__.py
@@ -3,6 +3,13 @@ from __future__ import absolute_import
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
+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__ == '':
@@ -13,7 +20,7 @@ if __package__ == '':
path = os.path.dirname(os.path.dirname(__file__))
sys.path.insert(0, path)
-from pip._internal import main as _main # isort:skip # noqa
+from pip._internal.cli.main import main as _main # isort:skip # noqa
if __name__ == '__main__':
sys.exit(_main())
diff --git a/venv/lib/python3.8/site-packages/pip/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/__pycache__/__init__.cpython-38.pyc
index 9d4b243..c55e943 100644
Binary files a/venv/lib/python3.8/site-packages/pip/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/__pycache__/__main__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/__pycache__/__main__.cpython-38.pyc
index e75d861..8f61de9 100644
Binary files a/venv/lib/python3.8/site-packages/pip/__pycache__/__main__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/__pycache__/__main__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/__init__.py
index fbadc28..264c2ca 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/__init__.py
@@ -1,77 +1,17 @@
-#!/usr/bin/env python
-from __future__ import absolute_import
+import pip._internal.utils.inject_securetransport # noqa
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
-import locale
-import logging
-import os
-import warnings
-
-import sys
-
-# 2016-06-17 barry@debian.org: urllib3 1.14 added optional support for socks,
-# but if invoked (i.e. imported), it will issue a warning to stderr if socks
-# isn't available. requests unconditionally imports urllib3's socks contrib
-# module, triggering this warning. The warning breaks DEP-8 tests (because of
-# the stderr output) and is just plain annoying in normal usage. I don't want
-# to add socks as yet another dependency for pip, nor do I want to allow-stderr
-# in the DEP-8 tests, so just suppress the warning. pdb tells me this has to
-# be done before the import of pip.vcs.
-from pip._vendor.urllib3.exceptions import DependencyWarning
-warnings.filterwarnings("ignore", category=DependencyWarning) # noqa
-
-# We want to inject the use of SecureTransport as early as possible so that any
-# references or sessions or what have you are ensured to have it, however we
-# only want to do this in the case that we're running on macOS and the linked
-# OpenSSL is too old to handle TLSv1.2
-try:
- import ssl
-except ImportError:
- pass
-else:
- # Checks for OpenSSL 1.0.1 on MacOS
- if sys.platform == "darwin" and ssl.OPENSSL_VERSION_NUMBER < 0x1000100f:
- try:
- from pip._vendor.urllib3.contrib import securetransport
- except (ImportError, OSError):
- pass
- else:
- securetransport.inject_into_urllib3()
-
-from pip._internal.cli.autocompletion import autocomplete
-from pip._internal.cli.main_parser import parse_command
-from pip._internal.commands import commands_dict
-from pip._internal.exceptions import PipError
-from pip._internal.utils import deprecation
-from pip._vendor.urllib3.exceptions import InsecureRequestWarning
-
-logger = logging.getLogger(__name__)
-
-# Hide the InsecureRequestWarning from urllib3
-warnings.filterwarnings("ignore", category=InsecureRequestWarning)
+if MYPY_CHECK_RUNNING:
+ from typing import Optional, List
def main(args=None):
- if args is None:
- args = sys.argv[1:]
+ # type: (Optional[List[str]]) -> int
+ """This is preserved for old console scripts that may still be referencing
+ it.
- # Configure our deprecation warnings to be sent through loggers
- deprecation.install_warning_logger()
+ For additional details, see https://github.com/pypa/pip/issues/7498.
+ """
+ from pip._internal.utils.entrypoints import _wrapper
- autocomplete()
-
- try:
- cmd_name, cmd_args = parse_command(args)
- except PipError as exc:
- sys.stderr.write("ERROR: %s" % 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 = commands_dict[cmd_name](isolated=("--isolated" in cmd_args))
- return command.main(cmd_args)
+ return _wrapper(args)
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/__init__.cpython-38.pyc
index ce21350..6d86fe0 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/build_env.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/build_env.cpython-38.pyc
index 51a8a40..1eaaf3d 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/build_env.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/build_env.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/cache.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/cache.cpython-38.pyc
index e5ae769..535ef4f 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/cache.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/cache.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/configuration.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/configuration.cpython-38.pyc
index 68f8062..0b1b187 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/configuration.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/configuration.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/download.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/download.cpython-38.pyc
deleted file mode 100644
index 0659707..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/download.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/exceptions.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/exceptions.cpython-38.pyc
index 6a344c8..37cf1c6 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/exceptions.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/exceptions.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/index.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/index.cpython-38.pyc
deleted file mode 100644
index 2c8ac19..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/index.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/legacy_resolve.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/legacy_resolve.cpython-38.pyc
deleted file mode 100644
index 6403e82..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/legacy_resolve.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/locations.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/locations.cpython-38.pyc
index e8d9ca7..2a46b8a 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/locations.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/locations.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/pep425tags.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/pep425tags.cpython-38.pyc
deleted file mode 100644
index d8c8745..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/pep425tags.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/pyproject.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/pyproject.cpython-38.pyc
index ad861ef..ffa82a0 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/pyproject.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/pyproject.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/wheel.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/wheel.cpython-38.pyc
deleted file mode 100644
index 63cc4e0..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/__pycache__/wheel.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/build_env.py b/venv/lib/python3.8/site-packages/pip/_internal/build_env.py
index a060cee..28d1ad6 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/build_env.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/build_env.py
@@ -12,14 +12,15 @@ from sysconfig import get_paths
from pip._vendor.pkg_resources import Requirement, VersionConflict, WorkingSet
from pip import __file__ as pip_location
-from pip._internal.utils.misc import call_subprocess
-from pip._internal.utils.temp_dir import TempDirectory
+from pip._internal.cli.spinners import open_spinner
+from pip._internal.utils.subprocess import call_subprocess
+from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
-from pip._internal.utils.ui import open_spinner
if MYPY_CHECK_RUNNING:
- from typing import Tuple, Set, Iterable, Optional, List
- from pip._internal.index import PackageFinder
+ from types import TracebackType
+ from typing import Tuple, Set, Iterable, Optional, List, Type
+ from pip._internal.index.package_finder import PackageFinder
logger = logging.getLogger(__name__)
@@ -50,11 +51,12 @@ class BuildEnvironment(object):
def __init__(self):
# type: () -> None
- self._temp_dir = TempDirectory(kind="build-env")
- self._temp_dir.create()
+ temp_dir = TempDirectory(
+ kind=tempdir_kinds.BUILD_ENV, globally_managed=True
+ )
self._prefixes = OrderedDict((
- (name, _Prefix(os.path.join(self._temp_dir.path, name)))
+ (name, _Prefix(os.path.join(temp_dir.path, name)))
for name in ('normal', 'overlay')
))
@@ -73,7 +75,7 @@ class BuildEnvironment(object):
get_python_lib(plat_specific=True),
)
}
- self._site_dir = os.path.join(self._temp_dir.path, 'site')
+ 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') as fp:
@@ -105,6 +107,7 @@ class BuildEnvironment(object):
).format(system_sites=system_sites, lib_dirs=self._lib_dirs))
def __enter__(self):
+ # type: () -> None
self._save_env = {
name: os.environ.get(name, None)
for name in ('PATH', 'PYTHONNOUSERSITE', 'PYTHONPATH')
@@ -123,17 +126,19 @@ class BuildEnvironment(object):
'PYTHONPATH': os.pathsep.join(pythonpath),
})
- def __exit__(self, exc_type, exc_val, exc_tb):
+ def __exit__(
+ self,
+ exc_type, # type: Optional[Type[BaseException]]
+ exc_val, # type: Optional[BaseException]
+ exc_tb # type: Optional[TracebackType]
+ ):
+ # type: (...) -> 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 cleanup(self):
- # type: () -> None
- self._temp_dir.cleanup()
-
def check_requirements(self, reqs):
# type: (Iterable[str]) -> Tuple[Set[Tuple[str, str]], Set[str]]
"""Return 2 sets:
@@ -158,7 +163,7 @@ class BuildEnvironment(object):
finder, # type: PackageFinder
requirements, # type: Iterable[str]
prefix_as_string, # type: str
- message # type: Optional[str]
+ message # type: str
):
# type: (...) -> None
prefix = self._prefixes[prefix_as_string]
@@ -192,6 +197,8 @@ class BuildEnvironment(object):
args.extend(['--trusted-host', host])
if finder.allow_all_prereleases:
args.append('--pre')
+ if finder.prefer_binary:
+ args.append('--prefer-binary')
args.append('--')
args.extend(requirements)
with open_spinner(message) as spinner:
@@ -203,16 +210,32 @@ class NoOpBuildEnvironment(BuildEnvironment):
"""
def __init__(self):
+ # type: () -> None
pass
def __enter__(self):
+ # type: () -> None
pass
- def __exit__(self, exc_type, exc_val, exc_tb):
+ def __exit__(
+ self,
+ exc_type, # type: Optional[Type[BaseException]]
+ exc_val, # type: Optional[BaseException]
+ exc_tb # type: Optional[TracebackType]
+ ):
+ # type: (...) -> None
pass
def cleanup(self):
+ # type: () -> None
pass
- def install_requirements(self, finder, requirements, prefix, message):
+ def install_requirements(
+ self,
+ finder, # type: PackageFinder
+ requirements, # type: Iterable[str]
+ prefix_as_string, # type: str
+ message # type: str
+ ):
+ # type: (...) -> None
raise NotImplementedError()
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cache.py b/venv/lib/python3.8/site-packages/pip/_internal/cache.py
index 894624c..07db948 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/cache.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/cache.py
@@ -1,27 +1,38 @@
"""Cache Management
"""
-import errno
import hashlib
+import json
import logging
import os
+from pip._vendor.packaging.tags import interpreter_name, interpreter_version
from pip._vendor.packaging.utils import canonicalize_name
+from pip._internal.exceptions import InvalidWheelFilename
from pip._internal.models.link import Link
-from pip._internal.utils.compat import expanduser
-from pip._internal.utils.misc import path_to_url
-from pip._internal.utils.temp_dir import TempDirectory
+from pip._internal.models.wheel import Wheel
+from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
-from pip._internal.wheel import InvalidWheelFilename, Wheel
+from pip._internal.utils.urls import path_to_url
if MYPY_CHECK_RUNNING:
- from typing import Optional, Set, List, Any
- from pip._internal.index import FormatControl
+ from typing import Optional, Set, List, Any, Dict
+
+ from pip._vendor.packaging.tags import Tag
+
+ from pip._internal.models.format_control import FormatControl
logger = logging.getLogger(__name__)
+def _hash_dict(d):
+ # type: (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(object):
"""An abstract class - provides cache directories for data from links
@@ -36,16 +47,19 @@ class Cache(object):
def __init__(self, cache_dir, format_control, allowed_formats):
# type: (str, FormatControl, Set[str]) -> None
super(Cache, self).__init__()
- self.cache_dir = expanduser(cache_dir) if cache_dir else None
+ assert not cache_dir or os.path.isabs(cache_dir)
+ self.cache_dir = cache_dir or None
self.format_control = format_control
self.allowed_formats = allowed_formats
_valid_formats = {"source", "binary"}
assert self.allowed_formats.union(_valid_formats) == _valid_formats
- def _get_cache_path_parts(self, link):
+ def _get_cache_path_parts_legacy(self, link):
# type: (Link) -> List[str]
"""Get parts of part that must be os.path.joined with cache_dir
+
+ Legacy cache key (pip < 20) for compatibility with older caches.
"""
# We want to generate an url to use as our cache key, we don't want to
@@ -69,30 +83,72 @@ class Cache(object):
return parts
- def _get_candidates(self, link, package_name):
- # type: (Link, Optional[str]) -> List[Any]
+ def _get_cache_path_parts(self, link):
+ # type: (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 re-use 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, canonical_package_name):
+ # type: (Link, str) -> List[Any]
can_not_cache = (
not self.cache_dir or
- not package_name or
+ not canonical_package_name or
not link
)
if can_not_cache:
return []
- canonical_name = canonicalize_name(package_name)
formats = self.format_control.get_allowed_formats(
- canonical_name
+ canonical_package_name
)
if not self.allowed_formats.intersection(formats):
return []
- root = self.get_path_for_link(link)
- try:
- return os.listdir(root)
- except OSError as err:
- if err.errno in {errno.ENOENT, errno.ENOTDIR}:
- return []
- raise
+ candidates = []
+ path = self.get_path_for_link(link)
+ if os.path.isdir(path):
+ for candidate in os.listdir(path):
+ candidates.append((candidate, path))
+ # TODO remove legacy path lookup in pip>=21
+ legacy_path = self.get_path_for_link_legacy(link)
+ if os.path.isdir(legacy_path):
+ for candidate in os.listdir(legacy_path):
+ candidates.append((candidate, legacy_path))
+ return candidates
+
+ def get_path_for_link_legacy(self, link):
+ # type: (Link) -> str
+ raise NotImplementedError()
def get_path_for_link(self, link):
# type: (Link) -> str
@@ -100,24 +156,18 @@ class Cache(object):
"""
raise NotImplementedError()
- def get(self, link, package_name):
- # type: (Link, Optional[str]) -> Link
+ def get(
+ self,
+ link, # type: Link
+ package_name, # type: Optional[str]
+ supported_tags, # type: List[Tag]
+ ):
+ # type: (...) -> Link
"""Returns a link to a cached item if it exists, otherwise returns the
passed link.
"""
raise NotImplementedError()
- def _link_for_candidate(self, link, candidate):
- # type: (Link, str) -> Link
- root = self.get_path_for_link(link)
- path = os.path.join(root, candidate)
-
- return Link(path_to_url(path))
-
- def cleanup(self):
- # type: () -> None
- pass
-
class SimpleWheelCache(Cache):
"""A cache of wheels for future installs.
@@ -129,6 +179,12 @@ class SimpleWheelCache(Cache):
cache_dir, format_control, {"binary"}
)
+ def get_path_for_link_legacy(self, link):
+ # type: (Link) -> str
+ parts = self._get_cache_path_parts_legacy(link)
+ assert self.cache_dir
+ return os.path.join(self.cache_dir, "wheels", *parts)
+
def get_path_for_link(self, link):
# type: (Link) -> str
"""Return a directory to store cached wheels for link
@@ -146,28 +202,53 @@ class SimpleWheelCache(Cache):
: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, package_name):
- # type: (Link, Optional[str]) -> Link
+ def get(
+ self,
+ link, # type: Link
+ package_name, # type: Optional[str]
+ supported_tags, # type: List[Tag]
+ ):
+ # type: (...) -> Link
candidates = []
- for wheel_name in self._get_candidates(link, package_name):
+ 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 not wheel.supported():
+ 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(), wheel_name))
+ candidates.append(
+ (
+ wheel.support_index_min(supported_tags),
+ wheel_name,
+ wheel_dir,
+ )
+ )
if not candidates:
return link
- return self._link_for_candidate(link, min(candidates)[1])
+ _, wheel_name, wheel_dir = min(candidates)
+ return Link(path_to_url(os.path.join(wheel_dir, wheel_name)))
class EphemWheelCache(SimpleWheelCache):
@@ -176,16 +257,24 @@ class EphemWheelCache(SimpleWheelCache):
def __init__(self, format_control):
# type: (FormatControl) -> None
- self._temp_dir = TempDirectory(kind="ephem-wheel-cache")
- self._temp_dir.create()
+ self._temp_dir = TempDirectory(
+ kind=tempdir_kinds.EPHEM_WHEEL_CACHE,
+ globally_managed=True,
+ )
super(EphemWheelCache, self).__init__(
self._temp_dir.path, format_control
)
- def cleanup(self):
- # type: () -> None
- self._temp_dir.cleanup()
+
+class CacheEntry(object):
+ def __init__(
+ self,
+ link, # type: Link
+ persistent, # type: bool
+ ):
+ self.link = link
+ self.persistent = persistent
class WheelCache(Cache):
@@ -203,6 +292,10 @@ class WheelCache(Cache):
self._wheel_cache = SimpleWheelCache(cache_dir, format_control)
self._ephem_cache = EphemWheelCache(format_control)
+ def get_path_for_link_legacy(self, link):
+ # type: (Link) -> str
+ return self._wheel_cache.get_path_for_link_legacy(link)
+
def get_path_for_link(self, link):
# type: (Link) -> str
return self._wheel_cache.get_path_for_link(link)
@@ -211,14 +304,43 @@ class WheelCache(Cache):
# type: (Link) -> str
return self._ephem_cache.get_path_for_link(link)
- def get(self, link, package_name):
- # type: (Link, Optional[str]) -> Link
- retval = self._wheel_cache.get(link, package_name)
- if retval is link:
- retval = self._ephem_cache.get(link, package_name)
- return retval
+ def get(
+ self,
+ link, # type: Link
+ package_name, # type: Optional[str]
+ supported_tags, # type: List[Tag]
+ ):
+ # type: (...) -> Link
+ cache_entry = self.get_cache_entry(link, package_name, supported_tags)
+ if cache_entry is None:
+ return link
+ return cache_entry.link
- def cleanup(self):
- # type: () -> None
- self._wheel_cache.cleanup()
- self._ephem_cache.cleanup()
+ def get_cache_entry(
+ self,
+ link, # type: Link
+ package_name, # type: Optional[str]
+ supported_tags, # type: List[Tag]
+ ):
+ # type: (...) -> 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
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-38.pyc
index 18c8076..a978686 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-38.pyc
index c6cdac8..2b18acf 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-38.pyc
index 6d6dd76..01eb324 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-38.pyc
index ef22884..2731b6e 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-38.pyc
index 45e5e38..de56f12 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/parser.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/parser.cpython-38.pyc
index 92951e1..ced6be7 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/parser.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/parser.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-38.pyc
index e2c65d4..10ec3eb 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/autocompletion.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/autocompletion.py
index 0a04199..329de60 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/cli/autocompletion.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/cli/autocompletion.py
@@ -4,13 +4,19 @@
import optparse
import os
import sys
+from itertools import chain
from pip._internal.cli.main_parser import create_main_parser
-from pip._internal.commands import commands_dict, get_summaries
+from pip._internal.commands import commands_dict, create_command
from pip._internal.utils.misc import get_installed_distributions
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+
+if MYPY_CHECK_RUNNING:
+ from typing import Any, Iterable, List, Optional
def autocomplete():
+ # type: () -> None
"""Entry Point for completion of main and subcommand options.
"""
# Don't complete if user hasn't sourced bash_completion file.
@@ -23,17 +29,18 @@ def autocomplete():
except IndexError:
current = ''
- subcommands = [cmd for cmd, summary in get_summaries()]
- options = []
- # subcommand
- try:
- subcommand_name = [w for w in cwords if w in subcommands][0]
- except IndexError:
- subcommand_name = None
-
parser = create_main_parser()
+ subcommands = list(commands_dict)
+ options = []
+
+ # subcommand
+ subcommand_name = None # type: Optional[str]
+ for word in cwords:
+ if word in subcommands:
+ subcommand_name = word
+ break
# subcommand options
- if subcommand_name:
+ if subcommand_name is not None:
# special case: 'help' subcommand has no options
if subcommand_name == 'help':
sys.exit(1)
@@ -54,7 +61,7 @@ def autocomplete():
print(dist)
sys.exit(1)
- subcommand = commands_dict[subcommand_name]()
+ subcommand = create_command(subcommand_name)
for opt in subcommand.parser.option_list_all:
if opt.help != optparse.SUPPRESS_HELP:
@@ -73,8 +80,8 @@ def autocomplete():
# get completion files and directories if ``completion_type`` is
# ````, ```` or ````
if completion_type:
- options = auto_complete_paths(current, completion_type)
- options = ((opt, 0) for opt in options)
+ 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
@@ -86,22 +93,25 @@ def autocomplete():
opts = [i.option_list for i in parser.option_groups]
opts.append(parser.option_list)
- opts = (o for it in opts for o in it)
+ flattened_opts = chain.from_iterable(opts)
if current.startswith('-'):
- for opt in opts:
+ 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, opts)
+ completion_type = get_path_completion_type(cwords, cword,
+ flattened_opts)
if completion_type:
- subcommands = auto_complete_paths(current, 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, cword, opts):
+ # type: (List[str], int, Iterable[Any]) -> Optional[str]
"""Get the type of path completion (``file``, ``dir``, ``path`` or None)
:param cwords: same as the environmental variable ``COMP_WORDS``
@@ -110,7 +120,7 @@ def get_path_completion_type(cwords, cword, opts):
:return: path completion type (``file``, ``dir``, ``path`` or None)
"""
if cword < 2 or not cwords[cword - 2].startswith('-'):
- return
+ return None
for opt in opts:
if opt.help == optparse.SUPPRESS_HELP:
continue
@@ -120,9 +130,11 @@ def get_path_completion_type(cwords, cword, opts):
x in ('path', 'file', 'dir')
for x in opt.metavar.split('/')):
return opt.metavar
+ return None
def auto_complete_paths(current, completion_type):
+ # type: (str, 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``.
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/base_command.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/base_command.py
index 90830be..197400a 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/cli/base_command.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/cli/base_command.py
@@ -1,4 +1,5 @@
"""Base Command class, and related routines"""
+
from __future__ import absolute_import, print_function
import logging
@@ -10,65 +11,75 @@ import sys
import traceback
from pip._internal.cli import cmdoptions
-from pip._internal.cli.cmdoptions import make_search_scope
+from pip._internal.cli.command_context import CommandContextMixIn
from pip._internal.cli.parser import (
- ConfigOptionParser, UpdatingDefaultsHelpFormatter,
+ ConfigOptionParser,
+ UpdatingDefaultsHelpFormatter,
)
from pip._internal.cli.status_codes import (
- ERROR, PREVIOUS_BUILD_DIR_ERROR, SUCCESS, UNKNOWN_ERROR,
+ ERROR,
+ PREVIOUS_BUILD_DIR_ERROR,
+ UNKNOWN_ERROR,
VIRTUALENV_NOT_FOUND,
)
-from pip._internal.download import PipSession
from pip._internal.exceptions import (
- BadCommand, CommandError, InstallationError, PreviousBuildDirError,
+ BadCommand,
+ CommandError,
+ InstallationError,
+ NetworkConnectionError,
+ PreviousBuildDirError,
+ SubProcessError,
UninstallationError,
)
-from pip._internal.index import PackageFinder
-from pip._internal.models.selection_prefs import SelectionPreferences
-from pip._internal.models.target_python import TargetPython
-from pip._internal.req.constructors import (
- install_req_from_editable, install_req_from_line,
-)
-from pip._internal.req.req_file import parse_requirements
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.outdated import pip_version_check
+from pip._internal.utils.temp_dir import (
+ global_tempdir_manager,
+ tempdir_registry,
+)
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
from pip._internal.utils.virtualenv import running_under_virtualenv
if MYPY_CHECK_RUNNING:
- from typing import Optional, List, Tuple, Any
+ from typing import List, Optional, Tuple, Any
from optparse import Values
- from pip._internal.cache import WheelCache
- from pip._internal.req.req_set import RequirementSet
+
+ from pip._internal.utils.temp_dir import (
+ TempDirectoryTypeRegistry as TempDirRegistry
+ )
__all__ = ['Command']
logger = logging.getLogger(__name__)
-class Command(object):
- name = None # type: Optional[str]
- usage = None # type: Optional[str]
+class Command(CommandContextMixIn):
+ usage = None # type: str
ignore_require_venv = False # type: bool
- def __init__(self, isolated=False):
- # type: (bool) -> None
+ def __init__(self, name, summary, isolated=False):
+ # type: (str, str, bool) -> None
+ super(Command, self).__init__()
parser_kw = {
'usage': self.usage,
- 'prog': '%s %s' % (get_prog(), self.name),
+ 'prog': '{} {}'.format(get_prog(), name),
'formatter': UpdatingDefaultsHelpFormatter(),
'add_help_option': False,
- 'name': self.name,
+ 'name': name,
'description': self.__doc__,
'isolated': isolated,
}
+ self.name = name
+ self.summary = summary
self.parser = ConfigOptionParser(**parser_kw)
+ self.tempdir_registry = None # type: Optional[TempDirRegistry]
+
# Commands should add options to this option group
- optgroup_name = '%s Options' % self.name.capitalize()
+ optgroup_name = '{} Options'.format(self.name.capitalize())
self.cmd_opts = optparse.OptionGroup(self.parser, optgroup_name)
# Add the general options
@@ -78,69 +89,49 @@ class Command(object):
)
self.parser.add_option_group(gen_opts)
+ self.add_options()
+
+ def add_options(self):
+ # type: () -> None
+ pass
+
+ def handle_pip_version_check(self, options):
+ # type: (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, args):
- # type: (Values, List[Any]) -> Any
+ # type: (Values, List[Any]) -> int
raise NotImplementedError
- @classmethod
- def _get_index_urls(cls, options):
- """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 _build_session(self, options, retries=None, timeout=None):
- # type: (Values, Optional[int], Optional[int]) -> PipSession
- session = PipSession(
- cache=(
- normalize_path(os.path.join(options.cache_dir, "http"))
- if options.cache_dir else None
- ),
- retries=retries if retries is not None else options.retries,
- insecure_hosts=options.trusted_hosts,
- index_urls=self._get_index_urls(options),
- )
-
- # 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,
- }
-
- # Determine if we can prompt the user for authentication or not
- session.auth.prompting = not options.no_input
-
- return session
-
def parse_args(self, args):
- # type: (List[str]) -> Tuple
+ # type: (List[str]) -> Tuple[Any, Any]
# factored out for testability
return self.parser.parse_args(args)
def main(self, args):
# type: (List[str]) -> int
+ try:
+ with self.main_context():
+ return self._main(args)
+ finally:
+ logging.shutdown()
+
+ def _main(self, args):
+ # type: (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.
@@ -152,19 +143,34 @@ class Command(object):
user_log_file=options.log,
)
- if sys.version_info[:2] == (2, 7):
+ if (
+ sys.version_info[:2] == (2, 7) and
+ not options.no_python_version_warning
+ ):
message = (
- "A future version of pip will drop support for Python 2.7. "
- "More details about Python 2 support in pip, can be found at "
+ "pip 21.0 will drop support for Python 2.7 in January 2021. "
+ "More details about Python 2 support in pip can be found at "
"https://pip.pypa.io/en/latest/development/release-process/#python-2-support" # noqa
)
if platform.python_implementation() == "CPython":
message = (
- "Python 2.7 will reach the end of its life on January "
+ "Python 2.7 reached the end of its life on January "
"1st, 2020. Please upgrade your Python as Python 2.7 "
- "won't be maintained after that date. "
+ "is no longer maintained. "
) + message
- deprecated(message, replacement=None, gone_in=None)
+ deprecated(message, replacement=None, gone_in="21.0")
+
+ if (
+ sys.version_info[:2] == (3, 5) and
+ not options.no_python_version_warning
+ ):
+ message = (
+ "Python 3.5 reached the end of its life on September "
+ "13th, 2020. Please upgrade your Python as Python 3.5 "
+ "is no longer maintained. pip 21.0 will drop support "
+ "for Python 3.5 in January 2021."
+ )
+ deprecated(message, replacement=None, gone_in="21.0")
# TODO: Try to get these passing down from the command?
# without resorting to os.environ to hold these.
@@ -184,18 +190,51 @@ class Command(object):
)
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 may want "
+ "sudo's -H flag.",
+ options.cache_dir,
+ )
+ options.cache_dir = None
+
+ if getattr(options, "build_dir", None):
+ deprecated(
+ reason=(
+ "The -b/--build/--build-dir/--build-directory "
+ "option is deprecated."
+ ),
+ replacement=(
+ "use the TMPDIR/TEMP/TMP environment variable, "
+ "possibly combined with --no-clean"
+ ),
+ gone_in="20.3",
+ issue=8333,
+ )
+
+ if 'resolver' in options.unstable_features:
+ logger.critical(
+ "--unstable-feature=resolver is no longer supported, and "
+ "has been replaced with --use-feature=2020-resolver instead."
+ )
+ sys.exit(ERROR)
+
try:
status = self.run(options, args)
- # FIXME: all commands should return an exit status
- # and when it is done, isinstance is not needed anymore
- if isinstance(status, int):
- return status
+ assert isinstance(status, int)
+ return status
except PreviousBuildDirError as exc:
logger.critical(str(exc))
logger.debug('Exception information:', exc_info=True)
return PREVIOUS_BUILD_DIR_ERROR
- except (InstallationError, UninstallationError, BadCommand) as exc:
+ except (InstallationError, UninstallationError, BadCommand,
+ SubProcessError, NetworkConnectionError) as exc:
logger.critical(str(exc))
logger.debug('Exception information:', exc_info=True)
@@ -223,124 +262,4 @@ class Command(object):
return UNKNOWN_ERROR
finally:
- allow_version_check = (
- # Does this command have the index_group options?
- hasattr(options, "no_index") and
- # Is this command allowed to perform this check?
- not (options.disable_pip_version_check or options.no_index)
- )
- # Check if we're using the latest version of pip available
- if allow_version_check:
- session = self._build_session(
- options,
- retries=0,
- timeout=min(5, options.timeout)
- )
- with session:
- pip_version_check(session, options)
-
- # Shutdown the logging module
- logging.shutdown()
-
- return SUCCESS
-
-
-class RequirementCommand(Command):
-
- @staticmethod
- def populate_requirement_set(requirement_set, # type: RequirementSet
- args, # type: List[str]
- options, # type: Values
- finder, # type: PackageFinder
- session, # type: PipSession
- name, # type: str
- wheel_cache # type: Optional[WheelCache]
- ):
- # type: (...) -> None
- """
- Marshal cmd line args into a requirement set.
- """
- # NOTE: As a side-effect, options.require_hashes and
- # requirement_set.require_hashes may be updated
-
- for filename in options.constraints:
- for req_to_add in parse_requirements(
- filename,
- constraint=True, finder=finder, options=options,
- session=session, wheel_cache=wheel_cache):
- req_to_add.is_direct = True
- requirement_set.add_requirement(req_to_add)
-
- for req in args:
- req_to_add = install_req_from_line(
- req, None, isolated=options.isolated_mode,
- use_pep517=options.use_pep517,
- wheel_cache=wheel_cache
- )
- req_to_add.is_direct = True
- requirement_set.add_requirement(req_to_add)
-
- for req in options.editables:
- req_to_add = install_req_from_editable(
- req,
- isolated=options.isolated_mode,
- use_pep517=options.use_pep517,
- wheel_cache=wheel_cache
- )
- req_to_add.is_direct = True
- requirement_set.add_requirement(req_to_add)
-
- for filename in options.requirements:
- for req_to_add in parse_requirements(
- filename,
- finder=finder, options=options, session=session,
- wheel_cache=wheel_cache,
- use_pep517=options.use_pep517):
- req_to_add.is_direct = True
- requirement_set.add_requirement(req_to_add)
- # If --require-hashes was a line in a requirements file, tell
- # RequirementSet about it:
- requirement_set.require_hashes = options.require_hashes
-
- if not (args or options.editables or options.requirements):
- opts = {'name': name}
- if options.find_links:
- raise CommandError(
- 'You must give at least one requirement to %(name)s '
- '(maybe you meant "pip %(name)s %(links)s"?)' %
- dict(opts, links=' '.join(options.find_links)))
- else:
- raise CommandError(
- 'You must give at least one requirement to %(name)s '
- '(see "pip help %(name)s")' % opts)
-
- def _build_package_finder(
- self,
- options, # type: Values
- session, # type: PipSession
- target_python=None, # type: Optional[TargetPython]
- ignore_requires_python=None, # type: Optional[bool]
- ):
- # type: (...) -> 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.
- """
- search_scope = make_search_scope(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(
- search_scope=search_scope,
- selection_prefs=selection_prefs,
- trusted_hosts=options.trusted_hosts,
- session=session,
- target_python=target_python,
- )
+ self.handle_pip_version_check(options)
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/cmdoptions.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/cmdoptions.py
index c5c6c22..ed42c5f 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/cli/cmdoptions.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/cli/cmdoptions.py
@@ -5,11 +5,14 @@ The principle here is to define options once, but *not* instantiate them
globally. One reason being that options with action='append' can carry state
between parses. pip parses general options twice internally, and shouldn't
pass on state. To be consistent, all options will follow this design.
-
"""
+
+# The following comment should be removed at some point in the future.
+# mypy: strict-optional=False
+
from __future__ import absolute_import
-import logging
+import os
import textwrap
import warnings
from distutils.util import strtobool
@@ -17,26 +20,23 @@ from functools import partial
from optparse import SUPPRESS_HELP, Option, OptionGroup
from textwrap import dedent
+from pip._internal.cli.progress_bars import BAR_TYPES
from pip._internal.exceptions import CommandError
from pip._internal.locations import USER_CACHE_DIR, get_src_prefix
from pip._internal.models.format_control import FormatControl
from pip._internal.models.index import PyPI
-from pip._internal.models.search_scope import SearchScope
from pip._internal.models.target_python import TargetPython
from pip._internal.utils.hashes import STRONG_HASHES
-from pip._internal.utils.misc import redact_password_from_url
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
-from pip._internal.utils.ui import BAR_TYPES
if MYPY_CHECK_RUNNING:
from typing import Any, Callable, Dict, Optional, Tuple
from optparse import OptionParser, Values
from pip._internal.cli.parser import ConfigOptionParser
-logger = logging.getLogger(__name__)
-
def raise_option_error(parser, option, msg):
+ # type: (OptionParser, Option, str) -> None
"""
Raise an option parsing error using parser.error().
@@ -75,14 +75,15 @@ def check_install_build_global(options, check_options=None):
check_options = options
def getname(n):
+ # type: (str) -> Optional[Any]
return getattr(check_options, n, None)
names = ["build_options", "global_options", "install_options"]
if any(map(getname, names)):
control = options.format_control
control.disallow_binaries()
warnings.warn(
- 'Disabling all use of wheels due to the use of --build-options '
- '/ --global-options / --install-options.', stacklevel=2,
+ 'Disabling all use of wheels due to the use of --build-option '
+ '/ --global-option / --install-option.', stacklevel=2,
)
@@ -126,6 +127,17 @@ def check_dist_restriction(options, check_target=False):
)
+def _path_option_check(option, opt, value):
+ # type: (Option, str, str) -> str
+ return os.path.expanduser(value)
+
+
+class PipOption(Option):
+ TYPES = Option.TYPES + ("path",)
+ TYPE_CHECKER = Option.TYPE_CHECKER.copy()
+ TYPE_CHECKER["path"] = _path_option_check
+
+
###########
# options #
###########
@@ -213,10 +225,11 @@ progress_bar = partial(
) # type: Callable[..., Option]
log = partial(
- Option,
+ PipOption,
"--log", "--log-file", "--local-log",
dest="log",
metavar="path",
+ type="path",
help="Path to a verbose appending log."
) # type: Callable[..., Option]
@@ -227,7 +240,7 @@ no_input = partial(
dest='no_input',
action='store_true',
default=False,
- help=SUPPRESS_HELP
+ help="Disable prompting for input."
) # type: Callable[..., Option]
proxy = partial(
@@ -259,16 +272,6 @@ timeout = partial(
help='Set the socket timeout (default %default seconds).',
) # type: Callable[..., Option]
-skip_requirements_regex = partial(
- Option,
- # A regex to be used to skip requirements
- '--skip-requirements-regex',
- dest='skip_requirements_regex',
- type='str',
- default='',
- help=SUPPRESS_HELP,
-) # type: Callable[..., Option]
-
def exists_action():
# type: () -> Option
@@ -287,19 +290,19 @@ def exists_action():
cert = partial(
- Option,
+ PipOption,
'--cert',
dest='cert',
- type='str',
+ type='path',
metavar='path',
help="Path to alternate CA bundle.",
) # type: Callable[..., Option]
client_cert = partial(
- Option,
+ PipOption,
'--client-cert',
dest='client_cert',
- type='str',
+ type='path',
default=None,
metavar='path',
help="Path to SSL client certificate, a single file containing the "
@@ -320,6 +323,7 @@ index_url = partial(
def extra_index_url():
+ # type: () -> Option
return Option(
'--extra-index-url',
dest='extra_index_urls',
@@ -350,36 +354,14 @@ def find_links():
action='append',
default=[],
metavar='url',
- help="If a url or path to an html file, then parse for links to "
- "archives. If a local path or file:// url that's a directory, "
- "then look for archives in the directory listing.",
+ help="If a URL or path to an html file, then parse for links to "
+ "archives such as sdist (.tar.gz) or wheel (.whl) files. "
+ "If a local path or file:// URL that's a directory, "
+ "then look for archives in the directory listing. "
+ "Links to VCS project URLs are not supported.",
)
-def make_search_scope(options, suppress_no_index=False):
- # type: (Values, bool) -> SearchScope
- """
- :param suppress_no_index: Whether to ignore the --no-index option
- when constructing the SearchScope object.
- """
- index_urls = [options.index_url] + options.extra_index_urls
- if options.no_index and not suppress_no_index:
- logger.debug(
- 'Ignoring indexes: %s',
- ','.join(redact_password_from_url(url) for url in index_urls),
- )
- index_urls = []
-
- # Make sure find_links is a list before passing to create().
- find_links = options.find_links or []
-
- search_scope = SearchScope.create(
- find_links=find_links, index_urls=index_urls,
- )
-
- return search_scope
-
-
def trusted_host():
# type: () -> Option
return Option(
@@ -388,8 +370,8 @@ def trusted_host():
action="append",
metavar="HOSTNAME",
default=[],
- help="Mark this host as trusted, even though it does not have valid "
- "or any HTTPS.",
+ help="Mark this host or host:port pair as trusted, even though it "
+ "does not have valid or any HTTPS.",
)
@@ -432,12 +414,21 @@ def editable():
)
+def _handle_src(option, opt_str, value, parser):
+ # type: (Option, str, str, OptionParser) -> None
+ value = os.path.abspath(value)
+ setattr(parser.values, option.dest, value)
+
+
src = partial(
- Option,
+ PipOption,
'--src', '--source', '--source-dir', '--source-directory',
dest='src_dir',
+ type='path',
metavar='dir',
default=get_src_prefix(),
+ action='callback',
+ callback=_handle_src,
help='Directory to check out editable projects into. '
'The default in a virtualenv is "/src". '
'The default for global installs is "/src".'
@@ -473,12 +464,12 @@ def no_binary():
"--no-binary", dest="format_control", action="callback",
callback=_handle_no_binary, type="str",
default=format_control,
- help="Do not use binary packages. Can be supplied multiple times, and "
- "each time adds to the existing value. Accepts either :all: to "
- "disable all binary packages, :none: to empty the set, or one or "
- "more package names with commas between them. Note that some "
- "packages are tricky to compile and may fail to install when "
- "this option is used on them.",
+ help='Do not use binary packages. Can be supplied multiple times, and '
+ 'each time adds to the existing value. Accepts either ":all:" to '
+ 'disable all binary packages, ":none:" to empty the set (notice '
+ 'the colons), or one or more package names with commas between '
+ 'them (no colons). Note that some packages are tricky to compile '
+ 'and may fail to install when this option is used on them.',
)
@@ -489,12 +480,12 @@ def only_binary():
"--only-binary", dest="format_control", action="callback",
callback=_handle_only_binary, type="str",
default=format_control,
- help="Do not use source packages. Can be supplied multiple times, and "
- "each time adds to the existing value. Accepts either :all: to "
- "disable all source packages, :none: to empty the set, or one or "
- "more package names with commas between them. Packages without "
- "binary distributions will fail to install when this option is "
- "used on them.",
+ help='Do not use source packages. Can be supplied multiple times, and '
+ 'each time adds to the existing value. Accepts either ":all:" to '
+ 'disable all source packages, ":none:" to empty the set, or one '
+ 'or more package names with commas between them. Packages '
+ 'without binary distributions will fail to install when this '
+ 'option is used on them.',
)
@@ -636,11 +627,12 @@ def prefer_binary():
cache_dir = partial(
- Option,
+ PipOption,
"--cache-dir",
dest="cache_dir",
default=USER_CACHE_DIR,
metavar="dir",
+ type='path',
help="Store the cache data in ."
) # type: Callable[..., Option]
@@ -691,12 +683,24 @@ no_deps = partial(
help="Don't install package dependencies.",
) # type: Callable[..., Option]
+
+def _handle_build_dir(option, opt, value, parser):
+ # type: (Option, str, str, OptionParser) -> None
+ if value:
+ value = os.path.abspath(value)
+ setattr(parser.values, option.dest, value)
+
+
build_dir = partial(
- Option,
+ PipOption,
'-b', '--build', '--build-dir', '--build-directory',
dest='build_dir',
+ type='path',
metavar='dir',
- help='Directory to unpack packages into and build in. Note that '
+ action='callback',
+ callback=_handle_build_dir,
+ help='(DEPRECATED) '
+ 'Directory to unpack packages into and build in. Note that '
'an initial build still takes place in a temporary directory. '
'The location of temporary directories can be controlled by setting '
'the TMPDIR environment variable (TEMP on Windows) appropriately. '
@@ -818,16 +822,6 @@ disable_pip_version_check = partial(
) # type: Callable[..., Option]
-# Deprecated, Remove later
-always_unzip = partial(
- Option,
- '-Z', '--always-unzip',
- dest='always_unzip',
- action='store_true',
- help=SUPPRESS_HELP,
-) # type: Callable[..., Option]
-
-
def _handle_merge_hash(option, opt_str, value, parser):
# type: (Option, str, str, OptionParser) -> None
"""Given a value spelled "algo:digest", append the digest to a list
@@ -837,12 +831,12 @@ def _handle_merge_hash(option, opt_str, value, parser):
try:
algo, digest = value.split(':', 1)
except ValueError:
- parser.error('Arguments to %s must be a hash name '
- 'followed by a value, like --hash=sha256:abcde...' %
- opt_str)
+ parser.error('Arguments to {} must be a hash name ' # noqa
+ 'followed by a value, like --hash=sha256:'
+ 'abcde...'.format(opt_str))
if algo not in STRONG_HASHES:
- parser.error('Allowed hash algorithms for %s are %s.' %
- (opt_str, ', '.join(STRONG_HASHES)))
+ parser.error('Allowed hash algorithms for {} are {}.'.format( # noqa
+ opt_str, ', '.join(STRONG_HASHES)))
parser.values.hashes.setdefault(algo, []).append(digest)
@@ -873,9 +867,10 @@ require_hashes = partial(
list_path = partial(
- Option,
+ PipOption,
'--path',
dest='path',
+ type='path',
action='append',
help='Restrict to the specified installation path for listing '
'packages (can be used multiple times).'
@@ -890,6 +885,52 @@ def check_list_path_option(options):
)
+no_python_version_warning = partial(
+ Option,
+ '--no-python-version-warning',
+ dest='no_python_version_warning',
+ action='store_true',
+ default=False,
+ help='Silence deprecation warnings for upcoming unsupported Pythons.',
+) # type: Callable[..., Option]
+
+
+unstable_feature = partial(
+ Option,
+ '--unstable-feature',
+ dest='unstable_features',
+ metavar='feature',
+ action='append',
+ default=[],
+ choices=['resolver'],
+ help=SUPPRESS_HELP, # TODO: drop this in pip 20.3
+) # type: Callable[..., Option]
+
+use_new_feature = partial(
+ Option,
+ '--use-feature',
+ dest='features_enabled',
+ metavar='feature',
+ action='append',
+ default=[],
+ choices=['2020-resolver', 'fast-deps'],
+ help='Enable new functionality, that may be backward incompatible.',
+) # type: Callable[..., Option]
+
+use_deprecated_feature = partial(
+ Option,
+ '--use-deprecated',
+ dest='deprecated_features_enabled',
+ metavar='feature',
+ action='append',
+ default=[],
+ choices=[],
+ help=(
+ 'Enable deprecated functionality, that will be removed in the future.'
+ ),
+) # type: Callable[..., Option]
+
+
##########
# groups #
##########
@@ -908,7 +949,6 @@ general_group = {
proxy,
retries,
timeout,
- skip_requirements_regex,
exists_action,
trusted_host,
cert,
@@ -917,6 +957,10 @@ general_group = {
no_cache,
disable_pip_version_check,
no_color,
+ no_python_version_warning,
+ unstable_feature,
+ use_new_feature,
+ use_deprecated_feature,
]
} # type: Dict[str, Any]
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/main_parser.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/main_parser.py
index 6d0b719..08c82c1 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/cli/main_parser.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/cli/main_parser.py
@@ -6,11 +6,10 @@ import sys
from pip._internal.cli import cmdoptions
from pip._internal.cli.parser import (
- ConfigOptionParser, UpdatingDefaultsHelpFormatter,
-)
-from pip._internal.commands import (
- commands_dict, get_similar_commands, get_summaries,
+ 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
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
@@ -48,8 +47,10 @@ def create_main_parser():
parser.main = True # type: ignore
# create command listing for description
- command_summaries = get_summaries()
- description = [''] + ['%-27s %s' % (i, j) for i, j in command_summaries]
+ description = [''] + [
+ '{name:27} {command_info.summary}'.format(**locals())
+ for name, command_info in commands_dict.items()
+ ]
parser.description = '\n'.join(description)
return parser
@@ -85,9 +86,9 @@ def parse_command(args):
if cmd_name not in commands_dict:
guess = get_similar_commands(cmd_name)
- msg = ['unknown command "%s"' % cmd_name]
+ msg = ['unknown command "{}"'.format(cmd_name)]
if guess:
- msg.append('maybe you meant "%s"' % guess)
+ msg.append('maybe you meant "{}"'.format(guess))
raise CommandError(' - '.join(msg))
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/cli/parser.py b/venv/lib/python3.8/site-packages/pip/_internal/cli/parser.py
index e1eaac4..04e00b7 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/cli/parser.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/cli/parser.py
@@ -1,4 +1,8 @@
"""Base option parser setup"""
+
+# The following comment should be removed at some point in the future.
+# mypy: disallow-untyped-defs=False
+
from __future__ import absolute_import
import logging
@@ -27,14 +31,14 @@ class PrettyHelpFormatter(optparse.IndentedHelpFormatter):
optparse.IndentedHelpFormatter.__init__(self, *args, **kwargs)
def format_option_strings(self, option):
- return self._format_option_strings(option, ' <%s>', ', ')
+ return self._format_option_strings(option)
- def _format_option_strings(self, option, mvarfmt=' <%s>', optsep=', '):
+ def _format_option_strings(self, option, mvarfmt=' <{}>', optsep=', '):
"""
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 - evaluated as mvarfmt % metavar
+ :param mvarfmt: metavar format string
:param optsep: separator
"""
opts = []
@@ -48,7 +52,7 @@ class PrettyHelpFormatter(optparse.IndentedHelpFormatter):
if option.takes_value():
metavar = option.metavar or option.dest.lower()
- opts.append(mvarfmt % metavar.lower())
+ opts.append(mvarfmt.format(metavar.lower()))
return ''.join(opts)
@@ -62,7 +66,8 @@ class PrettyHelpFormatter(optparse.IndentedHelpFormatter):
Ensure there is only one newline between usage and the first heading
if there is no description.
"""
- msg = '\nUsage: %s\n' % self.indent_lines(textwrap.dedent(usage), " ")
+ msg = '\nUsage: {}\n'.format(
+ self.indent_lines(textwrap.dedent(usage), " "))
return msg
def format_description(self, description):
@@ -78,7 +83,7 @@ class PrettyHelpFormatter(optparse.IndentedHelpFormatter):
description = description.rstrip()
# dedent, then reindent
description = self.indent_lines(textwrap.dedent(description), " ")
- description = '%s:\n%s\n' % (label, description)
+ description = '{}:\n{}\n'.format(label, description)
return description
else:
return ''
@@ -146,7 +151,7 @@ class ConfigOptionParser(CustomOptionParser):
try:
return option.check_value(key, val)
except optparse.OptionValueError as exc:
- print("An error occurred during configuration: %s" % exc)
+ print("An error occurred during configuration: {}".format(exc))
sys.exit(3)
def _get_ordered_configuration_items(self):
@@ -245,7 +250,7 @@ class ConfigOptionParser(CustomOptionParser):
def error(self, msg):
self.print_usage(sys.stderr)
- self.exit(UNKNOWN_ERROR, "%s\n" % msg)
+ self.exit(UNKNOWN_ERROR, "{}\n".format(msg))
def invalid_config_error_message(action, key, val):
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/__init__.py
index 9e0ab86..6825fa6 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/commands/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/__init__.py
@@ -1,59 +1,111 @@
"""
Package containing all pip commands
"""
+
+# The following comment should be removed at some point in the future.
+# mypy: disallow-untyped-defs=False
+# There is currently a bug in python/typeshed mentioned at
+# https://github.com/python/typeshed/issues/3906 which causes the
+# return type of difflib.get_close_matches to be reported
+# as List[Sequence[str]] whereas it should have been List[str]
+
from __future__ import absolute_import
-from pip._internal.commands.completion import CompletionCommand
-from pip._internal.commands.configuration import ConfigurationCommand
-from pip._internal.commands.debug import DebugCommand
-from pip._internal.commands.download import DownloadCommand
-from pip._internal.commands.freeze import FreezeCommand
-from pip._internal.commands.hash import HashCommand
-from pip._internal.commands.help import HelpCommand
-from pip._internal.commands.list import ListCommand
-from pip._internal.commands.check import CheckCommand
-from pip._internal.commands.search import SearchCommand
-from pip._internal.commands.show import ShowCommand
-from pip._internal.commands.install import InstallCommand
-from pip._internal.commands.uninstall import UninstallCommand
-from pip._internal.commands.wheel import WheelCommand
+import importlib
+from collections import OrderedDict, namedtuple
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
if MYPY_CHECK_RUNNING:
- from typing import List, Type
+ from typing import Any
from pip._internal.cli.base_command import Command
-commands_order = [
- InstallCommand,
- DownloadCommand,
- UninstallCommand,
- FreezeCommand,
- ListCommand,
- ShowCommand,
- CheckCommand,
- ConfigurationCommand,
- SearchCommand,
- WheelCommand,
- HashCommand,
- CompletionCommand,
- DebugCommand,
- HelpCommand,
-] # type: List[Type[Command]]
-commands_dict = {c.name: c for c in commands_order}
+CommandInfo = namedtuple('CommandInfo', 'module_path, class_name, summary')
+
+# The ordering matters for help display.
+# Also, even though the module path starts with the same
+# "pip._internal.commands" prefix in each case, we include the full path
+# because it makes testing easier (specifically when modifying commands_dict
+# in test setup / teardown by adding info for a FakeCommand class defined
+# in a test-related module).
+# Finally, we need to pass an iterable of pairs here rather than a dict
+# so that the ordering won't be lost when using Python 2.7.
+commands_dict = OrderedDict([
+ ('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.',
+ )),
+ ('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.",
+ )),
+ ('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.',
+ )),
+]) # type: OrderedDict[str, CommandInfo]
-def get_summaries(ordered=True):
- """Yields sorted (command name, command summary) tuples."""
+def create_command(name, **kwargs):
+ # type: (str, **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)
- if ordered:
- cmditems = _sort_commands(commands_dict, commands_order)
- else:
- cmditems = commands_dict.items()
-
- for name, command_class in cmditems:
- yield (name, command_class.summary)
+ return command
def get_similar_commands(name):
@@ -68,14 +120,3 @@ def get_similar_commands(name):
return close_commands[0]
else:
return False
-
-
-def _sort_commands(cmddict, order):
- def keyfn(key):
- try:
- return order.index(key[1])
- except ValueError:
- # unordered items should come last
- return 0xff
-
- return sorted(cmddict.items(), key=keyfn)
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-38.pyc
index 1e8b800..45a364d 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/check.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/check.cpython-38.pyc
index 027afb9..993fa68 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/check.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/check.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/completion.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/completion.cpython-38.pyc
index fde6dfe..c0f9992 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/completion.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/completion.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-38.pyc
index 6d16af1..9a18a74 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/debug.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/debug.cpython-38.pyc
index e4951ec..abc45de 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/debug.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/debug.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/download.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/download.cpython-38.pyc
index 7264525..396634d 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/download.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/download.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-38.pyc
index 0adc909..3d6bcb1 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/hash.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/hash.cpython-38.pyc
index 772beda..008bf8c 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/hash.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/hash.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/help.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/help.cpython-38.pyc
index 8436a69..a7f140c 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/help.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/help.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/install.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/install.cpython-38.pyc
index 3c79b4e..948c824 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/install.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/install.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/list.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/list.cpython-38.pyc
index a8e6e53..6e4f44d 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/list.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/list.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/search.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/search.cpython-38.pyc
index 3c8a9d0..d1fbc9e 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/search.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/search.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/show.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/show.cpython-38.pyc
index de3e629..b585ce2 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/show.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/show.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-38.pyc
index 7462f64..ea18121 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-38.pyc
index acfb10f..57758ff 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/check.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/check.py
index 801cecc..b557ca6 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/commands/check.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/check.py
@@ -1,28 +1,37 @@
import logging
from pip._internal.cli.base_command import Command
+from pip._internal.cli.status_codes import ERROR, SUCCESS
from pip._internal.operations.check import (
- check_package_set, create_package_set_from_installed,
+ check_package_set,
+ create_package_set_from_installed,
)
+from pip._internal.utils.misc import write_output
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
logger = logging.getLogger(__name__)
+if MYPY_CHECK_RUNNING:
+ from typing import List, Any
+ from optparse import Values
+
class CheckCommand(Command):
"""Verify installed packages have compatible dependencies."""
- name = 'check'
+
usage = """
%prog [options]"""
- summary = 'Verify installed packages have compatible dependencies.'
def run(self, options, args):
+ # type: (Values, List[Any]) -> int
+
package_set, parsing_probs = create_package_set_from_installed()
missing, conflicting = check_package_set(package_set)
for project_name in missing:
version = package_set[project_name].version
for dependency in missing[project_name]:
- logger.info(
+ write_output(
"%s %s requires %s, which is not installed.",
project_name, version, dependency[0],
)
@@ -30,12 +39,13 @@ class CheckCommand(Command):
for project_name in conflicting:
version = package_set[project_name].version
for dep_name, dep_version, req in conflicting[project_name]:
- logger.info(
+ write_output(
"%s %s has requirement %s, but you have %s %s.",
project_name, version, req, dep_name, dep_version,
)
if missing or conflicting or parsing_probs:
- return 1
+ return ERROR
else:
- logger.info("No broken requirements found.")
+ write_output("No broken requirements found.")
+ return SUCCESS
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/completion.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/completion.py
index 2fcdd39..9b99f51 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/commands/completion.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/completion.py
@@ -4,32 +4,38 @@ import sys
import textwrap
from pip._internal.cli.base_command import Command
+from pip._internal.cli.status_codes import SUCCESS
from pip._internal.utils.misc import get_prog
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+
+if MYPY_CHECK_RUNNING:
+ from typing import List
+ from optparse import Values
BASE_COMPLETION = """
-# pip %(shell)s completion start%(script)s# pip %(shell)s completion end
+# pip {shell} completion start{script}# pip {shell} completion end
"""
COMPLETION_SCRIPTS = {
'bash': """
_pip_completion()
- {
- COMPREPLY=( $( COMP_WORDS="${COMP_WORDS[*]}" \\
+ {{
+ COMPREPLY=( $( COMP_WORDS="${{COMP_WORDS[*]}}" \\
COMP_CWORD=$COMP_CWORD \\
- PIP_AUTO_COMPLETE=1 $1 ) )
- }
- complete -o default -F _pip_completion %(prog)s
+ PIP_AUTO_COMPLETE=1 $1 2>/dev/null ) )
+ }}
+ complete -o default -F _pip_completion {prog}
""",
'zsh': """
- function _pip_completion {
+ function _pip_completion {{
local words cword
read -Ac words
read -cn cword
reply=( $( COMP_WORDS="$words[*]" \\
COMP_CWORD=$(( cword-1 )) \\
- PIP_AUTO_COMPLETE=1 $words[1] ) )
- }
- compctl -K _pip_completion %(prog)s
+ PIP_AUTO_COMPLETE=1 $words[1] 2>/dev/null ))
+ }}
+ compctl -K _pip_completion {prog}
""",
'fish': """
function __fish_complete_pip
@@ -40,55 +46,53 @@ COMPLETION_SCRIPTS = {
set -lx PIP_AUTO_COMPLETE 1
string split \\ -- (eval $COMP_WORDS[1])
end
- complete -fa "(__fish_complete_pip)" -c %(prog)s
+ complete -fa "(__fish_complete_pip)" -c {prog}
""",
}
class CompletionCommand(Command):
"""A helper command to be used for command completion."""
- name = 'completion'
- summary = 'A helper command used for command completion.'
+
ignore_require_venv = True
- def __init__(self, *args, **kw):
- super(CompletionCommand, self).__init__(*args, **kw)
-
- cmd_opts = self.cmd_opts
-
- cmd_opts.add_option(
+ def add_options(self):
+ # type: () -> None
+ self.cmd_opts.add_option(
'--bash', '-b',
action='store_const',
const='bash',
dest='shell',
help='Emit completion code for bash')
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'--zsh', '-z',
action='store_const',
const='zsh',
dest='shell',
help='Emit completion code for zsh')
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'--fish', '-f',
action='store_const',
const='fish',
dest='shell',
help='Emit completion code for fish')
- self.parser.insert_option_group(0, cmd_opts)
+ self.parser.insert_option_group(0, self.cmd_opts)
def run(self, options, args):
+ # type: (Values, 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, '') % {
- 'prog': get_prog(),
- }
+ COMPLETION_SCRIPTS.get(options.shell, '').format(
+ prog=get_prog())
)
- print(BASE_COMPLETION % {'script': script, 'shell': options.shell})
+ print(BASE_COMPLETION.format(script=script, shell=options.shell))
+ return SUCCESS
else:
sys.stderr.write(
- 'ERROR: You must pass %s\n' % ' or '.join(shell_options)
+ 'ERROR: You must pass {}\n' .format(' or '.join(shell_options))
)
+ return SUCCESS
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/configuration.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/configuration.py
index 1ec77d2..f9b3ab7 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/commands/configuration.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/configuration.py
@@ -5,34 +5,44 @@ import subprocess
from pip._internal.cli.base_command import Command
from pip._internal.cli.status_codes import ERROR, SUCCESS
from pip._internal.configuration import (
- Configuration, get_configuration_files, kinds,
+ Configuration,
+ get_configuration_files,
+ kinds,
)
from pip._internal.exceptions import PipError
-from pip._internal.utils.deprecation import deprecated
-from pip._internal.utils.misc import get_prog
-from pip._internal.utils.virtualenv import running_under_virtualenv
+from pip._internal.utils.logging import indent_log
+from pip._internal.utils.misc import get_prog, write_output
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+
+if MYPY_CHECK_RUNNING:
+ from typing import List, Any, Optional
+ from optparse import Values
+
+ from pip._internal.configuration import Kind
logger = logging.getLogger(__name__)
class ConfigurationCommand(Command):
- """Manage local and global configuration.
+ """
+ Manage local and global configuration.
- Subcommands:
+ Subcommands:
- list: List the active configuration (or from the file specified)
- edit: Edit the configuration file in an editor
- get: Get the value associated with name
- set: Set the name=value
- unset: Unset the value associated with name
+ - list: List the active configuration (or from the file specified)
+ - edit: Edit the configuration file in an editor
+ - get: Get the value associated with name
+ - set: Set the name=value
+ - unset: Unset the value associated with name
+ - debug: List the configuration files and values defined under them
- If none of --user, --global and --site are passed, a virtual
- environment configuration file is used if one is active and the file
- exists. Otherwise, all modifications happen on the to the user file by
- default.
+ If none of --user, --global and --site are passed, a virtual
+ environment configuration file is used if one is active and the file
+ exists. Otherwise, all modifications happen on the to the user file by
+ default.
"""
- name = 'config'
+ ignore_require_venv = True
usage = """
%prog [] list
%prog [] [--editor ] edit
@@ -40,15 +50,11 @@ class ConfigurationCommand(Command):
%prog [] get name
%prog [] set name value
%prog [] unset name
+ %prog [] debug
"""
- summary = "Manage local and global configuration."
-
- def __init__(self, *args, **kwargs):
- super(ConfigurationCommand, self).__init__(*args, **kwargs)
-
- self.configuration = None
-
+ def add_options(self):
+ # type: () -> None
self.cmd_opts.add_option(
'--editor',
dest='editor',
@@ -84,32 +90,24 @@ class ConfigurationCommand(Command):
help='Use the current environment configuration file only'
)
- self.cmd_opts.add_option(
- '--venv',
- dest='venv_file',
- action='store_true',
- default=False,
- help=(
- '[Deprecated] Use the current environment configuration '
- 'file in a virtual environment only'
- )
- )
-
self.parser.insert_option_group(0, self.cmd_opts)
def run(self, options, args):
+ # type: (Values, List[str]) -> int
handlers = {
"list": self.list_values,
"edit": self.open_in_editor,
"get": self.get_name,
"set": self.set_name_value,
- "unset": self.unset_name
+ "unset": self.unset_name,
+ "debug": self.list_config_values,
}
# Determine action
if not args or args[0] not in handlers:
- logger.error("Need an action ({}) to perform.".format(
- ", ".join(sorted(handlers)))
+ logger.error(
+ "Need an action (%s) to perform.",
+ ", ".join(sorted(handlers)),
)
return ERROR
@@ -141,21 +139,7 @@ class ConfigurationCommand(Command):
return SUCCESS
def _determine_file(self, options, need_value):
- # Convert legacy venv_file option to site_file or error
- if options.venv_file and not options.site_file:
- if running_under_virtualenv():
- options.site_file = True
- deprecated(
- "The --venv option has been deprecated.",
- replacement="--site",
- gone_in="19.3",
- )
- else:
- raise PipError(
- "Legacy --venv option requires a virtual environment. "
- "Use --site instead."
- )
-
+ # type: (Values, bool) -> Optional[Kind]
file_options = [key for key, value in (
(kinds.USER, options.user_file),
(kinds.GLOBAL, options.global_file),
@@ -182,30 +166,70 @@ class ConfigurationCommand(Command):
)
def list_values(self, options, args):
+ # type: (Values, List[str]) -> None
self._get_n_args(args, "list", n=0)
for key, value in sorted(self.configuration.items()):
- logger.info("%s=%r", key, value)
+ write_output("%s=%r", key, value)
def get_name(self, options, args):
+ # type: (Values, List[str]) -> None
key = self._get_n_args(args, "get [name]", n=1)
value = self.configuration.get_value(key)
- logger.info("%s", value)
+ write_output("%s", value)
def set_name_value(self, options, args):
+ # type: (Values, List[str]) -> None
key, value = self._get_n_args(args, "set [name] [value]", n=2)
self.configuration.set_value(key, value)
self._save_configuration()
def unset_name(self, options, args):
+ # type: (Values, List[str]) -> None
key = self._get_n_args(args, "unset [name]", n=1)
self.configuration.unset_value(key)
self._save_configuration()
+ def list_config_values(self, options, args):
+ # type: (Values, List[str]) -> None
+ """List config key-value pairs across different config files"""
+ self._get_n_args(args, "debug", n=0)
+
+ self.print_env_var_values()
+ # Iterate over config files and print if they exist, and the
+ # key-value pairs present in them if they do
+ for variant, files in sorted(self.configuration.iter_config_files()):
+ write_output("%s:", variant)
+ for fname in files:
+ with indent_log():
+ file_exists = os.path.exists(fname)
+ write_output("%s, exists: %r",
+ fname, file_exists)
+ if file_exists:
+ self.print_config_file_values(variant)
+
+ def print_config_file_values(self, variant):
+ # type: (Kind) -> None
+ """Get key-value pairs from the file of a variant"""
+ for name, value in self.configuration.\
+ get_values_in_config(variant).items():
+ with indent_log():
+ write_output("%s: %s", name, value)
+
+ def print_env_var_values(self):
+ # type: () -> None
+ """Get key-values pairs present as environment variables"""
+ write_output("%s:", 'env_var')
+ with indent_log():
+ for key, value in sorted(self.configuration.get_environ_vars()):
+ env_var = 'PIP_{}'.format(key.upper())
+ write_output("%s=%r", env_var, value)
+
def open_in_editor(self, options, args):
+ # type: (Values, List[str]) -> None
editor = self._determine_editor(options)
fname = self.configuration.get_file_to_edit()
@@ -221,6 +245,7 @@ class ConfigurationCommand(Command):
)
def _get_n_args(self, args, example, n):
+ # type: (List[str], str, int) -> Any
"""Helper to make sure the command got the right number of arguments
"""
if len(args) != n:
@@ -236,18 +261,19 @@ class ConfigurationCommand(Command):
return args
def _save_configuration(self):
+ # type: () -> None
# We successfully ran a modifying command. Need to save the
# configuration.
try:
self.configuration.save()
except Exception:
- logger.error(
- "Unable to save configuration. Please report this as a bug.",
- exc_info=1
+ logger.exception(
+ "Unable to save configuration. Please report this as a bug."
)
raise PipError("Internal Error.")
def _determine_editor(self, options):
+ # type: (Values) -> str
if options.editor is not None:
return options.editor
elif "VISUAL" in os.environ:
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/debug.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/debug.py
index eb4f8c4..ff369d7 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/commands/debug.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/debug.py
@@ -2,8 +2,14 @@ from __future__ import absolute_import
import locale
import logging
+import os
import sys
+import pip._vendor
+from pip._vendor import pkg_resources
+from pip._vendor.certifi import where
+
+from pip import __file__ as pip_location
from pip._internal.cli import cmdoptions
from pip._internal.cli.base_command import Command
from pip._internal.cli.cmdoptions import make_target_python
@@ -11,18 +17,19 @@ from pip._internal.cli.status_codes import SUCCESS
from pip._internal.utils.logging import indent_log
from pip._internal.utils.misc import get_pip_version
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
-from pip._internal.wheel import format_tag
if MYPY_CHECK_RUNNING:
- from typing import Any, List
+ from types import ModuleType
+ from typing import List, Optional, Dict
from optparse import Values
+ from pip._internal.configuration import Configuration
logger = logging.getLogger(__name__)
def show_value(name, value):
- # type: (str, str) -> None
- logger.info('{}: {}'.format(name, value))
+ # type: (str, Optional[str]) -> None
+ logger.info('%s: %s', name, value)
def show_sys_implementation():
@@ -38,6 +45,88 @@ def show_sys_implementation():
show_value('name', implementation_name)
+def create_vendor_txt_map():
+ # type: () -> Dict[str, str]
+ vendor_txt_path = os.path.join(
+ os.path.dirname(pip_location),
+ '_vendor',
+ 'vendor.txt'
+ )
+
+ with open(vendor_txt_path) as f:
+ # Purge non version specifying lines.
+ # Also, remove any space prefix or suffixes (including comments).
+ lines = [line.strip().split(' ', 1)[0]
+ for line in f.readlines() if '==' in line]
+
+ # Transform into "module" -> version dict.
+ return dict(line.split('==', 1) for line in lines) # type: ignore
+
+
+def get_module_from_module_name(module_name):
+ # type: (str) -> ModuleType
+ # Module name can be uppercase in vendor.txt for some reason...
+ module_name = module_name.lower()
+ # PATCH: setuptools is actually only pkg_resources.
+ if module_name == 'setuptools':
+ module_name = 'pkg_resources'
+
+ __import__(
+ 'pip._vendor.{}'.format(module_name),
+ globals(),
+ locals(),
+ level=0
+ )
+ return getattr(pip._vendor, module_name)
+
+
+def get_vendor_version_from_module(module_name):
+ # type: (str) -> Optional[str]
+ module = get_module_from_module_name(module_name)
+ version = getattr(module, '__version__', None)
+
+ if not version:
+ # Try to find version in debundled module info
+ # The type for module.__file__ is Optional[str] in
+ # Python 2, and str in Python 3. The type: ignore is
+ # added to account for Python 2, instead of a cast
+ # and should be removed once we drop Python 2 support
+ pkg_set = pkg_resources.WorkingSet(
+ [os.path.dirname(module.__file__)] # type: ignore
+ )
+ package = pkg_set.find(pkg_resources.Requirement.parse(module_name))
+ version = getattr(package, 'version', None)
+
+ return version
+
+
+def show_actual_vendor_versions(vendor_txt_versions):
+ # type: (Dict[str, str]) -> None
+ """Log the actual version and print extra info if there is
+ a conflict or if the actual version could not be imported.
+ """
+ for module_name, expected_version in vendor_txt_versions.items():
+ extra_message = ''
+ actual_version = get_vendor_version_from_module(module_name)
+ if not actual_version:
+ extra_message = ' (Unable to locate actual module version, using'\
+ ' vendor.txt specified version)'
+ actual_version = expected_version
+ elif actual_version != expected_version:
+ extra_message = ' (CONFLICT: vendor.txt suggests version should'\
+ ' be {})'.format(expected_version)
+ logger.info('%s==%s%s', module_name, actual_version, extra_message)
+
+
+def show_vendor_versions():
+ # type: () -> None
+ logger.info('vendored library versions:')
+
+ vendor_txt_versions = create_vendor_txt_map()
+ with indent_log():
+ show_actual_vendor_versions(vendor_txt_versions)
+
+
def show_tags(options):
# type: (Values) -> None
tag_limit = 10
@@ -62,7 +151,7 @@ def show_tags(options):
with indent_log():
for tag in tags:
- logger.info(format_tag(tag))
+ logger.info(str(tag))
if tags_limited:
msg = (
@@ -72,26 +161,44 @@ def show_tags(options):
logger.info(msg)
+def ca_bundle_info(config):
+ # type: (Configuration) -> str
+ levels = set()
+ for key, _ in config.items():
+ levels.add(key.split('.')[0])
+
+ if not levels:
+ return "Not specified"
+
+ levels_that_override_global = ['install', 'wheel', 'download']
+ global_overriding_level = [
+ level for level in levels if level in levels_that_override_global
+ ]
+ if not global_overriding_level:
+ return 'global'
+
+ if 'global' in levels:
+ levels.remove('global')
+ return ", ".join(levels)
+
+
class DebugCommand(Command):
"""
Display debug information.
"""
- name = 'debug'
usage = """
%prog """
- summary = 'Show information useful for debugging.'
ignore_require_venv = True
- def __init__(self, *args, **kw):
- super(DebugCommand, self).__init__(*args, **kw)
-
- cmd_opts = self.cmd_opts
- cmdoptions.add_target_python_options(cmd_opts)
- self.parser.insert_option_group(0, cmd_opts)
+ def add_options(self):
+ # type: () -> None
+ cmdoptions.add_target_python_options(self.cmd_opts)
+ self.parser.insert_option_group(0, self.cmd_opts)
+ self.parser.config.load()
def run(self, options, args):
- # type: (Values, List[Any]) -> int
+ # type: (Values, List[str]) -> int
logger.warning(
"This command is only meant for debugging. "
"Do not use this with automation for parsing and getting these "
@@ -109,6 +216,14 @@ class DebugCommand(Command):
show_value('sys.platform', sys.platform)
show_sys_implementation()
+ show_value("'cert' config value", ca_bundle_info(self.parser.config))
+ show_value("REQUESTS_CA_BUNDLE", os.environ.get('REQUESTS_CA_BUNDLE'))
+ show_value("CURL_CA_BUNDLE", os.environ.get('CURL_CA_BUNDLE'))
+ show_value("pip._vendor.certifi.where()", where())
+ show_value("pip._vendor.DEBUNDLED", pip._vendor.DEBUNDLED)
+
+ show_vendor_versions()
+
show_tags(options)
return SUCCESS
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/download.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/download.py
index 5642b56..46e8371 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/commands/download.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/download.py
@@ -4,15 +4,17 @@ import logging
import os
from pip._internal.cli import cmdoptions
-from pip._internal.cli.base_command import RequirementCommand
from pip._internal.cli.cmdoptions import make_target_python
-from pip._internal.legacy_resolve import Resolver
-from pip._internal.operations.prepare import RequirementPreparer
-from pip._internal.req import RequirementSet
-from pip._internal.req.req_tracker import RequirementTracker
-from pip._internal.utils.filesystem import check_path_owner
-from pip._internal.utils.misc import ensure_dir, normalize_path
+from pip._internal.cli.req_command import RequirementCommand, with_cleanup
+from pip._internal.cli.status_codes import SUCCESS
+from pip._internal.req.req_tracker import get_requirement_tracker
+from pip._internal.utils.misc import ensure_dir, normalize_path, write_output
from pip._internal.utils.temp_dir import TempDirectory
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+
+if MYPY_CHECK_RUNNING:
+ from optparse import Values
+ from typing import List
logger = logging.getLogger(__name__)
@@ -29,7 +31,6 @@ class DownloadCommand(RequirementCommand):
pip also supports downloading from "requirements files", which provide
an easy way to specify a whole environment to be downloaded.
"""
- name = 'download'
usage = """
%prog [options] [package-index-options] ...
@@ -38,31 +39,25 @@ class DownloadCommand(RequirementCommand):
%prog [options] ...
%prog [options] ..."""
- summary = 'Download packages.'
+ def add_options(self):
+ # type: () -> None
+ self.cmd_opts.add_option(cmdoptions.constraints())
+ self.cmd_opts.add_option(cmdoptions.requirements())
+ self.cmd_opts.add_option(cmdoptions.build_dir())
+ self.cmd_opts.add_option(cmdoptions.no_deps())
+ self.cmd_opts.add_option(cmdoptions.global_options())
+ self.cmd_opts.add_option(cmdoptions.no_binary())
+ self.cmd_opts.add_option(cmdoptions.only_binary())
+ self.cmd_opts.add_option(cmdoptions.prefer_binary())
+ self.cmd_opts.add_option(cmdoptions.src())
+ self.cmd_opts.add_option(cmdoptions.pre())
+ self.cmd_opts.add_option(cmdoptions.require_hashes())
+ self.cmd_opts.add_option(cmdoptions.progress_bar())
+ self.cmd_opts.add_option(cmdoptions.no_build_isolation())
+ self.cmd_opts.add_option(cmdoptions.use_pep517())
+ self.cmd_opts.add_option(cmdoptions.no_use_pep517())
- def __init__(self, *args, **kw):
- super(DownloadCommand, self).__init__(*args, **kw)
-
- cmd_opts = self.cmd_opts
-
- cmd_opts.add_option(cmdoptions.constraints())
- cmd_opts.add_option(cmdoptions.requirements())
- cmd_opts.add_option(cmdoptions.build_dir())
- cmd_opts.add_option(cmdoptions.no_deps())
- cmd_opts.add_option(cmdoptions.global_options())
- cmd_opts.add_option(cmdoptions.no_binary())
- cmd_opts.add_option(cmdoptions.only_binary())
- cmd_opts.add_option(cmdoptions.prefer_binary())
- cmd_opts.add_option(cmdoptions.src())
- cmd_opts.add_option(cmdoptions.pre())
- cmd_opts.add_option(cmdoptions.no_clean())
- cmd_opts.add_option(cmdoptions.require_hashes())
- cmd_opts.add_option(cmdoptions.progress_bar())
- cmd_opts.add_option(cmdoptions.no_build_isolation())
- cmd_opts.add_option(cmdoptions.use_pep517())
- cmd_opts.add_option(cmdoptions.no_use_pep517())
-
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'-d', '--dest', '--destination-dir', '--destination-directory',
dest='download_dir',
metavar='dir',
@@ -70,7 +65,7 @@ class DownloadCommand(RequirementCommand):
help=("Download packages into ."),
)
- cmdoptions.add_target_python_options(cmd_opts)
+ cmdoptions.add_target_python_options(self.cmd_opts)
index_opts = cmdoptions.make_option_group(
cmdoptions.index_group,
@@ -78,9 +73,12 @@ class DownloadCommand(RequirementCommand):
)
self.parser.insert_option_group(0, index_opts)
- self.parser.insert_option_group(0, cmd_opts)
+ self.parser.insert_option_group(0, self.cmd_opts)
+ @with_cleanup
def run(self, options, args):
+ # type: (Values, List[str]) -> int
+
options.ignore_installed = True
# editable doesn't really make sense for `pip download`, but the bowels
# of the RequirementSet code require that property.
@@ -88,81 +86,58 @@ class DownloadCommand(RequirementCommand):
cmdoptions.check_dist_restriction(options)
- options.src_dir = os.path.abspath(options.src_dir)
options.download_dir = normalize_path(options.download_dir)
ensure_dir(options.download_dir)
- with self._build_session(options) as session:
- target_python = make_target_python(options)
- finder = self._build_package_finder(
- options=options,
- session=session,
- target_python=target_python,
- )
- build_delete = (not (options.no_clean or options.build_dir))
- if options.cache_dir and not check_path_owner(options.cache_dir):
- logger.warning(
- "The directory '%s' or its parent directory is not owned "
- "by the current user and caching wheels has been "
- "disabled. check the permissions and owner of that "
- "directory. If executing pip with sudo, you may want "
- "sudo's -H flag.",
- options.cache_dir,
- )
- options.cache_dir = None
+ session = self.get_default_session(options)
- with RequirementTracker() as req_tracker, TempDirectory(
- options.build_dir, delete=build_delete, kind="download"
- ) as directory:
+ target_python = make_target_python(options)
+ finder = self._build_package_finder(
+ options=options,
+ session=session,
+ target_python=target_python,
+ )
+ build_delete = (not (options.no_clean or options.build_dir))
- requirement_set = RequirementSet(
- require_hashes=options.require_hashes,
- )
- self.populate_requirement_set(
- requirement_set,
- args,
- options,
- finder,
- session,
- self.name,
- None
- )
+ req_tracker = self.enter_context(get_requirement_tracker())
- preparer = RequirementPreparer(
- build_dir=directory.path,
- src_dir=options.src_dir,
- download_dir=options.download_dir,
- wheel_download_dir=None,
- progress_bar=options.progress_bar,
- build_isolation=options.build_isolation,
- req_tracker=req_tracker,
- )
+ directory = TempDirectory(
+ options.build_dir,
+ delete=build_delete,
+ kind="download",
+ globally_managed=True,
+ )
- resolver = Resolver(
- preparer=preparer,
- finder=finder,
- session=session,
- wheel_cache=None,
- use_user_site=False,
- upgrade_strategy="to-satisfy-only",
- force_reinstall=False,
- ignore_dependencies=options.ignore_dependencies,
- py_version_info=options.python_version,
- ignore_requires_python=False,
- ignore_installed=True,
- isolated=options.isolated_mode,
- )
- resolver.resolve(requirement_set)
+ reqs = self.get_requirements(args, options, finder, session)
- downloaded = ' '.join([
- req.name for req in requirement_set.successfully_downloaded
- ])
- if downloaded:
- logger.info('Successfully downloaded %s', downloaded)
+ preparer = self.make_requirement_preparer(
+ temp_build_dir=directory,
+ options=options,
+ req_tracker=req_tracker,
+ session=session,
+ finder=finder,
+ download_dir=options.download_dir,
+ use_user_site=False,
+ )
- # Clean up
- if not options.no_clean:
- requirement_set.cleanup_files()
+ resolver = self.make_resolver(
+ preparer=preparer,
+ finder=finder,
+ options=options,
+ py_version_info=options.python_version,
+ )
- return requirement_set
+ self.trace_basic_info(finder)
+
+ requirement_set = resolver.resolve(
+ reqs, check_supported_wheels=True
+ )
+
+ downloaded = ' '.join([req.name # type: ignore
+ for req in requirement_set.requirements.values()
+ if req.successfully_downloaded])
+ if downloaded:
+ write_output('Successfully downloaded %s', downloaded)
+
+ return SUCCESS
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/freeze.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/freeze.py
index 9fc5b04..2071fba 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/commands/freeze.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/freeze.py
@@ -5,12 +5,18 @@ import sys
from pip._internal.cache import WheelCache
from pip._internal.cli import cmdoptions
from pip._internal.cli.base_command import Command
+from pip._internal.cli.status_codes import SUCCESS
from pip._internal.models.format_control import FormatControl
from pip._internal.operations.freeze import freeze
from pip._internal.utils.compat import stdlib_pkgs
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
DEV_PKGS = {'pip', 'setuptools', 'distribute', 'wheel'}
+if MYPY_CHECK_RUNNING:
+ from optparse import Values
+ from typing import List
+
class FreezeCommand(Command):
"""
@@ -18,15 +24,13 @@ class FreezeCommand(Command):
packages are listed in a case-insensitive sorted order.
"""
- name = 'freeze'
+
usage = """
%prog [options]"""
- summary = 'Output installed packages in requirements format.'
log_streams = ("ext://sys.stderr", "ext://sys.stderr")
- def __init__(self, *args, **kw):
- super(FreezeCommand, self).__init__(*args, **kw)
-
+ def add_options(self):
+ # type: () -> None
self.cmd_opts.add_option(
'-r', '--requirement',
dest='requirements',
@@ -63,7 +67,7 @@ class FreezeCommand(Command):
dest='freeze_all',
action='store_true',
help='Do not skip these packages in the output:'
- ' %s' % ', '.join(DEV_PKGS))
+ ' {}'.format(', '.join(DEV_PKGS)))
self.cmd_opts.add_option(
'--exclude-editable',
dest='exclude_editable',
@@ -73,6 +77,7 @@ class FreezeCommand(Command):
self.parser.insert_option_group(0, self.cmd_opts)
def run(self, options, args):
+ # type: (Values, List[str]) -> int
format_control = FormatControl(set(), set())
wheel_cache = WheelCache(options.cache_dir, format_control)
skip = set(stdlib_pkgs)
@@ -87,15 +92,12 @@ class FreezeCommand(Command):
local_only=options.local,
user_only=options.user,
paths=options.path,
- skip_regex=options.skip_requirements_regex,
isolated=options.isolated_mode,
wheel_cache=wheel_cache,
skip=skip,
exclude_editable=options.exclude_editable,
)
- try:
- for line in freeze(**freeze_kwargs):
- sys.stdout.write(line + '\n')
- finally:
- wheel_cache.cleanup()
+ for line in freeze(**freeze_kwargs):
+ sys.stdout.write(line + '\n')
+ return SUCCESS
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/hash.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/hash.py
index 423440e..37831c3 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/commands/hash.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/hash.py
@@ -5,9 +5,14 @@ import logging
import sys
from pip._internal.cli.base_command import Command
-from pip._internal.cli.status_codes import ERROR
+from pip._internal.cli.status_codes import ERROR, SUCCESS
from pip._internal.utils.hashes import FAVORITE_HASH, STRONG_HASHES
-from pip._internal.utils.misc import read_chunks
+from pip._internal.utils.misc import read_chunks, write_output
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+
+if MYPY_CHECK_RUNNING:
+ from optparse import Values
+ from typing import List
logger = logging.getLogger(__name__)
@@ -18,37 +23,38 @@ class HashCommand(Command):
These can be used with --hash in a requirements file to do repeatable
installs.
-
"""
- name = 'hash'
+
usage = '%prog [options] ...'
- summary = 'Compute hashes of package archives.'
ignore_require_venv = True
- def __init__(self, *args, **kw):
- super(HashCommand, self).__init__(*args, **kw)
+ def add_options(self):
+ # type: () -> None
self.cmd_opts.add_option(
'-a', '--algorithm',
dest='algorithm',
choices=STRONG_HASHES,
action='store',
default=FAVORITE_HASH,
- help='The hash algorithm to use: one of %s' %
- ', '.join(STRONG_HASHES))
+ help='The hash algorithm to use: one of {}'.format(
+ ', '.join(STRONG_HASHES)))
self.parser.insert_option_group(0, self.cmd_opts)
def run(self, options, args):
+ # type: (Values, List[str]) -> int
if not args:
self.parser.print_usage(sys.stderr)
return ERROR
algorithm = options.algorithm
for path in args:
- logger.info('%s:\n--hash=%s:%s',
- path, algorithm, _hash_of_file(path, algorithm))
+ write_output('%s:\n--hash=%s:%s',
+ path, algorithm, _hash_of_file(path, algorithm))
+ return SUCCESS
def _hash_of_file(path, algorithm):
+ # type: (str, str) -> str
"""Return the hash digest of a file."""
with open(path, 'rb') as archive:
hash = hashlib.new(algorithm)
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/help.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/help.py
index 49a81cb..a2edc29 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/commands/help.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/help.py
@@ -3,18 +3,25 @@ from __future__ import absolute_import
from pip._internal.cli.base_command import Command
from pip._internal.cli.status_codes import SUCCESS
from pip._internal.exceptions import CommandError
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+
+if MYPY_CHECK_RUNNING:
+ from typing import List
+ from optparse import Values
class HelpCommand(Command):
"""Show help for commands"""
- name = 'help'
+
usage = """
%prog """
- summary = 'Show help for commands.'
ignore_require_venv = True
def run(self, options, args):
- from pip._internal.commands import commands_dict, get_similar_commands
+ # type: (Values, List[str]) -> int
+ from pip._internal.commands import (
+ commands_dict, create_command, get_similar_commands,
+ )
try:
# 'pip help' with no args is handled by pip.__init__.parseopt()
@@ -25,13 +32,13 @@ class HelpCommand(Command):
if cmd_name not in commands_dict:
guess = get_similar_commands(cmd_name)
- msg = ['unknown command "%s"' % cmd_name]
+ msg = ['unknown command "{}"'.format(cmd_name)]
if guess:
- msg.append('maybe you meant "%s"' % guess)
+ msg.append('maybe you meant "{}"'.format(guess))
raise CommandError(' - '.join(msg))
- command = commands_dict[cmd_name]()
+ command = create_command(cmd_name)
command.parser.print_help()
return SUCCESS
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/install.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/install.py
index ebeceac..704e2d6 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/commands/install.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/install.py
@@ -5,71 +5,61 @@ import logging
import operator
import os
import shutil
+import site
from optparse import SUPPRESS_HELP
from pip._vendor import pkg_resources
+from pip._vendor.packaging.utils import canonicalize_name
from pip._internal.cache import WheelCache
from pip._internal.cli import cmdoptions
-from pip._internal.cli.base_command import RequirementCommand
from pip._internal.cli.cmdoptions import make_target_python
-from pip._internal.cli.status_codes import ERROR
-from pip._internal.exceptions import (
- CommandError, InstallationError, PreviousBuildDirError,
-)
-from pip._internal.legacy_resolve import Resolver
+from pip._internal.cli.req_command import RequirementCommand, with_cleanup
+from pip._internal.cli.status_codes import ERROR, SUCCESS
+from pip._internal.exceptions import CommandError, InstallationError
from pip._internal.locations import distutils_scheme
from pip._internal.operations.check import check_install_conflicts
-from pip._internal.operations.prepare import RequirementPreparer
-from pip._internal.req import RequirementSet, install_given_reqs
-from pip._internal.req.req_tracker import RequirementTracker
-from pip._internal.utils.filesystem import check_path_owner
+from pip._internal.req import install_given_reqs
+from pip._internal.req.req_tracker import get_requirement_tracker
+from pip._internal.utils.datetime import today_is_later_than
+from pip._internal.utils.distutils_args import parse_distutils_args
+from pip._internal.utils.filesystem import test_writable_dir
from pip._internal.utils.misc import (
- ensure_dir, get_installed_version,
+ ensure_dir,
+ get_installed_version,
+ get_pip_version,
protect_pip_from_modification_on_windows,
+ write_output,
)
from pip._internal.utils.temp_dir import TempDirectory
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
from pip._internal.utils.virtualenv import virtualenv_no_global
-from pip._internal.wheel import WheelBuilder
+from pip._internal.wheel_builder import build, should_build_for_install_command
+
+if MYPY_CHECK_RUNNING:
+ from optparse import Values
+ from typing import Iterable, List, Optional
+
+ from pip._internal.models.format_control import FormatControl
+ from pip._internal.operations.check import ConflictDetails
+ from pip._internal.req.req_install import InstallRequirement
+ from pip._internal.wheel_builder import BinaryAllowedPredicate
+
logger = logging.getLogger(__name__)
-def is_wheel_installed():
- """
- Return whether the wheel package is installed.
- """
- try:
- import wheel # noqa: F401
- except ImportError:
- return False
+def get_check_binary_allowed(format_control):
+ # type: (FormatControl) -> BinaryAllowedPredicate
+ def check_binary_allowed(req):
+ # type: (InstallRequirement) -> bool
+ if req.use_pep517:
+ return True
+ canonical_name = canonicalize_name(req.name)
+ allowed_formats = format_control.get_allowed_formats(canonical_name)
+ return "binary" in allowed_formats
- return True
-
-
-def build_wheels(builder, pep517_requirements, legacy_requirements, session):
- """
- Build wheels for requirements, depending on whether wheel is installed.
- """
- # We don't build wheels for legacy requirements if wheel is not installed.
- should_build_legacy = is_wheel_installed()
-
- # Always build PEP 517 requirements
- build_failures = builder.build(
- pep517_requirements,
- session=session, autobuilding=True
- )
-
- if should_build_legacy:
- # We don't care about failures building legacy
- # requirements, as we'll fall through to a direct
- # install for those.
- builder.build(
- legacy_requirements,
- session=session, autobuilding=True
- )
-
- return build_failures
+ return check_binary_allowed
class InstallCommand(RequirementCommand):
@@ -81,10 +71,9 @@ class InstallCommand(RequirementCommand):
- Local project directories.
- Local or remote source archives.
- pip also supports installing from "requirements files," which provide
+ pip also supports installing from "requirements files", which provide
an easy way to specify a whole environment to be installed.
"""
- name = 'install'
usage = """
%prog [options] [package-index-options] ...
@@ -93,20 +82,15 @@ class InstallCommand(RequirementCommand):
%prog [options] [-e] ...
%prog [options] ..."""
- summary = 'Install packages.'
+ def add_options(self):
+ # type: () -> None
+ self.cmd_opts.add_option(cmdoptions.requirements())
+ self.cmd_opts.add_option(cmdoptions.constraints())
+ self.cmd_opts.add_option(cmdoptions.no_deps())
+ self.cmd_opts.add_option(cmdoptions.pre())
- def __init__(self, *args, **kw):
- super(InstallCommand, self).__init__(*args, **kw)
-
- cmd_opts = self.cmd_opts
-
- cmd_opts.add_option(cmdoptions.requirements())
- cmd_opts.add_option(cmdoptions.constraints())
- cmd_opts.add_option(cmdoptions.no_deps())
- cmd_opts.add_option(cmdoptions.pre())
-
- cmd_opts.add_option(cmdoptions.editable())
- cmd_opts.add_option(
+ self.cmd_opts.add_option(cmdoptions.editable())
+ self.cmd_opts.add_option(
'-t', '--target',
dest='target_dir',
metavar='dir',
@@ -116,9 +100,9 @@ class InstallCommand(RequirementCommand):
'. Use --upgrade to replace existing packages in '
'with new versions.'
)
- cmdoptions.add_target_python_options(cmd_opts)
+ cmdoptions.add_target_python_options(self.cmd_opts)
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'--user',
dest='use_user_site',
action='store_true',
@@ -126,19 +110,19 @@ class InstallCommand(RequirementCommand):
"platform. Typically ~/.local/, or %APPDATA%\\Python on "
"Windows. (See the Python documentation for site.USER_BASE "
"for full details.)")
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'--no-user',
dest='use_user_site',
action='store_false',
help=SUPPRESS_HELP)
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'--root',
dest='root_path',
metavar='dir',
default=None,
help="Install everything relative to this alternate root "
"directory.")
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'--prefix',
dest='prefix_path',
metavar='dir',
@@ -146,11 +130,11 @@ class InstallCommand(RequirementCommand):
help="Installation prefix where lib, bin and other top-level "
"folders are placed")
- cmd_opts.add_option(cmdoptions.build_dir())
+ self.cmd_opts.add_option(cmdoptions.build_dir())
- cmd_opts.add_option(cmdoptions.src())
+ self.cmd_opts.add_option(cmdoptions.src())
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'-U', '--upgrade',
dest='upgrade',
action='store_true',
@@ -159,7 +143,7 @@ class InstallCommand(RequirementCommand):
'upgrade-strategy used.'
)
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'--upgrade-strategy',
dest='upgrade_strategy',
default='only-if-needed',
@@ -173,28 +157,32 @@ class InstallCommand(RequirementCommand):
'satisfy the requirements of the upgraded package(s).'
)
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'--force-reinstall',
dest='force_reinstall',
action='store_true',
help='Reinstall all packages even if they are already '
'up-to-date.')
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'-I', '--ignore-installed',
dest='ignore_installed',
action='store_true',
- help='Ignore the installed packages (reinstalling instead).')
+ help='Ignore the installed packages, overwriting them. '
+ 'This can break your system if the existing package '
+ 'is of a different version or was installed '
+ 'with a different package manager!'
+ )
- cmd_opts.add_option(cmdoptions.ignore_requires_python())
- cmd_opts.add_option(cmdoptions.no_build_isolation())
- cmd_opts.add_option(cmdoptions.use_pep517())
- cmd_opts.add_option(cmdoptions.no_use_pep517())
+ self.cmd_opts.add_option(cmdoptions.ignore_requires_python())
+ self.cmd_opts.add_option(cmdoptions.no_build_isolation())
+ self.cmd_opts.add_option(cmdoptions.use_pep517())
+ self.cmd_opts.add_option(cmdoptions.no_use_pep517())
- cmd_opts.add_option(cmdoptions.install_options())
- cmd_opts.add_option(cmdoptions.global_options())
+ self.cmd_opts.add_option(cmdoptions.install_options())
+ self.cmd_opts.add_option(cmdoptions.global_options())
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
"--compile",
action="store_true",
dest="compile",
@@ -202,21 +190,21 @@ class InstallCommand(RequirementCommand):
help="Compile Python source files to bytecode",
)
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
"--no-compile",
action="store_false",
dest="compile",
help="Do not compile Python source files to bytecode",
)
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
"--no-warn-script-location",
action="store_false",
dest="warn_script_location",
default=True,
help="Do not warn when installing scripts outside PATH",
)
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
"--no-warn-conflicts",
action="store_false",
dest="warn_about_conflicts",
@@ -224,12 +212,11 @@ class InstallCommand(RequirementCommand):
help="Do not warn about broken dependencies",
)
- cmd_opts.add_option(cmdoptions.no_binary())
- cmd_opts.add_option(cmdoptions.only_binary())
- cmd_opts.add_option(cmdoptions.prefer_binary())
- cmd_opts.add_option(cmdoptions.no_clean())
- cmd_opts.add_option(cmdoptions.require_hashes())
- cmd_opts.add_option(cmdoptions.progress_bar())
+ self.cmd_opts.add_option(cmdoptions.no_binary())
+ self.cmd_opts.add_option(cmdoptions.only_binary())
+ self.cmd_opts.add_option(cmdoptions.prefer_binary())
+ self.cmd_opts.add_option(cmdoptions.require_hashes())
+ self.cmd_opts.add_option(cmdoptions.progress_bar())
index_opts = cmdoptions.make_option_group(
cmdoptions.index_group,
@@ -237,36 +224,34 @@ class InstallCommand(RequirementCommand):
)
self.parser.insert_option_group(0, index_opts)
- self.parser.insert_option_group(0, cmd_opts)
+ self.parser.insert_option_group(0, self.cmd_opts)
+ @with_cleanup
def run(self, options, args):
+ # type: (Values, List[str]) -> int
+ if options.use_user_site and options.target_dir is not None:
+ raise CommandError("Can not combine '--user' and '--target'")
+
cmdoptions.check_install_build_global(options)
upgrade_strategy = "to-satisfy-only"
if options.upgrade:
upgrade_strategy = options.upgrade_strategy
- if options.build_dir:
- options.build_dir = os.path.abspath(options.build_dir)
-
cmdoptions.check_dist_restriction(options, check_target=True)
- options.src_dir = os.path.abspath(options.src_dir)
install_options = options.install_options or []
- if options.use_user_site:
- if options.prefix_path:
- raise CommandError(
- "Can not combine '--user' and '--prefix' as they imply "
- "different installation locations"
- )
- if virtualenv_no_global():
- raise InstallationError(
- "Can not perform a '--user' install. User site-packages "
- "are not visible in this virtualenv."
- )
- install_options.append('--user')
- install_options.append('--prefix=')
- target_temp_dir = TempDirectory(kind="target")
+ logger.debug("Using %s", get_pip_version())
+ options.use_user_site = decide_user_install(
+ options.use_user_site,
+ prefix_path=options.prefix_path,
+ target_dir=options.target_dir,
+ root_path=options.root_path,
+ isolated_mode=options.isolated_mode,
+ )
+
+ target_temp_dir = None # type: Optional[TempDirectory]
+ target_temp_dir_path = None # type: Optional[str]
if options.target_dir:
options.ignore_installed = True
options.target_dir = os.path.abspath(options.target_dir)
@@ -278,273 +263,457 @@ class InstallCommand(RequirementCommand):
)
# Create a target directory for using with the target option
- target_temp_dir.create()
- install_options.append('--home=' + target_temp_dir.path)
+ target_temp_dir = TempDirectory(kind="target")
+ target_temp_dir_path = target_temp_dir.path
+ self.enter_context(target_temp_dir)
global_options = options.global_options or []
- with self._build_session(options) as session:
- target_python = make_target_python(options)
- finder = self._build_package_finder(
- options=options,
- session=session,
- target_python=target_python,
- ignore_requires_python=options.ignore_requires_python,
+ session = self.get_default_session(options)
+
+ target_python = make_target_python(options)
+ finder = self._build_package_finder(
+ options=options,
+ session=session,
+ target_python=target_python,
+ ignore_requires_python=options.ignore_requires_python,
+ )
+ build_delete = (not (options.no_clean or options.build_dir))
+ wheel_cache = WheelCache(options.cache_dir, options.format_control)
+
+ req_tracker = self.enter_context(get_requirement_tracker())
+
+ directory = TempDirectory(
+ options.build_dir,
+ delete=build_delete,
+ kind="install",
+ globally_managed=True,
+ )
+
+ try:
+ reqs = self.get_requirements(args, options, finder, session)
+
+ reject_location_related_install_options(
+ reqs, options.install_options
)
- build_delete = (not (options.no_clean or options.build_dir))
- wheel_cache = WheelCache(options.cache_dir, options.format_control)
- if options.cache_dir and not check_path_owner(options.cache_dir):
- logger.warning(
- "The directory '%s' or its parent directory is not owned "
- "by the current user and caching wheels has been "
- "disabled. check the permissions and owner of that "
- "directory. If executing pip with sudo, you may want "
- "sudo's -H flag.",
- options.cache_dir,
+ preparer = self.make_requirement_preparer(
+ temp_build_dir=directory,
+ options=options,
+ req_tracker=req_tracker,
+ session=session,
+ finder=finder,
+ use_user_site=options.use_user_site,
+ )
+ resolver = self.make_resolver(
+ preparer=preparer,
+ finder=finder,
+ options=options,
+ wheel_cache=wheel_cache,
+ use_user_site=options.use_user_site,
+ ignore_installed=options.ignore_installed,
+ ignore_requires_python=options.ignore_requires_python,
+ force_reinstall=options.force_reinstall,
+ upgrade_strategy=upgrade_strategy,
+ use_pep517=options.use_pep517,
+ )
+
+ self.trace_basic_info(finder)
+
+ requirement_set = resolver.resolve(
+ reqs, check_supported_wheels=not options.target_dir
+ )
+
+ try:
+ pip_req = requirement_set.get_requirement("pip")
+ except KeyError:
+ modifying_pip = False
+ else:
+ # If we're not replacing an already installed pip,
+ # we're not modifying it.
+ modifying_pip = pip_req.satisfied_by is None
+ protect_pip_from_modification_on_windows(
+ modifying_pip=modifying_pip
+ )
+
+ check_binary_allowed = get_check_binary_allowed(
+ finder.format_control
+ )
+
+ reqs_to_build = [
+ r for r in requirement_set.requirements.values()
+ if should_build_for_install_command(
+ r, check_binary_allowed
)
- options.cache_dir = None
+ ]
- with RequirementTracker() as req_tracker, TempDirectory(
- options.build_dir, delete=build_delete, kind="install"
- ) as directory:
- requirement_set = RequirementSet(
- require_hashes=options.require_hashes,
- check_supported_wheels=not options.target_dir,
+ _, build_failures = build(
+ reqs_to_build,
+ wheel_cache=wheel_cache,
+ build_options=[],
+ global_options=[],
+ )
+
+ # If we're using PEP 517, we cannot do a direct install
+ # so we fail here.
+ pep517_build_failure_names = [
+ r.name # type: ignore
+ for r in build_failures if r.use_pep517
+ ] # type: List[str]
+ if pep517_build_failure_names:
+ raise InstallationError(
+ "Could not build wheels for {} which use"
+ " PEP 517 and cannot be installed directly".format(
+ ", ".join(pep517_build_failure_names)
+ )
)
+ # For now, we just warn about failures building legacy
+ # requirements, as we'll fall through to a direct
+ # install for those.
+ for r in build_failures:
+ if not r.use_pep517:
+ r.legacy_install_reason = 8368
+
+ to_install = resolver.get_installation_order(
+ requirement_set
+ )
+
+ # Check for conflicts in the package set we're installing.
+ conflicts = None # type: Optional[ConflictDetails]
+ should_warn_about_conflicts = (
+ not options.ignore_dependencies and
+ options.warn_about_conflicts
+ )
+ if should_warn_about_conflicts:
+ conflicts = self._determine_conflicts(to_install)
+
+ # Don't warn about script install locations if
+ # --target has been specified
+ warn_script_location = options.warn_script_location
+ if options.target_dir:
+ warn_script_location = False
+
+ installed = install_given_reqs(
+ to_install,
+ install_options,
+ global_options,
+ root=options.root_path,
+ home=target_temp_dir_path,
+ prefix=options.prefix_path,
+ warn_script_location=warn_script_location,
+ use_user_site=options.use_user_site,
+ pycompile=options.compile,
+ )
+
+ lib_locations = get_lib_location_guesses(
+ user=options.use_user_site,
+ home=target_temp_dir_path,
+ root=options.root_path,
+ prefix=options.prefix_path,
+ isolated=options.isolated_mode,
+ )
+ working_set = pkg_resources.WorkingSet(lib_locations)
+
+ installed.sort(key=operator.attrgetter('name'))
+ items = []
+ for result in installed:
+ item = result.name
try:
- self.populate_requirement_set(
- requirement_set, args, options, finder, session,
- self.name, wheel_cache
- )
- preparer = RequirementPreparer(
- build_dir=directory.path,
- src_dir=options.src_dir,
- download_dir=None,
- wheel_download_dir=None,
- progress_bar=options.progress_bar,
- build_isolation=options.build_isolation,
- req_tracker=req_tracker,
+ installed_version = get_installed_version(
+ result.name, working_set=working_set
)
+ if installed_version:
+ item += '-' + installed_version
+ except Exception:
+ pass
+ items.append(item)
- resolver = Resolver(
- preparer=preparer,
- finder=finder,
- session=session,
- wheel_cache=wheel_cache,
- use_user_site=options.use_user_site,
- upgrade_strategy=upgrade_strategy,
- force_reinstall=options.force_reinstall,
- ignore_dependencies=options.ignore_dependencies,
- ignore_requires_python=options.ignore_requires_python,
- ignore_installed=options.ignore_installed,
- isolated=options.isolated_mode,
- use_pep517=options.use_pep517
- )
- resolver.resolve(requirement_set)
+ if conflicts is not None:
+ self._warn_about_conflicts(
+ conflicts,
+ new_resolver='2020-resolver' in options.features_enabled,
+ )
- protect_pip_from_modification_on_windows(
- modifying_pip=requirement_set.has_requirement("pip")
- )
+ installed_desc = ' '.join(items)
+ if installed_desc:
+ write_output(
+ 'Successfully installed %s', installed_desc,
+ )
+ except EnvironmentError as error:
+ show_traceback = (self.verbosity >= 1)
- # Consider legacy and PEP517-using requirements separately
- legacy_requirements = []
- pep517_requirements = []
- for req in requirement_set.requirements.values():
- if req.use_pep517:
- pep517_requirements.append(req)
- else:
- legacy_requirements.append(req)
+ message = create_env_error_message(
+ error, show_traceback, options.use_user_site,
+ )
+ logger.error(message, exc_info=show_traceback) # noqa
- wheel_builder = WheelBuilder(
- finder, preparer, wheel_cache,
- build_options=[], global_options=[],
- )
-
- build_failures = build_wheels(
- builder=wheel_builder,
- pep517_requirements=pep517_requirements,
- legacy_requirements=legacy_requirements,
- session=session,
- )
-
- # If we're using PEP 517, we cannot do a direct install
- # so we fail here.
- if build_failures:
- raise InstallationError(
- "Could not build wheels for {} which use"
- " PEP 517 and cannot be installed directly".format(
- ", ".join(r.name for r in build_failures)))
-
- to_install = resolver.get_installation_order(
- requirement_set
- )
-
- # Consistency Checking of the package set we're installing.
- should_warn_about_conflicts = (
- not options.ignore_dependencies and
- options.warn_about_conflicts
- )
- if should_warn_about_conflicts:
- self._warn_about_conflicts(to_install)
-
- # Don't warn about script install locations if
- # --target has been specified
- warn_script_location = options.warn_script_location
- if options.target_dir:
- warn_script_location = False
-
- installed = install_given_reqs(
- to_install,
- install_options,
- global_options,
- root=options.root_path,
- home=target_temp_dir.path,
- prefix=options.prefix_path,
- pycompile=options.compile,
- warn_script_location=warn_script_location,
- use_user_site=options.use_user_site,
- )
-
- lib_locations = get_lib_location_guesses(
- user=options.use_user_site,
- home=target_temp_dir.path,
- root=options.root_path,
- prefix=options.prefix_path,
- isolated=options.isolated_mode,
- )
- working_set = pkg_resources.WorkingSet(lib_locations)
-
- reqs = sorted(installed, key=operator.attrgetter('name'))
- items = []
- for req in reqs:
- item = req.name
- try:
- installed_version = get_installed_version(
- req.name, working_set=working_set
- )
- if installed_version:
- item += '-' + installed_version
- except Exception:
- pass
- items.append(item)
- installed = ' '.join(items)
- if installed:
- logger.info('Successfully installed %s', installed)
- except EnvironmentError as error:
- show_traceback = (self.verbosity >= 1)
-
- message = create_env_error_message(
- error, show_traceback, options.use_user_site,
- )
- logger.error(message, exc_info=show_traceback)
-
- return ERROR
- except PreviousBuildDirError:
- options.no_clean = True
- raise
- finally:
- # Clean up
- if not options.no_clean:
- requirement_set.cleanup_files()
- wheel_cache.cleanup()
+ return ERROR
if options.target_dir:
+ assert target_temp_dir
self._handle_target_dir(
options.target_dir, target_temp_dir, options.upgrade
)
- return requirement_set
+
+ return SUCCESS
def _handle_target_dir(self, target_dir, target_temp_dir, upgrade):
+ # type: (str, TempDirectory, bool) -> None
ensure_dir(target_dir)
# Checking both purelib and platlib directories for installed
# packages to be moved to target directory
lib_dir_list = []
- with target_temp_dir:
- # Checking both purelib and platlib directories for installed
- # packages to be moved to target directory
- scheme = distutils_scheme('', home=target_temp_dir.path)
- purelib_dir = scheme['purelib']
- platlib_dir = scheme['platlib']
- data_dir = scheme['data']
+ # Checking both purelib and platlib directories for installed
+ # packages to be moved to target directory
+ scheme = distutils_scheme('', home=target_temp_dir.path)
+ purelib_dir = scheme['purelib']
+ platlib_dir = scheme['platlib']
+ data_dir = scheme['data']
- if os.path.exists(purelib_dir):
- lib_dir_list.append(purelib_dir)
- if os.path.exists(platlib_dir) and platlib_dir != purelib_dir:
- lib_dir_list.append(platlib_dir)
- if os.path.exists(data_dir):
- lib_dir_list.append(data_dir)
+ if os.path.exists(purelib_dir):
+ lib_dir_list.append(purelib_dir)
+ if os.path.exists(platlib_dir) and platlib_dir != purelib_dir:
+ lib_dir_list.append(platlib_dir)
+ if os.path.exists(data_dir):
+ lib_dir_list.append(data_dir)
- for lib_dir in lib_dir_list:
- for item in os.listdir(lib_dir):
- if lib_dir == data_dir:
- ddir = os.path.join(data_dir, item)
- if any(s.startswith(ddir) for s in lib_dir_list[:-1]):
- continue
- target_item_dir = os.path.join(target_dir, item)
- if os.path.exists(target_item_dir):
- if not upgrade:
- logger.warning(
- 'Target directory %s already exists. Specify '
- '--upgrade to force replacement.',
- target_item_dir
- )
- continue
- if os.path.islink(target_item_dir):
- logger.warning(
- 'Target directory %s already exists and is '
- 'a link. Pip will not automatically replace '
- 'links, please remove if replacement is '
- 'desired.',
- target_item_dir
- )
- continue
- if os.path.isdir(target_item_dir):
- shutil.rmtree(target_item_dir)
- else:
- os.remove(target_item_dir)
+ for lib_dir in lib_dir_list:
+ for item in os.listdir(lib_dir):
+ if lib_dir == data_dir:
+ ddir = os.path.join(data_dir, item)
+ if any(s.startswith(ddir) for s in lib_dir_list[:-1]):
+ continue
+ target_item_dir = os.path.join(target_dir, item)
+ if os.path.exists(target_item_dir):
+ if not upgrade:
+ logger.warning(
+ 'Target directory %s already exists. Specify '
+ '--upgrade to force replacement.',
+ target_item_dir
+ )
+ continue
+ if os.path.islink(target_item_dir):
+ logger.warning(
+ 'Target directory %s already exists and is '
+ 'a link. pip will not automatically replace '
+ 'links, please remove if replacement is '
+ 'desired.',
+ target_item_dir
+ )
+ continue
+ if os.path.isdir(target_item_dir):
+ shutil.rmtree(target_item_dir)
+ else:
+ os.remove(target_item_dir)
- shutil.move(
- os.path.join(lib_dir, item),
- target_item_dir
- )
+ shutil.move(
+ os.path.join(lib_dir, item),
+ target_item_dir
+ )
- def _warn_about_conflicts(self, to_install):
+ def _determine_conflicts(self, to_install):
+ # type: (List[InstallRequirement]) -> Optional[ConflictDetails]
try:
- package_set, _dep_info = check_install_conflicts(to_install)
+ return check_install_conflicts(to_install)
except Exception:
- logger.error("Error checking for conflicts.", exc_info=True)
- return
- missing, conflicting = _dep_info
+ logger.exception(
+ "Error while checking for conflicts. Please file an issue on "
+ "pip's issue tracker: https://github.com/pypa/pip/issues/new"
+ )
+ return None
- # NOTE: There is some duplication here from pip check
+ def _warn_about_conflicts(self, conflict_details, new_resolver):
+ # type: (ConflictDetails, bool) -> None
+ package_set, (missing, conflicting) = conflict_details
+ if not missing and not conflicting:
+ return
+
+ parts = [] # type: List[str]
+ if not new_resolver:
+ parts.append(
+ "After October 2020 you may experience errors when installing "
+ "or updating packages. This is because pip will change the "
+ "way that it resolves dependency conflicts.\n"
+ )
+ parts.append(
+ "We recommend you use --use-feature=2020-resolver to test "
+ "your packages with the new resolver before it becomes the "
+ "default.\n"
+ )
+ elif not today_is_later_than(year=2020, month=7, day=31):
+ # NOTE: trailing newlines here are intentional
+ parts.append(
+ "Pip will install or upgrade your package(s) and its "
+ "dependencies without taking into account other packages you "
+ "already have installed. This may cause an uncaught "
+ "dependency conflict.\n"
+ )
+ form_link = "https://forms.gle/cWKMoDs8sUVE29hz9"
+ parts.append(
+ "If you would like pip to take your other packages into "
+ "account, please tell us here: {}\n".format(form_link)
+ )
+
+ # NOTE: There is some duplication here, with commands/check.py
for project_name in missing:
version = package_set[project_name][0]
for dependency in missing[project_name]:
- logger.critical(
- "%s %s requires %s, which is not installed.",
- project_name, version, dependency[1],
+ message = (
+ "{name} {version} requires {requirement}, "
+ "which is not installed."
+ ).format(
+ name=project_name,
+ version=version,
+ requirement=dependency[1],
)
+ parts.append(message)
for project_name in conflicting:
version = package_set[project_name][0]
for dep_name, dep_version, req in conflicting[project_name]:
- logger.critical(
- "%s %s has requirement %s, but you'll have %s %s which is "
- "incompatible.",
- project_name, version, req, dep_name, dep_version,
+ message = (
+ "{name} {version} requires {requirement}, but you'll have "
+ "{dep_name} {dep_version} which is incompatible."
+ ).format(
+ name=project_name,
+ version=version,
+ requirement=req,
+ dep_name=dep_name,
+ dep_version=dep_version,
)
+ parts.append(message)
+
+ logger.critical("\n".join(parts))
-def get_lib_location_guesses(*args, **kwargs):
- scheme = distutils_scheme('', *args, **kwargs)
+def get_lib_location_guesses(
+ user=False, # type: bool
+ home=None, # type: Optional[str]
+ root=None, # type: Optional[str]
+ isolated=False, # type: bool
+ prefix=None # type: Optional[str]
+):
+ # type:(...) -> List[str]
+ scheme = distutils_scheme('', user=user, home=home, root=root,
+ isolated=isolated, prefix=prefix)
return [scheme['purelib'], scheme['platlib']]
+def site_packages_writable(root, isolated):
+ # type: (Optional[str], bool) -> bool
+ return all(
+ test_writable_dir(d) for d in set(
+ get_lib_location_guesses(root=root, isolated=isolated))
+ )
+
+
+def decide_user_install(
+ use_user_site, # type: Optional[bool]
+ prefix_path=None, # type: Optional[str]
+ target_dir=None, # type: Optional[str]
+ root_path=None, # type: Optional[str]
+ isolated_mode=False, # type: bool
+):
+ # type: (...) -> bool
+ """Determine whether to do a user install based on the input options.
+
+ If use_user_site is False, no additional checks are done.
+ If use_user_site is True, it is checked for compatibility with other
+ options.
+ If use_user_site is None, the default behaviour depends on the environment,
+ which is provided by the other arguments.
+ """
+ # In some cases (config from tox), use_user_site can be set to an integer
+ # rather than a bool, which 'use_user_site is False' wouldn't catch.
+ if (use_user_site is not None) and (not use_user_site):
+ logger.debug("Non-user install by explicit request")
+ return False
+
+ if use_user_site:
+ if prefix_path:
+ raise CommandError(
+ "Can not combine '--user' and '--prefix' as they imply "
+ "different installation locations"
+ )
+ if virtualenv_no_global():
+ raise InstallationError(
+ "Can not perform a '--user' install. User site-packages "
+ "are not visible in this virtualenv."
+ )
+ logger.debug("User install by explicit request")
+ return True
+
+ # If we are here, user installs have not been explicitly requested/avoided
+ assert use_user_site is None
+
+ # user install incompatible with --prefix/--target
+ if prefix_path or target_dir:
+ logger.debug("Non-user install due to --prefix or --target option")
+ return False
+
+ # If user installs are not enabled, choose a non-user install
+ if not site.ENABLE_USER_SITE:
+ logger.debug("Non-user install because user site-packages disabled")
+ return False
+
+ # If we have permission for a non-user install, do that,
+ # otherwise do a user install.
+ if site_packages_writable(root=root_path, isolated=isolated_mode):
+ logger.debug("Non-user install because site-packages writeable")
+ return False
+
+ logger.info("Defaulting to user installation because normal site-packages "
+ "is not writeable")
+ return True
+
+
+def reject_location_related_install_options(requirements, options):
+ # type: (List[InstallRequirement], Optional[List[str]]) -> None
+ """If any location-changing --install-option arguments were passed for
+ requirements or on the command-line, then show a deprecation warning.
+ """
+ def format_options(option_names):
+ # type: (Iterable[str]) -> List[str]
+ return ["--{}".format(name.replace("_", "-")) for name in option_names]
+
+ offenders = []
+
+ for requirement in requirements:
+ install_options = requirement.install_options
+ location_options = parse_distutils_args(install_options)
+ if location_options:
+ offenders.append(
+ "{!r} from {}".format(
+ format_options(location_options.keys()), requirement
+ )
+ )
+
+ if options:
+ location_options = parse_distutils_args(options)
+ if location_options:
+ offenders.append(
+ "{!r} from command line".format(
+ format_options(location_options.keys())
+ )
+ )
+
+ if not offenders:
+ return
+
+ raise CommandError(
+ "Location-changing options found in --install-option: {}."
+ " This is unsupported, use pip-level options like --user,"
+ " --prefix, --root, and --target instead.".format(
+ "; ".join(offenders)
+ )
+ )
+
+
def create_env_error_message(error, show_traceback, using_user_site):
+ # type: (EnvironmentError, bool, bool) -> str
"""Format an error message for an EnvironmentError
It may occur anytime during the execution of the install command.
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/list.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/list.py
index cf71b13..20e9bff 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/commands/list.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/list.py
@@ -4,54 +4,63 @@ import json
import logging
from pip._vendor import six
-from pip._vendor.six.moves import zip_longest
from pip._internal.cli import cmdoptions
-from pip._internal.cli.base_command import Command
-from pip._internal.cli.cmdoptions import make_search_scope
+from pip._internal.cli.req_command import IndexGroupCommand
+from pip._internal.cli.status_codes import SUCCESS
from pip._internal.exceptions import CommandError
-from pip._internal.index import PackageFinder
+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.utils.misc import (
- dist_is_editable, get_installed_distributions,
+ dist_is_editable,
+ get_installed_distributions,
+ tabulate,
+ write_output,
)
from pip._internal.utils.packaging import get_installer
+from pip._internal.utils.parallel import map_multithread
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+
+if MYPY_CHECK_RUNNING:
+ from optparse import Values
+ from typing import List, Set, Tuple, Iterator
+
+ from pip._internal.network.session import PipSession
+ from pip._vendor.pkg_resources import Distribution
logger = logging.getLogger(__name__)
-class ListCommand(Command):
+class ListCommand(IndexGroupCommand):
"""
List installed packages, including editables.
Packages are listed in a case-insensitive sorted order.
"""
- name = 'list'
+
+ ignore_require_venv = True
usage = """
%prog [options]"""
- summary = 'List installed packages.'
- def __init__(self, *args, **kw):
- super(ListCommand, self).__init__(*args, **kw)
-
- cmd_opts = self.cmd_opts
-
- cmd_opts.add_option(
+ def add_options(self):
+ # type: () -> None
+ self.cmd_opts.add_option(
'-o', '--outdated',
action='store_true',
default=False,
help='List outdated packages')
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'-u', '--uptodate',
action='store_true',
default=False,
help='List uptodate packages')
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'-e', '--editable',
action='store_true',
default=False,
help='List editable projects.')
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'-l', '--local',
action='store_true',
default=False,
@@ -64,8 +73,8 @@ class ListCommand(Command):
action='store_true',
default=False,
help='Only output packages installed in user-site.')
- cmd_opts.add_option(cmdoptions.list_path())
- cmd_opts.add_option(
+ self.cmd_opts.add_option(cmdoptions.list_path())
+ self.cmd_opts.add_option(
'--pre',
action='store_true',
default=False,
@@ -73,7 +82,7 @@ class ListCommand(Command):
"pip only finds stable versions."),
)
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'--format',
action='store',
dest='list_format',
@@ -83,7 +92,7 @@ class ListCommand(Command):
"or json",
)
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'--not-required',
action='store_true',
dest='not_required',
@@ -91,13 +100,13 @@ class ListCommand(Command):
"installed packages.",
)
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'--exclude-editable',
action='store_false',
dest='include_editable',
help='Exclude editable package from output.',
)
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'--include-editable',
action='store_true',
dest='include_editable',
@@ -109,13 +118,14 @@ class ListCommand(Command):
)
self.parser.insert_option_group(0, index_opts)
- self.parser.insert_option_group(0, cmd_opts)
+ self.parser.insert_option_group(0, self.cmd_opts)
def _build_package_finder(self, options, session):
+ # type: (Values, PipSession) -> PackageFinder
"""
Create a package finder appropriate to this list command.
"""
- search_scope = make_search_scope(options)
+ link_collector = LinkCollector.create(session, options=options)
# Pass allow_yanked=False to ignore yanked versions.
selection_prefs = SelectionPreferences(
@@ -124,13 +134,12 @@ class ListCommand(Command):
)
return PackageFinder.create(
- search_scope=search_scope,
+ link_collector=link_collector,
selection_prefs=selection_prefs,
- trusted_hosts=options.trusted_hosts,
- session=session,
)
def run(self, options, args):
+ # type: (Values, List[str]) -> int
if options.outdated and options.uptodate:
raise CommandError(
"Options --outdated and --uptodate cannot be combined.")
@@ -158,30 +167,40 @@ class ListCommand(Command):
packages = self.get_uptodate(packages, options)
self.output_package_listing(packages, options)
+ return SUCCESS
def get_outdated(self, packages, options):
+ # type: (List[Distribution], Values) -> List[Distribution]
return [
dist for dist in self.iter_packages_latest_infos(packages, options)
if dist.latest_version > dist.parsed_version
]
def get_uptodate(self, packages, options):
+ # type: (List[Distribution], Values) -> List[Distribution]
return [
dist for dist in self.iter_packages_latest_infos(packages, options)
if dist.latest_version == dist.parsed_version
]
def get_not_required(self, packages, options):
- dep_keys = set()
+ # type: (List[Distribution], Values) -> List[Distribution]
+ dep_keys = set() # type: Set[Distribution]
for dist in packages:
dep_keys.update(requirement.key for requirement in dist.requires())
- return {pkg for pkg in packages if pkg.key not in dep_keys}
+
+ # Create a set to remove duplicate packages, and cast it to a list
+ # to keep the return type consistent with get_outdated and
+ # get_uptodate
+ return list({pkg for pkg in packages if pkg.key not in dep_keys})
def iter_packages_latest_infos(self, packages, options):
+ # type: (List[Distribution], Values) -> Iterator[Distribution]
with self._build_session(options) as session:
finder = self._build_package_finder(options, session)
- for dist in packages:
+ def latest_info(dist):
+ # type: (Distribution) -> Distribution
typ = 'unknown'
all_candidates = finder.find_all_candidates(dist.key)
if not options.pre:
@@ -192,9 +211,9 @@ class ListCommand(Command):
evaluator = finder.make_candidate_evaluator(
project_name=dist.project_name,
)
- best_candidate = evaluator.get_best_candidate(all_candidates)
+ best_candidate = evaluator.sort_best_candidate(all_candidates)
if best_candidate is None:
- continue
+ return None
remote_version = best_candidate.version
if best_candidate.link.is_wheel:
@@ -204,9 +223,14 @@ class ListCommand(Command):
# This is dirty but makes the rest of the code much cleaner
dist.latest_version = remote_version
dist.latest_filetype = typ
- yield dist
+ return dist
+
+ for dist in map_multithread(latest_info, packages):
+ if dist is not None:
+ yield dist
def output_package_listing(self, packages, options):
+ # type: (List[Distribution], Values) -> None
packages = sorted(
packages,
key=lambda dist: dist.project_name.lower(),
@@ -217,14 +241,15 @@ class ListCommand(Command):
elif options.list_format == 'freeze':
for dist in packages:
if options.verbose >= 1:
- logger.info("%s==%s (%s)", dist.project_name,
- dist.version, dist.location)
+ write_output("%s==%s (%s)", dist.project_name,
+ dist.version, dist.location)
else:
- logger.info("%s==%s", dist.project_name, dist.version)
+ write_output("%s==%s", dist.project_name, dist.version)
elif options.list_format == 'json':
- logger.info(format_for_json(packages, options))
+ write_output(format_for_json(packages, options))
def output_package_listing_columns(self, data, header):
+ # type: (List[List[str]], List[str]) -> None
# insert the header first: we need to know the size of column names
if len(data) > 0:
data.insert(0, header)
@@ -236,28 +261,11 @@ class ListCommand(Command):
pkg_strings.insert(1, " ".join(map(lambda x: '-' * x, sizes)))
for val in pkg_strings:
- logger.info(val)
-
-
-def tabulate(vals):
- # From pfmoore on GitHub:
- # https://github.com/pypa/pip/issues/3651#issuecomment-216932564
- assert len(vals) > 0
-
- sizes = [0] * max(len(x) for x in vals)
- for row in vals:
- sizes = [max(s, len(str(c))) for s, c in zip_longest(sizes, row)]
-
- result = []
- for row in vals:
- display = " ".join([str(c).ljust(s) if c is not None else ''
- for s, c in zip_longest(sizes, row)])
- result.append(display)
-
- return result, sizes
+ write_output(val)
def format_for_columns(pkgs, options):
+ # type: (List[Distribution], Values) -> Tuple[List[List[str]], List[str]]
"""
Convert the package data into something usable
by output_package_listing_columns.
@@ -295,6 +303,7 @@ def format_for_columns(pkgs, options):
def format_for_json(packages, options):
+ # type: (List[Distribution], Values) -> str
data = []
for dist in packages:
info = {
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/search.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/search.py
index 5802711..ff09472 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/commands/search.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/search.py
@@ -12,26 +12,37 @@ from pip._vendor.packaging.version import parse as parse_version
from pip._vendor.six.moves import xmlrpc_client # type: ignore
from pip._internal.cli.base_command import Command
+from pip._internal.cli.req_command import SessionCommandMixin
from pip._internal.cli.status_codes import NO_MATCHES_FOUND, SUCCESS
-from pip._internal.download import PipXmlrpcTransport
from pip._internal.exceptions import CommandError
from pip._internal.models.index import PyPI
+from pip._internal.network.xmlrpc import PipXmlrpcTransport
from pip._internal.utils.compat import get_terminal_size
from pip._internal.utils.logging import indent_log
+from pip._internal.utils.misc import get_distribution, write_output
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+
+if MYPY_CHECK_RUNNING:
+ from optparse import Values
+ from typing import List, Dict, Optional
+ from typing_extensions import TypedDict
+ TransformedHit = TypedDict(
+ 'TransformedHit',
+ {'name': str, 'summary': str, 'versions': List[str]},
+ )
logger = logging.getLogger(__name__)
-class SearchCommand(Command):
+class SearchCommand(Command, SessionCommandMixin):
"""Search for PyPI packages whose name or summary contains ."""
- name = 'search'
+
usage = """
%prog [options] """
- summary = 'Search PyPI for packages.'
ignore_require_venv = True
- def __init__(self, *args, **kw):
- super(SearchCommand, self).__init__(*args, **kw)
+ def add_options(self):
+ # type: () -> None
self.cmd_opts.add_option(
'-i', '--index',
dest='index',
@@ -42,6 +53,7 @@ class SearchCommand(Command):
self.parser.insert_option_group(0, self.cmd_opts)
def run(self, options, args):
+ # type: (Values, List[str]) -> int
if not args:
raise CommandError('Missing required argument (search query).')
query = args
@@ -58,21 +70,25 @@ class SearchCommand(Command):
return NO_MATCHES_FOUND
def search(self, query, options):
+ # type: (List[str], Values) -> List[Dict[str, str]]
index_url = options.index
- with self._build_session(options) as session:
- transport = PipXmlrpcTransport(index_url, session)
- pypi = xmlrpc_client.ServerProxy(index_url, transport)
- hits = pypi.search({'name': query, 'summary': query}, 'or')
- return hits
+
+ session = self.get_default_session(options)
+
+ transport = PipXmlrpcTransport(index_url, session)
+ pypi = xmlrpc_client.ServerProxy(index_url, transport)
+ hits = pypi.search({'name': query, 'summary': query}, 'or')
+ return hits
def transform_hits(hits):
+ # type: (List[Dict[str, str]]) -> List[TransformedHit]
"""
The list from pypi is really a list of versions. We want a list of
packages with the list of versions stored inline. This converts the
list from pypi into one we can use.
"""
- packages = OrderedDict()
+ packages = OrderedDict() # type: OrderedDict[str, TransformedHit]
for hit in hits:
name = hit['name']
summary = hit['summary']
@@ -95,6 +111,7 @@ def transform_hits(hits):
def print_results(hits, name_column_width=None, terminal_width=None):
+ # type: (List[TransformedHit], Optional[int], Optional[int]) -> None
if not hits:
return
if name_column_width is None:
@@ -112,28 +129,32 @@ def print_results(hits, name_column_width=None, terminal_width=None):
target_width = terminal_width - name_column_width - 5
if target_width > 10:
# wrap and indent summary to fit terminal
- summary = textwrap.wrap(summary, target_width)
- summary = ('\n' + ' ' * (name_column_width + 3)).join(summary)
+ summary_lines = textwrap.wrap(summary, target_width)
+ summary = ('\n' + ' ' * (name_column_width + 3)).join(
+ summary_lines)
- line = '%-*s - %s' % (name_column_width,
- '%s (%s)' % (name, latest), summary)
+ line = '{name_latest:{name_column_width}} - {summary}'.format(
+ name_latest='{name} ({latest})'.format(**locals()),
+ **locals())
try:
- logger.info(line)
+ write_output(line)
if name in installed_packages:
- dist = pkg_resources.get_distribution(name)
+ dist = get_distribution(name)
+ assert dist is not None
with indent_log():
if dist.version == latest:
- logger.info('INSTALLED: %s (latest)', dist.version)
+ write_output('INSTALLED: %s (latest)', dist.version)
else:
- logger.info('INSTALLED: %s', dist.version)
+ write_output('INSTALLED: %s', dist.version)
if parse_version(latest).pre:
- logger.info('LATEST: %s (pre-release; install'
- ' with "pip install --pre")', latest)
+ write_output('LATEST: %s (pre-release; install'
+ ' with "pip install --pre")', latest)
else:
- logger.info('LATEST: %s', latest)
+ write_output('LATEST: %s', latest)
except UnicodeEncodeError:
pass
def highest_version(versions):
+ # type: (List[str]) -> str
return max(versions, key=parse_version)
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/show.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/show.py
index a18a902..3892c59 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/commands/show.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/show.py
@@ -9,6 +9,12 @@ from pip._vendor.packaging.utils import canonicalize_name
from pip._internal.cli.base_command import Command
from pip._internal.cli.status_codes import ERROR, SUCCESS
+from pip._internal.utils.misc import write_output
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+
+if MYPY_CHECK_RUNNING:
+ from optparse import Values
+ from typing import List, Dict, Iterator
logger = logging.getLogger(__name__)
@@ -19,14 +25,13 @@ class ShowCommand(Command):
The output is in RFC-compliant mail header format.
"""
- name = 'show'
+
usage = """
%prog [options] ..."""
- summary = 'Show information about installed packages.'
ignore_require_venv = True
- def __init__(self, *args, **kw):
- super(ShowCommand, self).__init__(*args, **kw)
+ def add_options(self):
+ # type: () -> None
self.cmd_opts.add_option(
'-f', '--files',
dest='files',
@@ -37,6 +42,7 @@ class ShowCommand(Command):
self.parser.insert_option_group(0, self.cmd_opts)
def run(self, options, args):
+ # type: (Values, List[str]) -> int
if not args:
logger.warning('ERROR: Please provide a package name or names.')
return ERROR
@@ -50,6 +56,7 @@ class ShowCommand(Command):
def search_packages_info(query):
+ # type: (List[str]) -> Iterator[Dict[str, str]]
"""
Gather details from installed distributions. Print distribution name,
version, location, and installed files. Installed files requires a
@@ -61,6 +68,21 @@ def search_packages_info(query):
installed[canonicalize_name(p.project_name)] = p
query_names = [canonicalize_name(name) for name in query]
+ missing = sorted(
+ [name for name, pkg in zip(query, query_names) if pkg not in installed]
+ )
+ if missing:
+ logger.warning('Package(s) not found: %s', ', '.join(missing))
+
+ def get_requiring_packages(package_name):
+ # type: (str) -> List[str]
+ canonical_name = canonicalize_name(package_name)
+ return [
+ pkg.project_name for pkg in pkg_resources.working_set
+ if canonical_name in
+ [canonicalize_name(required.name) for required in
+ pkg.requires()]
+ ]
for dist in [installed[pkg] for pkg in query_names if pkg in installed]:
package = {
@@ -68,14 +90,15 @@ def search_packages_info(query):
'version': dist.version,
'location': dist.location,
'requires': [dep.project_name for dep in dist.requires()],
+ 'required_by': get_requiring_packages(dist.project_name)
}
file_list = None
- metadata = None
+ metadata = ''
if isinstance(dist, pkg_resources.DistInfoDistribution):
# RECORDs should be part of .dist-info metadatas
if dist.has_metadata('RECORD'):
lines = dist.get_metadata_lines('RECORD')
- paths = [l.split(',')[0] for l in lines]
+ paths = [line.split(',')[0] for line in lines]
paths = [os.path.join(dist.location, p) for p in paths]
file_list = [os.path.relpath(p, dist.location) for p in paths]
@@ -123,46 +146,41 @@ def search_packages_info(query):
def print_results(distributions, list_files=False, verbose=False):
+ # type: (Iterator[Dict[str, str]], bool, bool) -> bool
"""
- Print the informations from installed distributions found.
+ Print the information from installed distributions found.
"""
results_printed = False
for i, dist in enumerate(distributions):
results_printed = True
if i > 0:
- logger.info("---")
+ write_output("---")
- name = dist.get('name', '')
- required_by = [
- pkg.project_name for pkg in pkg_resources.working_set
- if name in [required.name for required in pkg.requires()]
- ]
-
- logger.info("Name: %s", name)
- logger.info("Version: %s", dist.get('version', ''))
- logger.info("Summary: %s", dist.get('summary', ''))
- logger.info("Home-page: %s", dist.get('home-page', ''))
- logger.info("Author: %s", dist.get('author', ''))
- logger.info("Author-email: %s", dist.get('author-email', ''))
- logger.info("License: %s", dist.get('license', ''))
- logger.info("Location: %s", dist.get('location', ''))
- logger.info("Requires: %s", ', '.join(dist.get('requires', [])))
- logger.info("Required-by: %s", ', '.join(required_by))
+ write_output("Name: %s", dist.get('name', ''))
+ write_output("Version: %s", dist.get('version', ''))
+ write_output("Summary: %s", dist.get('summary', ''))
+ write_output("Home-page: %s", dist.get('home-page', ''))
+ write_output("Author: %s", dist.get('author', ''))
+ write_output("Author-email: %s", dist.get('author-email', ''))
+ write_output("License: %s", dist.get('license', ''))
+ write_output("Location: %s", dist.get('location', ''))
+ write_output("Requires: %s", ', '.join(dist.get('requires', [])))
+ write_output("Required-by: %s", ', '.join(dist.get('required_by', [])))
if verbose:
- logger.info("Metadata-Version: %s",
- dist.get('metadata-version', ''))
- logger.info("Installer: %s", dist.get('installer', ''))
- logger.info("Classifiers:")
+ write_output("Metadata-Version: %s",
+ dist.get('metadata-version', ''))
+ write_output("Installer: %s", dist.get('installer', ''))
+ write_output("Classifiers:")
for classifier in dist.get('classifiers', []):
- logger.info(" %s", classifier)
- logger.info("Entry-points:")
+ write_output(" %s", classifier)
+ write_output("Entry-points:")
for entry in dist.get('entry_points', []):
- logger.info(" %s", entry.strip())
+ write_output(" %s", entry.strip())
if list_files:
- logger.info("Files:")
+ write_output("Files:")
for line in dist.get('files', []):
- logger.info(" %s", line.strip())
+ write_output(" %s", line.strip())
if "files" not in dist:
- logger.info("Cannot locate installed-files.txt")
+ write_output("Cannot locate installed-files.txt")
return results_printed
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/uninstall.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/uninstall.py
index 0cd6f54..3371fe4 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/commands/uninstall.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/uninstall.py
@@ -3,13 +3,23 @@ from __future__ import absolute_import
from pip._vendor.packaging.utils import canonicalize_name
from pip._internal.cli.base_command import Command
+from pip._internal.cli.req_command import SessionCommandMixin
+from pip._internal.cli.status_codes import SUCCESS
from pip._internal.exceptions import InstallationError
from pip._internal.req import parse_requirements
-from pip._internal.req.constructors import install_req_from_line
+from pip._internal.req.constructors import (
+ install_req_from_line,
+ install_req_from_parsed_requirement,
+)
from pip._internal.utils.misc import protect_pip_from_modification_on_windows
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+
+if MYPY_CHECK_RUNNING:
+ from optparse import Values
+ from typing import List
-class UninstallCommand(Command):
+class UninstallCommand(Command, SessionCommandMixin):
"""
Uninstall packages.
@@ -19,14 +29,13 @@ class UninstallCommand(Command):
leave behind no metadata to determine what files were installed.
- Script wrappers installed by ``python setup.py develop``.
"""
- name = 'uninstall'
+
usage = """
%prog [options] ...
%prog [options] -r ..."""
- summary = 'Uninstall packages.'
- def __init__(self, *args, **kw):
- super(UninstallCommand, self).__init__(*args, **kw)
+ def add_options(self):
+ # type: () -> None
self.cmd_opts.add_option(
'-r', '--requirement',
dest='requirements',
@@ -45,34 +54,42 @@ class UninstallCommand(Command):
self.parser.insert_option_group(0, self.cmd_opts)
def run(self, options, args):
- with self._build_session(options) as session:
- reqs_to_uninstall = {}
- for name in args:
- req = install_req_from_line(
- name, isolated=options.isolated_mode,
+ # type: (Values, List[str]) -> int
+ session = self.get_default_session(options)
+
+ reqs_to_uninstall = {}
+ for name in args:
+ req = install_req_from_line(
+ name, isolated=options.isolated_mode,
+ )
+ if req.name:
+ reqs_to_uninstall[canonicalize_name(req.name)] = req
+ for filename in options.requirements:
+ for parsed_req in parse_requirements(
+ filename,
+ options=options,
+ session=session):
+ req = install_req_from_parsed_requirement(
+ parsed_req,
+ isolated=options.isolated_mode
)
if req.name:
reqs_to_uninstall[canonicalize_name(req.name)] = req
- for filename in options.requirements:
- for req in parse_requirements(
- filename,
- options=options,
- session=session):
- if req.name:
- reqs_to_uninstall[canonicalize_name(req.name)] = req
- if not reqs_to_uninstall:
- raise InstallationError(
- 'You must give at least one requirement to %(name)s (see '
- '"pip help %(name)s")' % dict(name=self.name)
- )
-
- protect_pip_from_modification_on_windows(
- modifying_pip="pip" in reqs_to_uninstall
+ if not reqs_to_uninstall:
+ raise InstallationError(
+ 'You must give at least one requirement to {self.name} (see '
+ '"pip help {self.name}")'.format(**locals())
)
- for req in reqs_to_uninstall.values():
- uninstall_pathset = req.uninstall(
- auto_confirm=options.yes, verbose=self.verbosity > 0,
- )
- if uninstall_pathset:
- uninstall_pathset.commit()
+ protect_pip_from_modification_on_windows(
+ modifying_pip="pip" in reqs_to_uninstall
+ )
+
+ for req in reqs_to_uninstall.values():
+ uninstall_pathset = req.uninstall(
+ auto_confirm=options.yes, verbose=self.verbosity > 0,
+ )
+ if uninstall_pathset:
+ uninstall_pathset.commit()
+
+ return SUCCESS
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/commands/wheel.py b/venv/lib/python3.8/site-packages/pip/_internal/commands/wheel.py
index 97f3b14..0f71856 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/commands/wheel.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/commands/wheel.py
@@ -1,19 +1,26 @@
# -*- coding: utf-8 -*-
+
from __future__ import absolute_import
import logging
import os
+import shutil
from pip._internal.cache import WheelCache
from pip._internal.cli import cmdoptions
-from pip._internal.cli.base_command import RequirementCommand
-from pip._internal.exceptions import CommandError, PreviousBuildDirError
-from pip._internal.legacy_resolve import Resolver
-from pip._internal.operations.prepare import RequirementPreparer
-from pip._internal.req import RequirementSet
-from pip._internal.req.req_tracker import RequirementTracker
+from pip._internal.cli.req_command import RequirementCommand, with_cleanup
+from pip._internal.cli.status_codes import SUCCESS
+from pip._internal.exceptions import CommandError
+from pip._internal.req.req_tracker import get_requirement_tracker
+from pip._internal.utils.misc import ensure_dir, normalize_path
from pip._internal.utils.temp_dir import TempDirectory
-from pip._internal.wheel import WheelBuilder
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+from pip._internal.wheel_builder import build, should_build_for_wheel_command
+
+if MYPY_CHECK_RUNNING:
+ from optparse import Values
+ from typing import List
+
logger = logging.getLogger(__name__)
@@ -33,7 +40,6 @@ class WheelCommand(RequirementCommand):
"""
- name = 'wheel'
usage = """
%prog [options] ...
%prog [options] -r ...
@@ -41,14 +47,10 @@ class WheelCommand(RequirementCommand):
%prog [options] [-e] ...
%prog [options] ..."""
- summary = 'Build wheels from your requirements.'
+ def add_options(self):
+ # type: () -> None
- def __init__(self, *args, **kw):
- super(WheelCommand, self).__init__(*args, **kw)
-
- cmd_opts = self.cmd_opts
-
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'-w', '--wheel-dir',
dest='wheel_dir',
metavar='dir',
@@ -56,29 +58,29 @@ class WheelCommand(RequirementCommand):
help=("Build wheels into , where the default is the "
"current working directory."),
)
- cmd_opts.add_option(cmdoptions.no_binary())
- cmd_opts.add_option(cmdoptions.only_binary())
- cmd_opts.add_option(cmdoptions.prefer_binary())
- cmd_opts.add_option(
+ self.cmd_opts.add_option(cmdoptions.no_binary())
+ self.cmd_opts.add_option(cmdoptions.only_binary())
+ self.cmd_opts.add_option(cmdoptions.prefer_binary())
+ self.cmd_opts.add_option(
'--build-option',
dest='build_options',
metavar='options',
action='append',
help="Extra arguments to be supplied to 'setup.py bdist_wheel'.",
)
- cmd_opts.add_option(cmdoptions.no_build_isolation())
- cmd_opts.add_option(cmdoptions.use_pep517())
- cmd_opts.add_option(cmdoptions.no_use_pep517())
- cmd_opts.add_option(cmdoptions.constraints())
- cmd_opts.add_option(cmdoptions.editable())
- cmd_opts.add_option(cmdoptions.requirements())
- cmd_opts.add_option(cmdoptions.src())
- cmd_opts.add_option(cmdoptions.ignore_requires_python())
- cmd_opts.add_option(cmdoptions.no_deps())
- cmd_opts.add_option(cmdoptions.build_dir())
- cmd_opts.add_option(cmdoptions.progress_bar())
+ self.cmd_opts.add_option(cmdoptions.no_build_isolation())
+ self.cmd_opts.add_option(cmdoptions.use_pep517())
+ self.cmd_opts.add_option(cmdoptions.no_use_pep517())
+ self.cmd_opts.add_option(cmdoptions.constraints())
+ self.cmd_opts.add_option(cmdoptions.editable())
+ self.cmd_opts.add_option(cmdoptions.requirements())
+ self.cmd_opts.add_option(cmdoptions.src())
+ self.cmd_opts.add_option(cmdoptions.ignore_requires_python())
+ self.cmd_opts.add_option(cmdoptions.no_deps())
+ self.cmd_opts.add_option(cmdoptions.build_dir())
+ self.cmd_opts.add_option(cmdoptions.progress_bar())
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'--global-option',
dest='global_options',
action='append',
@@ -86,7 +88,7 @@ class WheelCommand(RequirementCommand):
help="Extra global options to be supplied to the setup.py "
"call before the 'bdist_wheel' command.")
- cmd_opts.add_option(
+ self.cmd_opts.add_option(
'--pre',
action='store_true',
default=False,
@@ -94,8 +96,7 @@ class WheelCommand(RequirementCommand):
"pip only finds stable versions."),
)
- cmd_opts.add_option(cmdoptions.no_clean())
- cmd_opts.add_option(cmdoptions.require_hashes())
+ self.cmd_opts.add_option(cmdoptions.require_hashes())
index_opts = cmdoptions.make_option_group(
cmdoptions.index_group,
@@ -103,79 +104,85 @@ class WheelCommand(RequirementCommand):
)
self.parser.insert_option_group(0, index_opts)
- self.parser.insert_option_group(0, cmd_opts)
+ self.parser.insert_option_group(0, self.cmd_opts)
+ @with_cleanup
def run(self, options, args):
+ # type: (Values, List[str]) -> int
cmdoptions.check_install_build_global(options)
- if options.build_dir:
- options.build_dir = os.path.abspath(options.build_dir)
+ session = self.get_default_session(options)
- options.src_dir = os.path.abspath(options.src_dir)
+ finder = self._build_package_finder(options, session)
+ build_delete = (not (options.no_clean or options.build_dir))
+ wheel_cache = WheelCache(options.cache_dir, options.format_control)
- with self._build_session(options) as session:
- finder = self._build_package_finder(options, session)
- build_delete = (not (options.no_clean or options.build_dir))
- wheel_cache = WheelCache(options.cache_dir, options.format_control)
+ options.wheel_dir = normalize_path(options.wheel_dir)
+ ensure_dir(options.wheel_dir)
- with RequirementTracker() as req_tracker, TempDirectory(
- options.build_dir, delete=build_delete, kind="wheel"
- ) as directory:
+ req_tracker = self.enter_context(get_requirement_tracker())
- requirement_set = RequirementSet(
- require_hashes=options.require_hashes,
+ directory = TempDirectory(
+ options.build_dir,
+ delete=build_delete,
+ kind="wheel",
+ globally_managed=True,
+ )
+
+ reqs = self.get_requirements(args, options, finder, session)
+
+ preparer = self.make_requirement_preparer(
+ temp_build_dir=directory,
+ options=options,
+ req_tracker=req_tracker,
+ session=session,
+ finder=finder,
+ wheel_download_dir=options.wheel_dir,
+ use_user_site=False,
+ )
+
+ resolver = self.make_resolver(
+ preparer=preparer,
+ finder=finder,
+ options=options,
+ wheel_cache=wheel_cache,
+ ignore_requires_python=options.ignore_requires_python,
+ use_pep517=options.use_pep517,
+ )
+
+ self.trace_basic_info(finder)
+
+ requirement_set = resolver.resolve(
+ reqs, check_supported_wheels=True
+ )
+
+ reqs_to_build = [
+ r for r in requirement_set.requirements.values()
+ if should_build_for_wheel_command(r)
+ ]
+
+ # build wheels
+ build_successes, build_failures = build(
+ reqs_to_build,
+ wheel_cache=wheel_cache,
+ build_options=options.build_options or [],
+ global_options=options.global_options or [],
+ )
+ for req in build_successes:
+ assert req.link and req.link.is_wheel
+ assert req.local_file_path
+ # copy from cache to target directory
+ try:
+ shutil.copy(req.local_file_path, options.wheel_dir)
+ except OSError as e:
+ logger.warning(
+ "Building wheel for %s failed: %s",
+ req.name, e,
)
+ build_failures.append(req)
+ if len(build_failures) != 0:
+ raise CommandError(
+ "Failed to build one or more wheels"
+ )
- try:
- self.populate_requirement_set(
- requirement_set, args, options, finder, session,
- self.name, wheel_cache
- )
-
- preparer = RequirementPreparer(
- build_dir=directory.path,
- src_dir=options.src_dir,
- download_dir=None,
- wheel_download_dir=options.wheel_dir,
- progress_bar=options.progress_bar,
- build_isolation=options.build_isolation,
- req_tracker=req_tracker,
- )
-
- resolver = Resolver(
- preparer=preparer,
- finder=finder,
- session=session,
- wheel_cache=wheel_cache,
- use_user_site=False,
- upgrade_strategy="to-satisfy-only",
- force_reinstall=False,
- ignore_dependencies=options.ignore_dependencies,
- ignore_requires_python=options.ignore_requires_python,
- ignore_installed=True,
- isolated=options.isolated_mode,
- use_pep517=options.use_pep517
- )
- resolver.resolve(requirement_set)
-
- # build wheels
- wb = WheelBuilder(
- finder, preparer, wheel_cache,
- build_options=options.build_options or [],
- global_options=options.global_options or [],
- no_clean=options.no_clean,
- )
- build_failures = wb.build(
- requirement_set.requirements.values(), session=session,
- )
- if len(build_failures) != 0:
- raise CommandError(
- "Failed to build one or more wheels"
- )
- except PreviousBuildDirError:
- options.no_clean = True
- raise
- finally:
- if not options.no_clean:
- requirement_set.cleanup_files()
- wheel_cache.cleanup()
+ return SUCCESS
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/configuration.py b/venv/lib/python3.8/site-packages/pip/_internal/configuration.py
index 437e92e..e49a5f4 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/configuration.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/configuration.py
@@ -19,7 +19,8 @@ import sys
from pip._vendor.six.moves import configparser
from pip._internal.exceptions import (
- ConfigurationError, ConfigurationFileCouldNotBeLoaded,
+ ConfigurationError,
+ ConfigurationFileCouldNotBeLoaded,
)
from pip._internal.utils import appdirs
from pip._internal.utils.compat import WINDOWS, expanduser
@@ -73,6 +74,7 @@ CONFIG_BASENAME = 'pip.ini' if WINDOWS else 'pip.conf'
def get_configuration_files():
+ # type: () -> Dict[Kind, List[str]]
global_config_files = [
os.path.join(path, CONFIG_BASENAME)
for path in appdirs.site_config_dirs('pip')
@@ -109,7 +111,7 @@ class Configuration(object):
"""
def __init__(self, isolated, load_only=None):
- # type: (bool, Kind) -> None
+ # type: (bool, Optional[Kind]) -> None
super(Configuration, self).__init__()
_valid_load_only = [kinds.USER, kinds.GLOBAL, kinds.SITE, None]
@@ -119,8 +121,8 @@ class Configuration(object):
", ".join(map(repr, _valid_load_only[:-1]))
)
)
- self.isolated = isolated # type: bool
- self.load_only = load_only # type: Optional[Kind]
+ self.isolated = isolated
+ self.load_only = load_only
# The order here determines the override order.
self._override_order = [
@@ -180,6 +182,7 @@ class Configuration(object):
"""
self._ensure_have_load_only()
+ assert self.load_only
fname, parser = self._get_parser_to_modify()
if parser is not None:
@@ -195,10 +198,10 @@ class Configuration(object):
def unset_value(self, key):
# type: (str) -> None
- """Unset a value in the configuration.
- """
+ """Unset a value in the configuration."""
self._ensure_have_load_only()
+ assert self.load_only
if key not in self._config[self.load_only]:
raise ConfigurationError("No such key - {}".format(key))
@@ -206,30 +209,18 @@ class Configuration(object):
if parser is not None:
section, name = _disassemble_key(key)
-
- # Remove the key in the parser
- modified_something = False
- if parser.has_section(section):
- # Returns whether the option was removed or not
- modified_something = parser.remove_option(section, name)
-
- if modified_something:
- # name removed from parser, section may now be empty
- section_iter = iter(parser.items(section))
- try:
- val = next(section_iter)
- except StopIteration:
- val = None
-
- if val is None:
- parser.remove_section(section)
-
- self._mark_as_modified(fname, parser)
- else:
+ if not (parser.has_section(section)
+ and parser.remove_option(section, name)):
+ # The option was not removed.
raise ConfigurationError(
"Fatal Internal error [id=1]. Please report as a bug."
)
+ # The section may be empty after the option was removed.
+ if not parser.items(section):
+ parser.remove_section(section)
+ self._mark_as_modified(fname, parser)
+
del self._config[self.load_only][key]
def save(self):
@@ -275,7 +266,7 @@ class Configuration(object):
# type: () -> None
"""Loads configuration from configuration files
"""
- config_files = dict(self._iter_config_files())
+ config_files = dict(self.iter_config_files())
if config_files[kinds.ENV][0:1] == [os.devnull]:
logger.debug(
"Skipping loading configuration files due to "
@@ -337,7 +328,7 @@ class Configuration(object):
"""Loads configuration from environment variables
"""
self._config[kinds.ENV_VAR].update(
- self._normalized_keys(":env:", self._get_environ_vars())
+ self._normalized_keys(":env:", self.get_environ_vars())
)
def _normalized_keys(self, section, items):
@@ -353,7 +344,7 @@ class Configuration(object):
normalized[key] = val
return normalized
- def _get_environ_vars(self):
+ def get_environ_vars(self):
# type: () -> Iterable[Tuple[str, str]]
"""Returns a generator with all environmental vars with prefix PIP_"""
for key, val in os.environ.items():
@@ -365,7 +356,7 @@ class Configuration(object):
yield key[4:].lower(), val
# XXX: This is patched in the tests.
- def _iter_config_files(self):
+ def iter_config_files(self):
# type: () -> Iterable[Tuple[Kind, List[str]]]
"""Yields variant and configuration files associated with it.
@@ -396,9 +387,15 @@ class Configuration(object):
# finally virtualenv configuration first trumping others
yield kinds.SITE, config_files[kinds.SITE]
+ def get_values_in_config(self, variant):
+ # type: (Kind) -> Dict[str, Any]
+ """Get values present in a config file"""
+ return self._config[variant]
+
def _get_parser_to_modify(self):
# type: () -> Tuple[str, RawConfigParser]
# Determine which parser to modify
+ assert self.load_only
parsers = self._parsers[self.load_only]
if not parsers:
# This should not happen if everything works correctly.
@@ -415,3 +412,7 @@ class Configuration(object):
file_parser_tuple = (fname, parser)
if file_parser_tuple not in self._modified_parsers:
self._modified_parsers.append(file_parser_tuple)
+
+ def __repr__(self):
+ # type: () -> str
+ return "{}({!r})".format(self.__class__.__name__, self._dictionary)
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/distributions/__init__.py
index fdf332a..d5c1afc 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/distributions/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/distributions/__init__.py
@@ -1,6 +1,5 @@
-from pip._internal.distributions.source import SourceDistribution
+from pip._internal.distributions.sdist import SourceDistribution
from pip._internal.distributions.wheel import WheelDistribution
-
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
if MYPY_CHECK_RUNNING:
@@ -12,11 +11,13 @@ def make_distribution_for_install_requirement(install_req):
# type: (InstallRequirement) -> AbstractDistribution
"""Returns a Distribution for the given InstallRequirement
"""
- # If it's not an editable, is a wheel, it's a WheelDistribution
+ # Editable requirements will always be source distributions. They use the
+ # legacy logic until we create a modern standard for them.
if install_req.editable:
return SourceDistribution(install_req)
- if install_req.link and install_req.is_wheel:
+ # If it's a wheel, it's a WheelDistribution
+ if install_req.is_wheel:
return WheelDistribution(install_req)
# Otherwise, a SourceDistribution
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-38.pyc
index 2d41e5a..5a5fd33 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/__pycache__/base.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/distributions/__pycache__/base.cpython-38.pyc
index 2763a7b..39a6172 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/distributions/__pycache__/base.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/distributions/__pycache__/base.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-38.pyc
index 781e0ed..caba054 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/__pycache__/source.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/distributions/__pycache__/source.cpython-38.pyc
deleted file mode 100644
index a0dd331..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/distributions/__pycache__/source.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-38.pyc
index dec6adf..93566e3 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/base.py b/venv/lib/python3.8/site-packages/pip/_internal/distributions/base.py
index b9af3f0..b836b98 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/distributions/base.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/distributions/base.py
@@ -2,6 +2,15 @@ import abc
from pip._vendor.six import add_metaclass
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+
+if MYPY_CHECK_RUNNING:
+ from typing import Optional
+
+ from pip._vendor.pkg_resources import Distribution
+ from pip._internal.req import InstallRequirement
+ from pip._internal.index.package_finder import PackageFinder
+
@add_metaclass(abc.ABCMeta)
class AbstractDistribution(object):
@@ -21,13 +30,16 @@ class AbstractDistribution(object):
"""
def __init__(self, req):
+ # type: (InstallRequirement) -> None
super(AbstractDistribution, self).__init__()
self.req = req
@abc.abstractmethod
def get_pkg_resources_distribution(self):
+ # type: () -> Optional[Distribution]
raise NotImplementedError()
@abc.abstractmethod
def prepare_distribution_metadata(self, finder, build_isolation):
+ # type: (PackageFinder, bool) -> None
raise NotImplementedError()
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/installed.py b/venv/lib/python3.8/site-packages/pip/_internal/distributions/installed.py
index c4a64e7..0d15bf4 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/distributions/installed.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/distributions/installed.py
@@ -1,4 +1,11 @@
from pip._internal.distributions.base import AbstractDistribution
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+
+if MYPY_CHECK_RUNNING:
+ from typing import Optional
+
+ from pip._vendor.pkg_resources import Distribution
+ from pip._internal.index.package_finder import PackageFinder
class InstalledDistribution(AbstractDistribution):
@@ -9,7 +16,9 @@ class InstalledDistribution(AbstractDistribution):
"""
def get_pkg_resources_distribution(self):
+ # type: () -> Optional[Distribution]
return self.req.satisfied_by
def prepare_distribution_metadata(self, finder, build_isolation):
+ # type: (PackageFinder, bool) -> None
pass
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/source.py b/venv/lib/python3.8/site-packages/pip/_internal/distributions/source.py
deleted file mode 100644
index e5d9fd4..0000000
--- a/venv/lib/python3.8/site-packages/pip/_internal/distributions/source.py
+++ /dev/null
@@ -1,80 +0,0 @@
-import logging
-
-from pip._internal.build_env import BuildEnvironment
-from pip._internal.distributions.base import AbstractDistribution
-from pip._internal.exceptions import InstallationError
-
-logger = logging.getLogger(__name__)
-
-
-class SourceDistribution(AbstractDistribution):
- """Represents a source distribution.
-
- The preparation step for these needs metadata for the packages to be
- generated, either using PEP 517 or using the legacy `setup.py egg_info`.
-
- NOTE from @pradyunsg (14 June 2019)
- I expect SourceDistribution class will need to be split into
- `legacy_source` (setup.py based) and `source` (PEP 517 based) when we start
- bringing logic for preparation out of InstallRequirement into this class.
- """
-
- def get_pkg_resources_distribution(self):
- return self.req.get_dist()
-
- def prepare_distribution_metadata(self, finder, build_isolation):
- # Prepare for building. We need to:
- # 1. Load pyproject.toml (if it exists)
- # 2. Set up the build environment
-
- self.req.load_pyproject_toml()
- should_isolate = self.req.use_pep517 and build_isolation
-
- def _raise_conflicts(conflicting_with, conflicting_reqs):
- raise InstallationError(
- "Some build dependencies for %s conflict with %s: %s." % (
- self.req, conflicting_with, ', '.join(
- '%s is incompatible with %s' % (installed, wanted)
- for installed, wanted in sorted(conflicting))))
-
- if should_isolate:
- # Isolate in a BuildEnvironment and install the build-time
- # requirements.
- self.req.build_env = BuildEnvironment()
- self.req.build_env.install_requirements(
- finder, self.req.pyproject_requires, 'overlay',
- "Installing build dependencies"
- )
- conflicting, missing = self.req.build_env.check_requirements(
- self.req.requirements_to_check
- )
- if conflicting:
- _raise_conflicts("PEP 517/518 supported requirements",
- conflicting)
- if missing:
- logger.warning(
- "Missing build requirements in pyproject.toml for %s.",
- self.req,
- )
- logger.warning(
- "The project does not specify a build backend, and "
- "pip cannot fall back to setuptools without %s.",
- " and ".join(map(repr, sorted(missing)))
- )
- # Install any extra build dependencies that the backend requests.
- # This must be done in a second pass, as the pyproject.toml
- # dependencies must be installed before we can call the backend.
- with self.req.build_env:
- # We need to have the env active when calling the hook.
- self.req.spin_message = "Getting requirements to build wheel"
- reqs = self.req.pep517_backend.get_requires_for_build_wheel()
- conflicting, missing = self.req.build_env.check_requirements(reqs)
- if conflicting:
- _raise_conflicts("the backend dependencies", conflicting)
- self.req.build_env.install_requirements(
- finder, missing, 'normal',
- "Installing backend dependencies"
- )
-
- self.req.prepare_metadata()
- self.req.assert_source_matches_version()
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/distributions/wheel.py b/venv/lib/python3.8/site-packages/pip/_internal/distributions/wheel.py
index de7be38..bf3482b 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/distributions/wheel.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/distributions/wheel.py
@@ -1,6 +1,12 @@
-from pip._vendor import pkg_resources
+from zipfile import ZipFile
from pip._internal.distributions.base import AbstractDistribution
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+from pip._internal.utils.wheel import pkg_resources_distribution_for_wheel
+
+if MYPY_CHECK_RUNNING:
+ from pip._vendor.pkg_resources import Distribution
+ from pip._internal.index.package_finder import PackageFinder
class WheelDistribution(AbstractDistribution):
@@ -10,8 +16,21 @@ class WheelDistribution(AbstractDistribution):
"""
def get_pkg_resources_distribution(self):
- return list(pkg_resources.find_distributions(
- self.req.source_dir))[0]
+ # type: () -> Distribution
+ """Loads the metadata from the wheel file into memory and returns a
+ Distribution that uses it, not relying on the wheel file or
+ requirement.
+ """
+ # Set as part of preparation during download.
+ assert self.req.local_file_path
+ # Wheels are never unnamed.
+ assert self.req.name
+
+ with ZipFile(self.req.local_file_path, allowZip64=True) as z:
+ return pkg_resources_distribution_for_wheel(
+ z, self.req.name, self.req.local_file_path
+ )
def prepare_distribution_metadata(self, finder, build_isolation):
+ # type: (PackageFinder, bool) -> None
pass
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/download.py b/venv/lib/python3.8/site-packages/pip/_internal/download.py
deleted file mode 100644
index fc1f4dd..0000000
--- a/venv/lib/python3.8/site-packages/pip/_internal/download.py
+++ /dev/null
@@ -1,1177 +0,0 @@
-from __future__ import absolute_import
-
-import cgi
-import email.utils
-import json
-import logging
-import mimetypes
-import os
-import platform
-import re
-import shutil
-import sys
-
-from pip._vendor import requests, urllib3
-from pip._vendor.cachecontrol import CacheControlAdapter
-from pip._vendor.cachecontrol.caches import FileCache
-from pip._vendor.lockfile import LockError
-from pip._vendor.requests.adapters import BaseAdapter, HTTPAdapter
-from pip._vendor.requests.auth import AuthBase, HTTPBasicAuth
-from pip._vendor.requests.models import CONTENT_CHUNK_SIZE, Response
-from pip._vendor.requests.structures import CaseInsensitiveDict
-from pip._vendor.requests.utils import get_netrc_auth
-# NOTE: XMLRPC Client is not annotated in typeshed as on 2017-07-17, which is
-# why we ignore the type on this import
-from pip._vendor.six.moves import xmlrpc_client # type: ignore
-from pip._vendor.six.moves.urllib import parse as urllib_parse
-from pip._vendor.six.moves.urllib import request as urllib_request
-
-import pip
-from pip._internal.exceptions import HashMismatch, InstallationError
-from pip._internal.models.index import PyPI
-# Import ssl from compat so the initial import occurs in only one place.
-from pip._internal.utils.compat import HAS_TLS, ssl
-from pip._internal.utils.encoding import auto_decode
-from pip._internal.utils.filesystem import check_path_owner
-from pip._internal.utils.glibc import libc_ver
-from pip._internal.utils.marker_files import write_delete_marker_file
-from pip._internal.utils.misc import (
- ARCHIVE_EXTENSIONS, ask, ask_input, ask_password, ask_path_exists,
- backup_dir, consume, display_path, format_size, get_installed_version,
- path_to_url, remove_auth_from_url, rmtree, split_auth_netloc_from_url,
- splitext, unpack_file,
-)
-from pip._internal.utils.temp_dir import TempDirectory
-from pip._internal.utils.typing import MYPY_CHECK_RUNNING
-from pip._internal.utils.ui import DownloadProgressProvider
-from pip._internal.vcs import vcs
-
-if MYPY_CHECK_RUNNING:
- from typing import (
- Optional, Tuple, Dict, IO, Text, Union
- )
- from optparse import Values
- from pip._internal.models.link import Link
- from pip._internal.utils.hashes import Hashes
- from pip._internal.vcs.versioncontrol import AuthInfo, VersionControl
-
- Credentials = Tuple[str, str, str]
-
-
-__all__ = ['get_file_content',
- 'is_url', 'url_to_path', 'path_to_url',
- 'is_archive_file', 'unpack_vcs_link',
- 'unpack_file_url', 'is_vcs_url', 'is_file_url',
- 'unpack_http_url', 'unpack_url',
- 'parse_content_disposition', 'sanitize_content_filename']
-
-
-logger = logging.getLogger(__name__)
-
-
-try:
- import keyring # noqa
-except ImportError:
- keyring = None
-except Exception as exc:
- logger.warning("Keyring is skipped due to an exception: %s",
- str(exc))
- keyring = None
-
-# These are environment variables present when running under various
-# CI systems. For each variable, some CI systems that use the variable
-# are indicated. The collection was chosen so that for each of a number
-# of popular systems, at least one of the environment variables is used.
-# This list is used to provide some indication of and lower bound for
-# CI traffic to PyPI. Thus, it is okay if the list is not comprehensive.
-# For more background, see: https://github.com/pypa/pip/issues/5499
-CI_ENVIRONMENT_VARIABLES = (
- # Azure Pipelines
- 'BUILD_BUILDID',
- # Jenkins
- 'BUILD_ID',
- # AppVeyor, CircleCI, Codeship, Gitlab CI, Shippable, Travis CI
- 'CI',
- # Explicit environment variable.
- 'PIP_IS_CI',
-)
-
-
-def looks_like_ci():
- # type: () -> bool
- """
- Return whether it looks like pip is running under CI.
- """
- # We don't use the method of checking for a tty (e.g. using isatty())
- # because some CI systems mimic a tty (e.g. Travis CI). Thus that
- # method doesn't provide definitive information in either direction.
- return any(name in os.environ for name in CI_ENVIRONMENT_VARIABLES)
-
-
-def user_agent():
- """
- Return a string representing the user agent.
- """
- data = {
- "installer": {"name": "pip", "version": pip.__version__},
- "python": platform.python_version(),
- "implementation": {
- "name": platform.python_implementation(),
- },
- }
-
- if data["implementation"]["name"] == 'CPython':
- data["implementation"]["version"] = platform.python_version()
- elif data["implementation"]["name"] == 'PyPy':
- if sys.pypy_version_info.releaselevel == 'final':
- pypy_version_info = sys.pypy_version_info[:3]
- else:
- pypy_version_info = sys.pypy_version_info
- data["implementation"]["version"] = ".".join(
- [str(x) for x in pypy_version_info]
- )
- elif data["implementation"]["name"] == 'Jython':
- # Complete Guess
- data["implementation"]["version"] = platform.python_version()
- elif data["implementation"]["name"] == 'IronPython':
- # Complete Guess
- data["implementation"]["version"] = platform.python_version()
-
- if sys.platform.startswith("linux"):
- from pip._vendor import distro
- distro_infos = dict(filter(
- lambda x: x[1],
- zip(["name", "version", "id"], distro.linux_distribution()),
- ))
- libc = dict(filter(
- lambda x: x[1],
- zip(["lib", "version"], libc_ver()),
- ))
- if libc:
- distro_infos["libc"] = libc
- if distro_infos:
- data["distro"] = distro_infos
-
- if sys.platform.startswith("darwin") and platform.mac_ver()[0]:
- data["distro"] = {"name": "macOS", "version": platform.mac_ver()[0]}
-
- if platform.system():
- data.setdefault("system", {})["name"] = platform.system()
-
- if platform.release():
- data.setdefault("system", {})["release"] = platform.release()
-
- if platform.machine():
- data["cpu"] = platform.machine()
-
- if HAS_TLS:
- data["openssl_version"] = ssl.OPENSSL_VERSION
-
- setuptools_version = get_installed_version("setuptools")
- if setuptools_version is not None:
- data["setuptools_version"] = setuptools_version
-
- # Use None rather than False so as not to give the impression that
- # pip knows it is not being run under CI. Rather, it is a null or
- # inconclusive result. Also, we include some value rather than no
- # value to make it easier to know that the check has been run.
- data["ci"] = True if looks_like_ci() else None
-
- user_data = os.environ.get("PIP_USER_AGENT_USER_DATA")
- if user_data is not None:
- data["user_data"] = user_data
-
- return "{data[installer][name]}/{data[installer][version]} {json}".format(
- data=data,
- json=json.dumps(data, separators=(",", ":"), sort_keys=True),
- )
-
-
-def _get_keyring_auth(url, username):
- """Return the tuple auth for a given url from keyring."""
- if not url or not keyring:
- return None
-
- try:
- try:
- get_credential = keyring.get_credential
- except AttributeError:
- pass
- else:
- logger.debug("Getting credentials from keyring for %s", url)
- cred = get_credential(url, username)
- if cred is not None:
- return cred.username, cred.password
- return None
-
- if username:
- logger.debug("Getting password from keyring for %s", url)
- password = keyring.get_password(url, username)
- if password:
- return username, password
-
- except Exception as exc:
- logger.warning("Keyring is skipped due to an exception: %s",
- str(exc))
-
-
-class MultiDomainBasicAuth(AuthBase):
-
- def __init__(self, prompting=True, index_urls=None):
- # type: (bool, Optional[Values]) -> None
- self.prompting = prompting
- self.index_urls = index_urls
- self.passwords = {} # type: Dict[str, AuthInfo]
- # When the user is prompted to enter credentials and keyring is
- # available, we will offer to save them. If the user accepts,
- # this value is set to the credentials they entered. After the
- # request authenticates, the caller should call
- # ``save_credentials`` to save these.
- self._credentials_to_save = None # type: Optional[Credentials]
-
- def _get_index_url(self, url):
- """Return the original index URL matching the requested URL.
-
- Cached or dynamically generated credentials may work against
- the original index URL rather than just the netloc.
-
- The provided url should have had its username and password
- removed already. If the original index url had credentials then
- they will be included in the return value.
-
- Returns None if no matching index was found, or if --no-index
- was specified by the user.
- """
- if not url or not self.index_urls:
- return None
-
- for u in self.index_urls:
- prefix = remove_auth_from_url(u).rstrip("/") + "/"
- if url.startswith(prefix):
- return u
-
- def _get_new_credentials(self, original_url, allow_netrc=True,
- allow_keyring=True):
- """Find and return credentials for the specified URL."""
- # Split the credentials and netloc from the url.
- url, netloc, url_user_password = split_auth_netloc_from_url(
- original_url)
-
- # Start with the credentials embedded in the url
- username, password = url_user_password
- if username is not None and password is not None:
- logger.debug("Found credentials in url for %s", netloc)
- return url_user_password
-
- # Find a matching index url for this request
- index_url = self._get_index_url(url)
- if index_url:
- # Split the credentials from the url.
- index_info = split_auth_netloc_from_url(index_url)
- if index_info:
- index_url, _, index_url_user_password = index_info
- logger.debug("Found index url %s", index_url)
-
- # If an index URL was found, try its embedded credentials
- if index_url and index_url_user_password[0] is not None:
- username, password = index_url_user_password
- if username is not None and password is not None:
- logger.debug("Found credentials in index url for %s", netloc)
- return index_url_user_password
-
- # Get creds from netrc if we still don't have them
- if allow_netrc:
- netrc_auth = get_netrc_auth(original_url)
- if netrc_auth:
- logger.debug("Found credentials in netrc for %s", netloc)
- return netrc_auth
-
- # If we don't have a password and keyring is available, use it.
- if allow_keyring:
- # The index url is more specific than the netloc, so try it first
- kr_auth = (_get_keyring_auth(index_url, username) or
- _get_keyring_auth(netloc, username))
- if kr_auth:
- logger.debug("Found credentials in keyring for %s", netloc)
- return kr_auth
-
- return username, password
-
- def _get_url_and_credentials(self, original_url):
- """Return the credentials to use for the provided URL.
-
- If allowed, netrc and keyring may be used to obtain the
- correct credentials.
-
- Returns (url_without_credentials, username, password). Note
- that even if the original URL contains credentials, this
- function may return a different username and password.
- """
- url, netloc, _ = split_auth_netloc_from_url(original_url)
-
- # Use any stored credentials that we have for this netloc
- username, password = self.passwords.get(netloc, (None, None))
-
- if username is None and password is None:
- # No stored credentials. Acquire new credentials without prompting
- # the user. (e.g. from netrc, keyring, or the URL itself)
- username, password = self._get_new_credentials(original_url)
-
- if username is not None or password is not None:
- # Convert the username and password if they're None, so that
- # this netloc will show up as "cached" in the conditional above.
- # Further, HTTPBasicAuth doesn't accept None, so it makes sense to
- # cache the value that is going to be used.
- username = username or ""
- password = password or ""
-
- # Store any acquired credentials.
- self.passwords[netloc] = (username, password)
-
- assert (
- # Credentials were found
- (username is not None and password is not None) or
- # Credentials were not found
- (username is None and password is None)
- ), "Could not load credentials from url: {}".format(original_url)
-
- return url, username, password
-
- def __call__(self, req):
- # Get credentials for this request
- url, username, password = self._get_url_and_credentials(req.url)
-
- # Set the url of the request to the url without any credentials
- req.url = url
-
- if username is not None and password is not None:
- # Send the basic auth with this request
- req = HTTPBasicAuth(username, password)(req)
-
- # Attach a hook to handle 401 responses
- req.register_hook("response", self.handle_401)
-
- return req
-
- # Factored out to allow for easy patching in tests
- def _prompt_for_password(self, netloc):
- username = ask_input("User for %s: " % netloc)
- if not username:
- return None, None
- auth = _get_keyring_auth(netloc, username)
- if auth:
- return auth[0], auth[1], False
- password = ask_password("Password: ")
- return username, password, True
-
- # Factored out to allow for easy patching in tests
- def _should_save_password_to_keyring(self):
- if not keyring:
- return False
- return ask("Save credentials to keyring [y/N]: ", ["y", "n"]) == "y"
-
- def handle_401(self, resp, **kwargs):
- # We only care about 401 responses, anything else we want to just
- # pass through the actual response
- if resp.status_code != 401:
- return resp
-
- # We are not able to prompt the user so simply return the response
- if not self.prompting:
- return resp
-
- parsed = urllib_parse.urlparse(resp.url)
-
- # Prompt the user for a new username and password
- username, password, save = self._prompt_for_password(parsed.netloc)
-
- # Store the new username and password to use for future requests
- self._credentials_to_save = None
- if username is not None and password is not None:
- self.passwords[parsed.netloc] = (username, password)
-
- # Prompt to save the password to keyring
- if save and self._should_save_password_to_keyring():
- self._credentials_to_save = (parsed.netloc, username, password)
-
- # Consume content and release the original connection to allow our new
- # request to reuse the same one.
- resp.content
- resp.raw.release_conn()
-
- # Add our new username and password to the request
- req = HTTPBasicAuth(username or "", password or "")(resp.request)
- req.register_hook("response", self.warn_on_401)
-
- # On successful request, save the credentials that were used to
- # keyring. (Note that if the user responded "no" above, this member
- # is not set and nothing will be saved.)
- if self._credentials_to_save:
- req.register_hook("response", self.save_credentials)
-
- # Send our new request
- new_resp = resp.connection.send(req, **kwargs)
- new_resp.history.append(resp)
-
- return new_resp
-
- def warn_on_401(self, resp, **kwargs):
- """Response callback to warn about incorrect credentials."""
- if resp.status_code == 401:
- logger.warning('401 Error, Credentials not correct for %s',
- resp.request.url)
-
- def save_credentials(self, resp, **kwargs):
- """Response callback to save credentials on success."""
- assert keyring is not None, "should never reach here without keyring"
- if not keyring:
- return
-
- creds = self._credentials_to_save
- self._credentials_to_save = None
- if creds and resp.status_code < 400:
- try:
- logger.info('Saving credentials to keyring')
- keyring.set_password(*creds)
- except Exception:
- logger.exception('Failed to save credentials')
-
-
-class LocalFSAdapter(BaseAdapter):
-
- def send(self, request, stream=None, timeout=None, verify=None, cert=None,
- proxies=None):
- pathname = url_to_path(request.url)
-
- resp = Response()
- resp.status_code = 200
- resp.url = request.url
-
- try:
- stats = os.stat(pathname)
- except OSError as exc:
- resp.status_code = 404
- resp.raw = exc
- else:
- modified = email.utils.formatdate(stats.st_mtime, usegmt=True)
- content_type = mimetypes.guess_type(pathname)[0] or "text/plain"
- resp.headers = CaseInsensitiveDict({
- "Content-Type": content_type,
- "Content-Length": stats.st_size,
- "Last-Modified": modified,
- })
-
- resp.raw = open(pathname, "rb")
- resp.close = resp.raw.close
-
- return resp
-
- def close(self):
- pass
-
-
-class SafeFileCache(FileCache):
- """
- A file based cache which is safe to use even when the target directory may
- not be accessible or writable.
- """
-
- def __init__(self, *args, **kwargs):
- super(SafeFileCache, self).__init__(*args, **kwargs)
-
- # Check to ensure that the directory containing our cache directory
- # is owned by the user current executing pip. If it does not exist
- # we will check the parent directory until we find one that does exist.
- # If it is not owned by the user executing pip then we will disable
- # the cache and log a warning.
- if not check_path_owner(self.directory):
- logger.warning(
- "The directory '%s' or its parent directory is not owned by "
- "the current user and the cache has been disabled. Please "
- "check the permissions and owner of that directory. If "
- "executing pip with sudo, you may want sudo's -H flag.",
- self.directory,
- )
-
- # Set our directory to None to disable the Cache
- self.directory = None
-
- def get(self, *args, **kwargs):
- # If we don't have a directory, then the cache should be a no-op.
- if self.directory is None:
- return
-
- try:
- return super(SafeFileCache, self).get(*args, **kwargs)
- except (LockError, OSError, IOError):
- # We intentionally silence this error, if we can't access the cache
- # then we can just skip caching and process the request as if
- # caching wasn't enabled.
- pass
-
- def set(self, *args, **kwargs):
- # If we don't have a directory, then the cache should be a no-op.
- if self.directory is None:
- return
-
- try:
- return super(SafeFileCache, self).set(*args, **kwargs)
- except (LockError, OSError, IOError):
- # We intentionally silence this error, if we can't access the cache
- # then we can just skip caching and process the request as if
- # caching wasn't enabled.
- pass
-
- def delete(self, *args, **kwargs):
- # If we don't have a directory, then the cache should be a no-op.
- if self.directory is None:
- return
-
- try:
- return super(SafeFileCache, self).delete(*args, **kwargs)
- except (LockError, OSError, IOError):
- # We intentionally silence this error, if we can't access the cache
- # then we can just skip caching and process the request as if
- # caching wasn't enabled.
- pass
-
-
-class InsecureHTTPAdapter(HTTPAdapter):
-
- def cert_verify(self, conn, url, verify, cert):
- conn.cert_reqs = 'CERT_NONE'
- conn.ca_certs = None
-
-
-class PipSession(requests.Session):
-
- timeout = None # type: Optional[int]
-
- def __init__(self, *args, **kwargs):
- retries = kwargs.pop("retries", 0)
- cache = kwargs.pop("cache", None)
- insecure_hosts = kwargs.pop("insecure_hosts", [])
- index_urls = kwargs.pop("index_urls", None)
-
- super(PipSession, self).__init__(*args, **kwargs)
-
- # Attach our User Agent to the request
- self.headers["User-Agent"] = user_agent()
-
- # Attach our Authentication handler to the session
- self.auth = MultiDomainBasicAuth(index_urls=index_urls)
-
- # Create our urllib3.Retry instance which will allow us to customize
- # how we handle retries.
- retries = urllib3.Retry(
- # Set the total number of retries that a particular request can
- # have.
- total=retries,
-
- # A 503 error from PyPI typically means that the Fastly -> Origin
- # connection got interrupted in some way. A 503 error in general
- # is typically considered a transient error so we'll go ahead and
- # retry it.
- # A 500 may indicate transient error in Amazon S3
- # A 520 or 527 - may indicate transient error in CloudFlare
- status_forcelist=[500, 503, 520, 527],
-
- # Add a small amount of back off between failed requests in
- # order to prevent hammering the service.
- backoff_factor=0.25,
- )
-
- # We want to _only_ cache responses on securely fetched origins. We do
- # this because we can't validate the response of an insecurely fetched
- # origin, and we don't want someone to be able to poison the cache and
- # require manual eviction from the cache to fix it.
- if cache:
- secure_adapter = CacheControlAdapter(
- cache=SafeFileCache(cache, use_dir_lock=True),
- max_retries=retries,
- )
- else:
- secure_adapter = HTTPAdapter(max_retries=retries)
-
- # Our Insecure HTTPAdapter disables HTTPS validation. It does not
- # support caching (see above) so we'll use it for all http:// URLs as
- # well as any https:// host that we've marked as ignoring TLS errors
- # for.
- insecure_adapter = InsecureHTTPAdapter(max_retries=retries)
- # Save this for later use in add_insecure_host().
- self._insecure_adapter = insecure_adapter
-
- self.mount("https://", secure_adapter)
- self.mount("http://", insecure_adapter)
-
- # Enable file:// urls
- self.mount("file://", LocalFSAdapter())
-
- # We want to use a non-validating adapter for any requests which are
- # deemed insecure.
- for host in insecure_hosts:
- self.add_insecure_host(host)
-
- def add_insecure_host(self, host):
- # type: (str) -> None
- self.mount('https://{}/'.format(host), self._insecure_adapter)
-
- def request(self, method, url, *args, **kwargs):
- # Allow setting a default timeout on a session
- kwargs.setdefault("timeout", self.timeout)
-
- # Dispatch the actual request
- return super(PipSession, self).request(method, url, *args, **kwargs)
-
-
-def get_file_content(url, comes_from=None, session=None):
- # type: (str, Optional[str], Optional[PipSession]) -> Tuple[str, Text]
- """Gets the content of a file; it may be a filename, file: URL, or
- http: URL. Returns (location, content). Content is unicode.
-
- :param url: File path or url.
- :param comes_from: Origin description of requirements.
- :param session: Instance of pip.download.PipSession.
- """
- if session is None:
- raise TypeError(
- "get_file_content() missing 1 required keyword argument: 'session'"
- )
-
- match = _scheme_re.search(url)
- if match:
- scheme = match.group(1).lower()
- if (scheme == 'file' and comes_from and
- comes_from.startswith('http')):
- raise InstallationError(
- 'Requirements file %s references URL %s, which is local'
- % (comes_from, url))
- if scheme == 'file':
- path = url.split(':', 1)[1]
- path = path.replace('\\', '/')
- match = _url_slash_drive_re.match(path)
- if match:
- path = match.group(1) + ':' + path.split('|', 1)[1]
- path = urllib_parse.unquote(path)
- if path.startswith('/'):
- path = '/' + path.lstrip('/')
- url = path
- else:
- # FIXME: catch some errors
- resp = session.get(url)
- resp.raise_for_status()
- return resp.url, resp.text
- try:
- with open(url, 'rb') as f:
- content = auto_decode(f.read())
- except IOError as exc:
- raise InstallationError(
- 'Could not open requirements file: %s' % str(exc)
- )
- return url, content
-
-
-_scheme_re = re.compile(r'^(http|https|file):', re.I)
-_url_slash_drive_re = re.compile(r'/*([a-z])\|', re.I)
-
-
-def is_url(name):
- # type: (Union[str, Text]) -> bool
- """Returns true if the name looks like a URL"""
- if ':' not in name:
- return False
- scheme = name.split(':', 1)[0].lower()
- return scheme in ['http', 'https', 'file', 'ftp'] + vcs.all_schemes
-
-
-def url_to_path(url):
- # type: (str) -> str
- """
- Convert a file: URL to a path.
- """
- assert url.startswith('file:'), (
- "You can only turn file: urls into filenames (not %r)" % url)
-
- _, netloc, path, _, _ = urllib_parse.urlsplit(url)
-
- if not netloc or netloc == 'localhost':
- # According to RFC 8089, same as empty authority.
- netloc = ''
- elif sys.platform == 'win32':
- # If we have a UNC path, prepend UNC share notation.
- netloc = '\\\\' + netloc
- else:
- raise ValueError(
- 'non-local file URIs are not supported on this platform: %r'
- % url
- )
-
- path = urllib_request.url2pathname(netloc + path)
- return path
-
-
-def is_archive_file(name):
- # type: (str) -> bool
- """Return True if `name` is a considered as an archive file."""
- ext = splitext(name)[1].lower()
- if ext in ARCHIVE_EXTENSIONS:
- return True
- return False
-
-
-def unpack_vcs_link(link, location):
- vcs_backend = _get_used_vcs_backend(link)
- vcs_backend.unpack(location, url=link.url)
-
-
-def _get_used_vcs_backend(link):
- # type: (Link) -> Optional[VersionControl]
- """
- Return a VersionControl object or None.
- """
- for vcs_backend in vcs.backends:
- if link.scheme in vcs_backend.schemes:
- return vcs_backend
- return None
-
-
-def is_vcs_url(link):
- # type: (Link) -> bool
- return bool(_get_used_vcs_backend(link))
-
-
-def is_file_url(link):
- # type: (Link) -> bool
- return link.url.lower().startswith('file:')
-
-
-def is_dir_url(link):
- # type: (Link) -> bool
- """Return whether a file:// Link points to a directory.
-
- ``link`` must not have any other scheme but file://. Call is_file_url()
- first.
-
- """
- link_path = url_to_path(link.url_without_fragment)
- return os.path.isdir(link_path)
-
-
-def _progress_indicator(iterable, *args, **kwargs):
- return iterable
-
-
-def _download_url(
- resp, # type: Response
- link, # type: Link
- content_file, # type: IO
- hashes, # type: Optional[Hashes]
- progress_bar # type: str
-):
- # type: (...) -> None
- try:
- total_length = int(resp.headers['content-length'])
- except (ValueError, KeyError, TypeError):
- total_length = 0
-
- cached_resp = getattr(resp, "from_cache", False)
- if logger.getEffectiveLevel() > logging.INFO:
- show_progress = False
- elif cached_resp:
- show_progress = False
- elif total_length > (40 * 1000):
- show_progress = True
- elif not total_length:
- show_progress = True
- else:
- show_progress = False
-
- show_url = link.show_url
-
- def resp_read(chunk_size):
- try:
- # Special case for urllib3.
- for chunk in resp.raw.stream(
- chunk_size,
- # We use decode_content=False here because we don't
- # want urllib3 to mess with the raw bytes we get
- # from the server. If we decompress inside of
- # urllib3 then we cannot verify the checksum
- # because the checksum will be of the compressed
- # file. This breakage will only occur if the
- # server adds a Content-Encoding header, which
- # depends on how the server was configured:
- # - Some servers will notice that the file isn't a
- # compressible file and will leave the file alone
- # and with an empty Content-Encoding
- # - Some servers will notice that the file is
- # already compressed and will leave the file
- # alone and will add a Content-Encoding: gzip
- # header
- # - Some servers won't notice anything at all and
- # will take a file that's already been compressed
- # and compress it again and set the
- # Content-Encoding: gzip header
- #
- # By setting this not to decode automatically we
- # hope to eliminate problems with the second case.
- decode_content=False):
- yield chunk
- except AttributeError:
- # Standard file-like object.
- while True:
- chunk = resp.raw.read(chunk_size)
- if not chunk:
- break
- yield chunk
-
- def written_chunks(chunks):
- for chunk in chunks:
- content_file.write(chunk)
- yield chunk
-
- progress_indicator = _progress_indicator
-
- if link.netloc == PyPI.netloc:
- url = show_url
- else:
- url = link.url_without_fragment
-
- if show_progress: # We don't show progress on cached responses
- progress_indicator = DownloadProgressProvider(progress_bar,
- max=total_length)
- if total_length:
- logger.info("Downloading %s (%s)", url, format_size(total_length))
- else:
- logger.info("Downloading %s", url)
- elif cached_resp:
- logger.info("Using cached %s", url)
- else:
- logger.info("Downloading %s", url)
-
- logger.debug('Downloading from URL %s', link)
-
- downloaded_chunks = written_chunks(
- progress_indicator(
- resp_read(CONTENT_CHUNK_SIZE),
- CONTENT_CHUNK_SIZE
- )
- )
- if hashes:
- hashes.check_against_chunks(downloaded_chunks)
- else:
- consume(downloaded_chunks)
-
-
-def _copy_file(filename, location, link):
- copy = True
- download_location = os.path.join(location, link.filename)
- if os.path.exists(download_location):
- response = ask_path_exists(
- 'The file %s exists. (i)gnore, (w)ipe, (b)ackup, (a)abort' %
- display_path(download_location), ('i', 'w', 'b', 'a'))
- if response == 'i':
- copy = False
- elif response == 'w':
- logger.warning('Deleting %s', display_path(download_location))
- os.remove(download_location)
- elif response == 'b':
- dest_file = backup_dir(download_location)
- logger.warning(
- 'Backing up %s to %s',
- display_path(download_location),
- display_path(dest_file),
- )
- shutil.move(download_location, dest_file)
- elif response == 'a':
- sys.exit(-1)
- if copy:
- shutil.copy(filename, download_location)
- logger.info('Saved %s', display_path(download_location))
-
-
-def unpack_http_url(
- link, # type: Link
- location, # type: str
- download_dir=None, # type: Optional[str]
- session=None, # type: Optional[PipSession]
- hashes=None, # type: Optional[Hashes]
- progress_bar="on" # type: str
-):
- # type: (...) -> None
- if session is None:
- raise TypeError(
- "unpack_http_url() missing 1 required keyword argument: 'session'"
- )
-
- with TempDirectory(kind="unpack") as temp_dir:
- # If a download dir is specified, is the file already downloaded there?
- already_downloaded_path = None
- if download_dir:
- already_downloaded_path = _check_download_dir(link,
- download_dir,
- hashes)
-
- if already_downloaded_path:
- from_path = already_downloaded_path
- content_type = mimetypes.guess_type(from_path)[0]
- else:
- # let's download to a tmp dir
- from_path, content_type = _download_http_url(link,
- session,
- temp_dir.path,
- hashes,
- progress_bar)
-
- # unpack the archive to the build dir location. even when only
- # downloading archives, they have to be unpacked to parse dependencies
- unpack_file(from_path, location, content_type, link)
-
- # a download dir is specified; let's copy the archive there
- if download_dir and not already_downloaded_path:
- _copy_file(from_path, download_dir, link)
-
- if not already_downloaded_path:
- os.unlink(from_path)
-
-
-def unpack_file_url(
- link, # type: Link
- location, # type: str
- download_dir=None, # type: Optional[str]
- hashes=None # type: Optional[Hashes]
-):
- # type: (...) -> None
- """Unpack link into location.
-
- If download_dir is provided and link points to a file, make a copy
- of the link file inside download_dir.
- """
- link_path = url_to_path(link.url_without_fragment)
-
- # If it's a url to a local directory
- if is_dir_url(link):
- if os.path.isdir(location):
- rmtree(location)
- shutil.copytree(link_path, location, symlinks=True)
- if download_dir:
- logger.info('Link is a directory, ignoring download_dir')
- return
-
- # If --require-hashes is off, `hashes` is either empty, the
- # link's embedded hash, or MissingHashes; it is required to
- # match. If --require-hashes is on, we are satisfied by any
- # hash in `hashes` matching: a URL-based or an option-based
- # one; no internet-sourced hash will be in `hashes`.
- if hashes:
- hashes.check_against_path(link_path)
-
- # If a download dir is specified, is the file already there and valid?
- already_downloaded_path = None
- if download_dir:
- already_downloaded_path = _check_download_dir(link,
- download_dir,
- hashes)
-
- if already_downloaded_path:
- from_path = already_downloaded_path
- else:
- from_path = link_path
-
- content_type = mimetypes.guess_type(from_path)[0]
-
- # unpack the archive to the build dir location. even when only downloading
- # archives, they have to be unpacked to parse dependencies
- unpack_file(from_path, location, content_type, link)
-
- # a download dir is specified and not already downloaded
- if download_dir and not already_downloaded_path:
- _copy_file(from_path, download_dir, link)
-
-
-class PipXmlrpcTransport(xmlrpc_client.Transport):
- """Provide a `xmlrpclib.Transport` implementation via a `PipSession`
- object.
- """
-
- def __init__(self, index_url, session, use_datetime=False):
- xmlrpc_client.Transport.__init__(self, use_datetime)
- index_parts = urllib_parse.urlparse(index_url)
- self._scheme = index_parts.scheme
- self._session = session
-
- def request(self, host, handler, request_body, verbose=False):
- parts = (self._scheme, host, handler, None, None, None)
- url = urllib_parse.urlunparse(parts)
- try:
- headers = {'Content-Type': 'text/xml'}
- response = self._session.post(url, data=request_body,
- headers=headers, stream=True)
- response.raise_for_status()
- self.verbose = verbose
- return self.parse_response(response.raw)
- except requests.HTTPError as exc:
- logger.critical(
- "HTTP error %s while getting %s",
- exc.response.status_code, url,
- )
- raise
-
-
-def unpack_url(
- link, # type: Link
- location, # type: str
- download_dir=None, # type: Optional[str]
- only_download=False, # type: bool
- session=None, # type: Optional[PipSession]
- hashes=None, # type: Optional[Hashes]
- progress_bar="on" # type: str
-):
- # type: (...) -> None
- """Unpack link.
- If link is a VCS link:
- if only_download, export into download_dir and ignore location
- else unpack into location
- for other types of link:
- - unpack into location
- - if download_dir, copy the file into download_dir
- - if only_download, mark location for deletion
-
- :param hashes: A Hashes object, one of whose embedded hashes must match,
- or HashMismatch will be raised. If the Hashes is empty, no matches are
- required, and unhashable types of requirements (like VCS ones, which
- would ordinarily raise HashUnsupported) are allowed.
- """
- # non-editable vcs urls
- if is_vcs_url(link):
- unpack_vcs_link(link, location)
-
- # file urls
- elif is_file_url(link):
- unpack_file_url(link, location, download_dir, hashes=hashes)
-
- # http urls
- else:
- if session is None:
- session = PipSession()
-
- unpack_http_url(
- link,
- location,
- download_dir,
- session,
- hashes=hashes,
- progress_bar=progress_bar
- )
- if only_download:
- write_delete_marker_file(location)
-
-
-def sanitize_content_filename(filename):
- # type: (str) -> str
- """
- Sanitize the "filename" value from a Content-Disposition header.
- """
- return os.path.basename(filename)
-
-
-def parse_content_disposition(content_disposition, default_filename):
- # type: (str, str) -> str
- """
- Parse the "filename" value from a Content-Disposition header, and
- return the default filename if the result is empty.
- """
- _type, params = cgi.parse_header(content_disposition)
- filename = params.get('filename')
- if filename:
- # We need to sanitize the filename to prevent directory traversal
- # in case the filename contains ".." path parts.
- filename = sanitize_content_filename(filename)
- return filename or default_filename
-
-
-def _download_http_url(
- link, # type: Link
- session, # type: PipSession
- temp_dir, # type: str
- hashes, # type: Optional[Hashes]
- progress_bar # type: str
-):
- # type: (...) -> Tuple[str, str]
- """Download link url into temp_dir using provided session"""
- target_url = link.url.split('#', 1)[0]
- try:
- resp = session.get(
- target_url,
- # We use Accept-Encoding: identity here because requests
- # defaults to accepting compressed responses. This breaks in
- # a variety of ways depending on how the server is configured.
- # - Some servers will notice that the file isn't a compressible
- # file and will leave the file alone and with an empty
- # Content-Encoding
- # - Some servers will notice that the file is already
- # compressed and will leave the file alone and will add a
- # Content-Encoding: gzip header
- # - Some servers won't notice anything at all and will take
- # a file that's already been compressed and compress it again
- # and set the Content-Encoding: gzip header
- # By setting this to request only the identity encoding We're
- # hoping to eliminate the third case. Hopefully there does not
- # exist a server which when given a file will notice it is
- # already compressed and that you're not asking for a
- # compressed file and will then decompress it before sending
- # because if that's the case I don't think it'll ever be
- # possible to make this work.
- headers={"Accept-Encoding": "identity"},
- stream=True,
- )
- resp.raise_for_status()
- except requests.HTTPError as exc:
- logger.critical(
- "HTTP error %s while getting %s", exc.response.status_code, link,
- )
- raise
-
- content_type = resp.headers.get('content-type', '')
- filename = link.filename # fallback
- # Have a look at the Content-Disposition header for a better guess
- content_disposition = resp.headers.get('content-disposition')
- if content_disposition:
- filename = parse_content_disposition(content_disposition, filename)
- ext = splitext(filename)[1] # type: Optional[str]
- if not ext:
- ext = mimetypes.guess_extension(content_type)
- if ext:
- filename += ext
- if not ext and link.url != resp.url:
- ext = os.path.splitext(resp.url)[1]
- if ext:
- filename += ext
- file_path = os.path.join(temp_dir, filename)
- with open(file_path, 'wb') as content_file:
- _download_url(resp, link, content_file, hashes, progress_bar)
- return file_path, content_type
-
-
-def _check_download_dir(link, download_dir, hashes):
- # type: (Link, str, Optional[Hashes]) -> Optional[str]
- """ Check download_dir for previously downloaded file with correct hash
- If a correct file is found return its path else None
- """
- download_path = os.path.join(download_dir, link.filename)
- if os.path.exists(download_path):
- # If already downloaded, does its hash match?
- logger.info('File was already downloaded %s', download_path)
- if hashes:
- try:
- hashes.check_against_path(download_path)
- except HashMismatch:
- logger.warning(
- 'Previously-downloaded file %s has bad hash. '
- 'Re-downloading.',
- download_path
- )
- os.unlink(download_path)
- return None
- return download_path
- return None
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/exceptions.py b/venv/lib/python3.8/site-packages/pip/_internal/exceptions.py
index 096adcd..3f26215 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/exceptions.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/exceptions.py
@@ -1,4 +1,5 @@
"""Exceptions used throughout package"""
+
from __future__ import absolute_import
from itertools import chain, groupby, repeat
@@ -8,10 +9,20 @@ from pip._vendor.six import iteritems
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
if MYPY_CHECK_RUNNING:
- from typing import Optional
+ from typing import Any, Optional, List, Dict, Text
+
from pip._vendor.pkg_resources import Distribution
+ from pip._vendor.requests.models import Response, Request
+ from pip._vendor.six import PY3
+ from pip._vendor.six.moves import configparser
+
from pip._internal.req.req_install import InstallRequirement
+ if PY3:
+ from hashlib import _Hash
+ else:
+ from hashlib import _hash as _Hash
+
class PipError(Exception):
"""Base pip exception"""
@@ -80,10 +91,38 @@ class CommandError(PipError):
"""Raised when there is an error in command-line arguments"""
+class SubProcessError(PipError):
+ """Raised when there is an error raised while executing a
+ command in subprocess"""
+
+
class PreviousBuildDirError(PipError):
"""Raised when there's a previous conflicting build directory"""
+class NetworkConnectionError(PipError):
+ """HTTP connection error"""
+
+ def __init__(self, error_msg, response=None, request=None):
+ # type: (Text, Response, Request) -> None
+ """
+ Initialize NetworkConnectionError with `request` and `response`
+ objects.
+ """
+ self.response = response
+ self.request = request
+ self.error_msg = error_msg
+ if (self.response is not None and not self.request and
+ hasattr(response, 'request')):
+ self.request = self.response.request
+ super(NetworkConnectionError, self).__init__(
+ error_msg, response, request)
+
+ def __str__(self):
+ # type: () -> str
+ return str(self.error_msg)
+
+
class InvalidWheelFilename(InstallationError):
"""Invalid wheel filename."""
@@ -92,16 +131,39 @@ class UnsupportedWheel(InstallationError):
"""Unsupported wheel."""
+class MetadataInconsistent(InstallationError):
+ """Built metadata contains inconsistent information.
+
+ This is raised when the metadata contains values (e.g. name and version)
+ that do not match the information previously obtained from sdist filename
+ or user-supplied ``#egg=`` value.
+ """
+ def __init__(self, ireq, field, built):
+ # type: (InstallRequirement, str, Any) -> None
+ self.ireq = ireq
+ self.field = field
+ self.built = built
+
+ def __str__(self):
+ # type: () -> str
+ return "Requested {} has different {} in metadata: {!r}".format(
+ self.ireq, self.field, self.built,
+ )
+
+
class HashErrors(InstallationError):
"""Multiple HashError instances rolled into one for reporting"""
def __init__(self):
- self.errors = []
+ # type: () -> None
+ self.errors = [] # type: List[HashError]
def append(self, error):
+ # type: (HashError) -> None
self.errors.append(error)
def __str__(self):
+ # type: () -> str
lines = []
self.errors.sort(key=lambda e: e.order)
for cls, errors_of_cls in groupby(self.errors, lambda e: e.__class__):
@@ -109,11 +171,14 @@ class HashErrors(InstallationError):
lines.extend(e.body() for e in errors_of_cls)
if lines:
return '\n'.join(lines)
+ return ''
def __nonzero__(self):
+ # type: () -> bool
return bool(self.errors)
def __bool__(self):
+ # type: () -> bool
return self.__nonzero__()
@@ -135,23 +200,27 @@ class HashError(InstallationError):
"""
req = None # type: Optional[InstallRequirement]
head = ''
+ order = None # type: Optional[int]
def body(self):
+ # type: () -> str
"""Return a summary of me for display under the heading.
This default implementation simply prints a description of the
triggering requirement.
:param req: The InstallRequirement that provoked this error, with
- populate_link() having already been called
+ its link already populated by the resolver's _populate_link().
"""
- return ' %s' % self._requirement_name()
+ return ' {}'.format(self._requirement_name())
def __str__(self):
- return '%s\n%s' % (self.head, self.body())
+ # type: () -> str
+ return '{}\n{}'.format(self.head, self.body())
def _requirement_name(self):
+ # type: () -> str
"""Return a description of the requirement that triggered me.
This default implementation returns long description of the req, with
@@ -192,6 +261,7 @@ class HashMissing(HashError):
'has a hash.)')
def __init__(self, gotten_hash):
+ # type: (str) -> None
"""
:param gotten_hash: The hash of the (possibly malicious) archive we
just downloaded
@@ -199,6 +269,7 @@ class HashMissing(HashError):
self.gotten_hash = gotten_hash
def body(self):
+ # type: () -> str
# Dodge circular import.
from pip._internal.utils.hashes import FAVORITE_HASH
@@ -211,9 +282,9 @@ class HashMissing(HashError):
# In case someone feeds something downright stupid
# to InstallRequirement's constructor.
else getattr(self.req, 'req', None))
- return ' %s --hash=%s:%s' % (package or 'unknown package',
- FAVORITE_HASH,
- self.gotten_hash)
+ return ' {} --hash={}:{}'.format(package or 'unknown package',
+ FAVORITE_HASH,
+ self.gotten_hash)
class HashUnpinned(HashError):
@@ -241,6 +312,7 @@ class HashMismatch(HashError):
'someone may have tampered with them.')
def __init__(self, allowed, gots):
+ # type: (Dict[str, List[str]], Dict[str, _Hash]) -> None
"""
:param allowed: A dict of algorithm names pointing to lists of allowed
hex digests
@@ -251,10 +323,12 @@ class HashMismatch(HashError):
self.gots = gots
def body(self):
- return ' %s:\n%s' % (self._requirement_name(),
- self._hash_comparison())
+ # type: () -> str
+ return ' {}:\n{}'.format(self._requirement_name(),
+ self._hash_comparison())
def _hash_comparison(self):
+ # type: () -> str
"""
Return a comparison of actual and expected hash values.
@@ -266,18 +340,18 @@ class HashMismatch(HashError):
"""
def hash_then_or(hash_name):
+ # type: (str) -> chain[str]
# For now, all the decent hashes have 6-char names, so we can get
# away with hard-coding space literals.
return chain([hash_name], repeat(' or'))
- lines = []
+ lines = [] # type: List[str]
for hash_name, expecteds in iteritems(self.allowed):
prefix = hash_then_or(hash_name)
- lines.extend((' Expected %s %s' % (next(prefix), e))
+ lines.extend((' Expected {} {}'.format(next(prefix), e))
for e in expecteds)
- lines.append(' Got %s\n' %
- self.gots[hash_name].hexdigest())
- prefix = ' or'
+ lines.append(' Got {}\n'.format(
+ self.gots[hash_name].hexdigest()))
return '\n'.join(lines)
@@ -291,15 +365,17 @@ class ConfigurationFileCouldNotBeLoaded(ConfigurationError):
"""
def __init__(self, reason="could not be loaded", fname=None, error=None):
+ # type: (str, Optional[str], Optional[configparser.Error]) -> None
super(ConfigurationFileCouldNotBeLoaded, self).__init__(error)
self.reason = reason
self.fname = fname
self.error = error
def __str__(self):
+ # type: () -> str
if self.fname is not None:
message_part = " in {}.".format(self.fname)
else:
assert self.error is not None
- message_part = ".\n{}\n".format(self.error.message)
+ message_part = ".\n{}\n".format(self.error)
return "Configuration file {}{}".format(self.reason, message_part)
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/index.py b/venv/lib/python3.8/site-packages/pip/_internal/index.py
deleted file mode 100644
index a1aaad5..0000000
--- a/venv/lib/python3.8/site-packages/pip/_internal/index.py
+++ /dev/null
@@ -1,1508 +0,0 @@
-"""Routines related to PyPI, indexes"""
-from __future__ import absolute_import
-
-import cgi
-import itertools
-import logging
-import mimetypes
-import os
-import re
-
-from pip._vendor import html5lib, requests, six
-from pip._vendor.distlib.compat import unescape
-from pip._vendor.packaging import specifiers
-from pip._vendor.packaging.utils import canonicalize_name
-from pip._vendor.packaging.version import parse as parse_version
-from pip._vendor.requests.exceptions import HTTPError, RetryError, SSLError
-from pip._vendor.six.moves.urllib import parse as urllib_parse
-from pip._vendor.six.moves.urllib import request as urllib_request
-
-from pip._internal.download import is_url, url_to_path
-from pip._internal.exceptions import (
- BestVersionAlreadyInstalled, DistributionNotFound, InvalidWheelFilename,
- UnsupportedWheel,
-)
-from pip._internal.models.candidate import InstallationCandidate
-from pip._internal.models.format_control import FormatControl
-from pip._internal.models.link import Link
-from pip._internal.models.selection_prefs import SelectionPreferences
-from pip._internal.models.target_python import TargetPython
-from pip._internal.utils.compat import ipaddress
-from pip._internal.utils.logging import indent_log
-from pip._internal.utils.misc import (
- ARCHIVE_EXTENSIONS, SUPPORTED_EXTENSIONS, WHEEL_EXTENSION, path_to_url,
- redact_password_from_url,
-)
-from pip._internal.utils.packaging import check_requires_python
-from pip._internal.utils.typing import MYPY_CHECK_RUNNING
-from pip._internal.wheel import Wheel
-
-if MYPY_CHECK_RUNNING:
- from logging import Logger
- from typing import (
- Any, Callable, FrozenSet, Iterable, Iterator, List, MutableMapping,
- Optional, Sequence, Set, Text, Tuple, Union,
- )
- import xml.etree.ElementTree
- from pip._vendor.packaging.version import _BaseVersion
- from pip._vendor.requests import Response
- from pip._internal.models.search_scope import SearchScope
- from pip._internal.req import InstallRequirement
- from pip._internal.download import PipSession
- from pip._internal.pep425tags import Pep425Tag
- from pip._internal.utils.hashes import Hashes
-
- BuildTag = Tuple[Any, ...] # either empty tuple or Tuple[int, str]
- CandidateSortingKey = (
- Tuple[int, int, int, _BaseVersion, BuildTag, Optional[int]]
- )
- HTMLElement = xml.etree.ElementTree.Element
- SecureOrigin = Tuple[str, str, Optional[str]]
-
-
-__all__ = ['FormatControl', 'FoundCandidates', 'PackageFinder']
-
-
-SECURE_ORIGINS = [
- # protocol, hostname, port
- # Taken from Chrome's list of secure origins (See: http://bit.ly/1qrySKC)
- ("https", "*", "*"),
- ("*", "localhost", "*"),
- ("*", "127.0.0.0/8", "*"),
- ("*", "::1/128", "*"),
- ("file", "*", None),
- # ssh is always secure.
- ("ssh", "*", "*"),
-] # type: List[SecureOrigin]
-
-
-logger = logging.getLogger(__name__)
-
-
-def _match_vcs_scheme(url):
- # type: (str) -> Optional[str]
- """Look for VCS schemes in the URL.
-
- Returns the matched VCS scheme, or None if there's no match.
- """
- from pip._internal.vcs import vcs
- for scheme in vcs.schemes:
- if url.lower().startswith(scheme) and url[len(scheme)] in '+:':
- return scheme
- return None
-
-
-def _is_url_like_archive(url):
- # type: (str) -> bool
- """Return whether the URL looks like an archive.
- """
- filename = Link(url).filename
- for bad_ext in ARCHIVE_EXTENSIONS:
- if filename.endswith(bad_ext):
- return True
- return False
-
-
-class _NotHTML(Exception):
- def __init__(self, content_type, request_desc):
- # type: (str, str) -> None
- super(_NotHTML, self).__init__(content_type, request_desc)
- self.content_type = content_type
- self.request_desc = request_desc
-
-
-def _ensure_html_header(response):
- # type: (Response) -> None
- """Check the Content-Type header to ensure the response contains HTML.
-
- Raises `_NotHTML` if the content type is not text/html.
- """
- content_type = response.headers.get("Content-Type", "")
- if not content_type.lower().startswith("text/html"):
- raise _NotHTML(content_type, response.request.method)
-
-
-class _NotHTTP(Exception):
- pass
-
-
-def _ensure_html_response(url, session):
- # type: (str, PipSession) -> None
- """Send a HEAD request to the URL, and ensure the response contains HTML.
-
- Raises `_NotHTTP` if the URL is not available for a HEAD request, or
- `_NotHTML` if the content type is not text/html.
- """
- scheme, netloc, path, query, fragment = urllib_parse.urlsplit(url)
- if scheme not in {'http', 'https'}:
- raise _NotHTTP()
-
- resp = session.head(url, allow_redirects=True)
- resp.raise_for_status()
-
- _ensure_html_header(resp)
-
-
-def _get_html_response(url, session):
- # type: (str, PipSession) -> Response
- """Access an HTML page with GET, and return the response.
-
- This consists of three parts:
-
- 1. If the URL looks suspiciously like an archive, send a HEAD first to
- check the Content-Type is HTML, to avoid downloading a large file.
- Raise `_NotHTTP` if the content type cannot be determined, or
- `_NotHTML` if it is not HTML.
- 2. Actually perform the request. Raise HTTP exceptions on network failures.
- 3. Check the Content-Type header to make sure we got HTML, and raise
- `_NotHTML` otherwise.
- """
- if _is_url_like_archive(url):
- _ensure_html_response(url, session=session)
-
- logger.debug('Getting page %s', redact_password_from_url(url))
-
- resp = session.get(
- url,
- headers={
- "Accept": "text/html",
- # We don't want to blindly returned cached data for
- # /simple/, because authors generally expecting that
- # twine upload && pip install will function, but if
- # they've done a pip install in the last ~10 minutes
- # it won't. Thus by setting this to zero we will not
- # blindly use any cached data, however the benefit of
- # using max-age=0 instead of no-cache, is that we will
- # still support conditional requests, so we will still
- # minimize traffic sent in cases where the page hasn't
- # changed at all, we will just always incur the round
- # trip for the conditional GET now instead of only
- # once per 10 minutes.
- # For more information, please see pypa/pip#5670.
- "Cache-Control": "max-age=0",
- },
- )
- resp.raise_for_status()
-
- # The check for archives above only works if the url ends with
- # something that looks like an archive. However that is not a
- # requirement of an url. Unless we issue a HEAD request on every
- # url we cannot know ahead of time for sure if something is HTML
- # or not. However we can check after we've downloaded it.
- _ensure_html_header(resp)
-
- return resp
-
-
-def _handle_get_page_fail(
- link, # type: Link
- reason, # type: Union[str, Exception]
- meth=None # type: Optional[Callable[..., None]]
-):
- # type: (...) -> None
- if meth is None:
- meth = logger.debug
- meth("Could not fetch URL %s: %s - skipping", link, reason)
-
-
-def _get_html_page(link, session=None):
- # type: (Link, Optional[PipSession]) -> Optional[HTMLPage]
- if session is None:
- raise TypeError(
- "_get_html_page() missing 1 required keyword argument: 'session'"
- )
-
- url = link.url.split('#', 1)[0]
-
- # Check for VCS schemes that do not support lookup as web pages.
- vcs_scheme = _match_vcs_scheme(url)
- if vcs_scheme:
- logger.debug('Cannot look at %s URL %s', vcs_scheme, link)
- return None
-
- # Tack index.html onto file:// URLs that point to directories
- scheme, _, path, _, _, _ = urllib_parse.urlparse(url)
- if (scheme == 'file' and os.path.isdir(urllib_request.url2pathname(path))):
- # add trailing slash if not present so urljoin doesn't trim
- # final segment
- if not url.endswith('/'):
- url += '/'
- url = urllib_parse.urljoin(url, 'index.html')
- logger.debug(' file: URL is directory, getting %s', url)
-
- try:
- resp = _get_html_response(url, session=session)
- except _NotHTTP:
- logger.debug(
- 'Skipping page %s because it looks like an archive, and cannot '
- 'be checked by HEAD.', link,
- )
- except _NotHTML as exc:
- logger.debug(
- 'Skipping page %s because the %s request got Content-Type: %s',
- link, exc.request_desc, exc.content_type,
- )
- except HTTPError as exc:
- _handle_get_page_fail(link, exc)
- except RetryError as exc:
- _handle_get_page_fail(link, exc)
- except SSLError as exc:
- reason = "There was a problem confirming the ssl certificate: "
- reason += str(exc)
- _handle_get_page_fail(link, reason, meth=logger.info)
- except requests.ConnectionError as exc:
- _handle_get_page_fail(link, "connection error: %s" % exc)
- except requests.Timeout:
- _handle_get_page_fail(link, "timed out")
- else:
- return HTMLPage(resp.content, resp.url, resp.headers)
- return None
-
-
-def _check_link_requires_python(
- link, # type: Link
- version_info, # type: Tuple[int, int, int]
- ignore_requires_python=False, # type: bool
-):
- # type: (...) -> bool
- """
- Return whether the given Python version is compatible with a link's
- "Requires-Python" value.
-
- :param version_info: A 3-tuple of ints representing the Python
- major-minor-micro version to check.
- :param ignore_requires_python: Whether to ignore the "Requires-Python"
- value if the given Python version isn't compatible.
- """
- try:
- is_compatible = check_requires_python(
- link.requires_python, version_info=version_info,
- )
- except specifiers.InvalidSpecifier:
- logger.debug(
- "Ignoring invalid Requires-Python (%r) for link: %s",
- link.requires_python, link,
- )
- else:
- if not is_compatible:
- version = '.'.join(map(str, version_info))
- if not ignore_requires_python:
- logger.debug(
- 'Link requires a different Python (%s not in: %r): %s',
- version, link.requires_python, link,
- )
- return False
-
- logger.debug(
- 'Ignoring failed Requires-Python check (%s not in: %r) '
- 'for link: %s',
- version, link.requires_python, link,
- )
-
- return True
-
-
-class LinkEvaluator(object):
-
- """
- Responsible for evaluating links for a particular project.
- """
-
- _py_version_re = re.compile(r'-py([123]\.?[0-9]?)$')
-
- # Don't include an allow_yanked default value to make sure each call
- # site considers whether yanked releases are allowed. This also causes
- # that decision to be made explicit in the calling code, which helps
- # people when reading the code.
- def __init__(
- self,
- project_name, # type: str
- canonical_name, # type: str
- formats, # type: FrozenSet
- target_python, # type: TargetPython
- allow_yanked, # type: bool
- ignore_requires_python=None, # type: Optional[bool]
- ):
- # type: (...) -> None
- """
- :param project_name: The user supplied package name.
- :param canonical_name: The canonical package name.
- :param formats: The formats allowed for this package. Should be a set
- with 'binary' or 'source' or both in it.
- :param target_python: The target Python interpreter to use when
- evaluating link compatibility. This is used, for example, to
- check wheel compatibility, as well as when checking the Python
- version, e.g. the Python version embedded in a link filename
- (or egg fragment) and against an HTML link's optional PEP 503
- "data-requires-python" attribute.
- :param allow_yanked: Whether files marked as yanked (in the sense
- of PEP 592) are permitted to be candidates for install.
- :param ignore_requires_python: Whether to ignore incompatible
- PEP 503 "data-requires-python" values in HTML links. Defaults
- to False.
- """
- if ignore_requires_python is None:
- ignore_requires_python = False
-
- self._allow_yanked = allow_yanked
- self._canonical_name = canonical_name
- self._ignore_requires_python = ignore_requires_python
- self._formats = formats
- self._target_python = target_python
-
- self.project_name = project_name
-
- def evaluate_link(self, link):
- # type: (Link) -> Tuple[bool, Optional[Text]]
- """
- Determine whether a link is a candidate for installation.
-
- :return: A tuple (is_candidate, result), where `result` is (1) a
- version string if `is_candidate` is True, and (2) if
- `is_candidate` is False, an optional string to log the reason
- the link fails to qualify.
- """
- version = None
- if link.is_yanked and not self._allow_yanked:
- reason = link.yanked_reason or ''
- # Mark this as a unicode string to prevent "UnicodeEncodeError:
- # 'ascii' codec can't encode character" in Python 2 when
- # the reason contains non-ascii characters.
- return (False, u'yanked for reason: {}'.format(reason))
-
- if link.egg_fragment:
- egg_info = link.egg_fragment
- ext = link.ext
- else:
- egg_info, ext = link.splitext()
- if not ext:
- return (False, 'not a file')
- if ext not in SUPPORTED_EXTENSIONS:
- return (False, 'unsupported archive format: %s' % ext)
- if "binary" not in self._formats and ext == WHEEL_EXTENSION:
- reason = 'No binaries permitted for %s' % self.project_name
- return (False, reason)
- if "macosx10" in link.path and ext == '.zip':
- return (False, 'macosx10 one')
- if ext == WHEEL_EXTENSION:
- try:
- wheel = Wheel(link.filename)
- except InvalidWheelFilename:
- return (False, 'invalid wheel filename')
- if canonicalize_name(wheel.name) != self._canonical_name:
- reason = 'wrong project name (not %s)' % self.project_name
- return (False, reason)
-
- supported_tags = self._target_python.get_tags()
- if not wheel.supported(supported_tags):
- # Include the wheel's tags in the reason string to
- # simplify troubleshooting compatibility issues.
- file_tags = wheel.get_formatted_file_tags()
- reason = (
- "none of the wheel's tags match: {}".format(
- ', '.join(file_tags)
- )
- )
- return (False, reason)
-
- version = wheel.version
-
- # This should be up by the self.ok_binary check, but see issue 2700.
- if "source" not in self._formats and ext != WHEEL_EXTENSION:
- return (False, 'No sources permitted for %s' % self.project_name)
-
- if not version:
- version = _extract_version_from_fragment(
- egg_info, self._canonical_name,
- )
- if not version:
- return (
- False, 'Missing project version for %s' % self.project_name,
- )
-
- match = self._py_version_re.search(version)
- if match:
- version = version[:match.start()]
- py_version = match.group(1)
- if py_version != self._target_python.py_version:
- return (False, 'Python version is incorrect')
-
- supports_python = _check_link_requires_python(
- link, version_info=self._target_python.py_version_info,
- ignore_requires_python=self._ignore_requires_python,
- )
- if not supports_python:
- # Return None for the reason text to suppress calling
- # _log_skipped_link().
- return (False, None)
-
- logger.debug('Found link %s, version: %s', link, version)
-
- return (True, version)
-
-
-def filter_unallowed_hashes(
- candidates, # type: List[InstallationCandidate]
- hashes, # type: Hashes
- project_name, # type: str
-):
- # type: (...) -> List[InstallationCandidate]
- """
- Filter out candidates whose hashes aren't allowed, and return a new
- list of candidates.
-
- If at least one candidate has an allowed hash, then all candidates with
- either an allowed hash or no hash specified are returned. Otherwise,
- the given candidates are returned.
-
- Including the candidates with no hash specified when there is a match
- allows a warning to be logged if there is a more preferred candidate
- with no hash specified. Returning all candidates in the case of no
- matches lets pip report the hash of the candidate that would otherwise
- have been installed (e.g. permitting the user to more easily update
- their requirements file with the desired hash).
- """
- if not hashes:
- logger.debug(
- 'Given no hashes to check %s links for project %r: '
- 'discarding no candidates',
- len(candidates),
- project_name,
- )
- # Make sure we're not returning back the given value.
- return list(candidates)
-
- matches_or_no_digest = []
- # Collect the non-matches for logging purposes.
- non_matches = []
- match_count = 0
- for candidate in candidates:
- link = candidate.link
- if not link.has_hash:
- pass
- elif link.is_hash_allowed(hashes=hashes):
- match_count += 1
- else:
- non_matches.append(candidate)
- continue
-
- matches_or_no_digest.append(candidate)
-
- if match_count:
- filtered = matches_or_no_digest
- else:
- # Make sure we're not returning back the given value.
- filtered = list(candidates)
-
- if len(filtered) == len(candidates):
- discard_message = 'discarding no candidates'
- else:
- discard_message = 'discarding {} non-matches:\n {}'.format(
- len(non_matches),
- '\n '.join(str(candidate.link) for candidate in non_matches)
- )
-
- logger.debug(
- 'Checked %s links for project %r against %s hashes '
- '(%s matches, %s no digest): %s',
- len(candidates),
- project_name,
- hashes.digest_count,
- match_count,
- len(matches_or_no_digest) - match_count,
- discard_message
- )
-
- return filtered
-
-
-class CandidatePreferences(object):
-
- """
- Encapsulates some of the preferences for filtering and sorting
- InstallationCandidate objects.
- """
-
- def __init__(
- self,
- prefer_binary=False, # type: bool
- allow_all_prereleases=False, # type: bool
- ):
- # type: (...) -> None
- """
- :param allow_all_prereleases: Whether to allow all pre-releases.
- """
- self.allow_all_prereleases = allow_all_prereleases
- self.prefer_binary = prefer_binary
-
-
-class CandidateEvaluator(object):
-
- """
- Responsible for filtering and sorting candidates for installation based
- on what tags are valid.
- """
-
- @classmethod
- def create(
- cls,
- project_name, # type: str
- target_python=None, # type: Optional[TargetPython]
- prefer_binary=False, # type: bool
- allow_all_prereleases=False, # type: bool
- specifier=None, # type: Optional[specifiers.BaseSpecifier]
- hashes=None, # type: Optional[Hashes]
- ):
- # type: (...) -> CandidateEvaluator
- """Create a CandidateEvaluator object.
-
- :param target_python: The target Python interpreter to use when
- checking compatibility. If None (the default), a TargetPython
- object will be constructed from the running Python.
- :param hashes: An optional collection of allowed hashes.
- """
- if target_python is None:
- target_python = TargetPython()
- if specifier is None:
- specifier = specifiers.SpecifierSet()
-
- supported_tags = target_python.get_tags()
-
- return cls(
- project_name=project_name,
- supported_tags=supported_tags,
- specifier=specifier,
- prefer_binary=prefer_binary,
- allow_all_prereleases=allow_all_prereleases,
- hashes=hashes,
- )
-
- def __init__(
- self,
- project_name, # type: str
- supported_tags, # type: List[Pep425Tag]
- specifier, # type: specifiers.BaseSpecifier
- prefer_binary=False, # type: bool
- allow_all_prereleases=False, # type: bool
- hashes=None, # type: Optional[Hashes]
- ):
- # type: (...) -> None
- """
- :param supported_tags: The PEP 425 tags supported by the target
- Python in order of preference (most preferred first).
- """
- self._allow_all_prereleases = allow_all_prereleases
- self._hashes = hashes
- self._prefer_binary = prefer_binary
- self._project_name = project_name
- self._specifier = specifier
- self._supported_tags = supported_tags
-
- def get_applicable_candidates(
- self,
- candidates, # type: List[InstallationCandidate]
- ):
- # type: (...) -> List[InstallationCandidate]
- """
- Return the applicable candidates from a list of candidates.
- """
- # Using None infers from the specifier instead.
- allow_prereleases = self._allow_all_prereleases or None
- specifier = self._specifier
- versions = {
- str(v) for v in specifier.filter(
- # We turn the version object into a str here because otherwise
- # when we're debundled but setuptools isn't, Python will see
- # packaging.version.Version and
- # pkg_resources._vendor.packaging.version.Version as different
- # types. This way we'll use a str as a common data interchange
- # format. If we stop using the pkg_resources provided specifier
- # and start using our own, we can drop the cast to str().
- (str(c.version) for c in candidates),
- prereleases=allow_prereleases,
- )
- }
-
- # Again, converting version to str to deal with debundling.
- applicable_candidates = [
- c for c in candidates if str(c.version) in versions
- ]
-
- return filter_unallowed_hashes(
- candidates=applicable_candidates,
- hashes=self._hashes,
- project_name=self._project_name,
- )
-
- def make_found_candidates(
- self,
- candidates, # type: List[InstallationCandidate]
- ):
- # type: (...) -> FoundCandidates
- """
- Create and return a `FoundCandidates` instance.
-
- :param specifier: An optional object implementing `filter`
- (e.g. `packaging.specifiers.SpecifierSet`) to filter applicable
- versions.
- """
- applicable_candidates = self.get_applicable_candidates(candidates)
-
- return FoundCandidates(
- candidates,
- applicable_candidates=applicable_candidates,
- evaluator=self,
- )
-
- def _sort_key(self, candidate):
- # type: (InstallationCandidate) -> CandidateSortingKey
- """
- Function to pass as the `key` argument to a call to sorted() to sort
- InstallationCandidates by preference.
-
- Returns a tuple such that tuples sorting as greater using Python's
- default comparison operator are more preferred.
-
- The preference is as follows:
-
- First and foremost, candidates with allowed (matching) hashes are
- always preferred over candidates without matching hashes. This is
- because e.g. if the only candidate with an allowed hash is yanked,
- we still want to use that candidate.
-
- Second, excepting hash considerations, candidates that have been
- yanked (in the sense of PEP 592) are always less preferred than
- candidates that haven't been yanked. Then:
-
- If not finding wheels, they are sorted by version only.
- If finding wheels, then the sort order is by version, then:
- 1. existing installs
- 2. wheels ordered via Wheel.support_index_min(self._supported_tags)
- 3. source archives
- If prefer_binary was set, then all wheels are sorted above sources.
-
- Note: it was considered to embed this logic into the Link
- comparison operators, but then different sdist links
- with the same version, would have to be considered equal
- """
- valid_tags = self._supported_tags
- support_num = len(valid_tags)
- build_tag = tuple() # type: BuildTag
- binary_preference = 0
- link = candidate.link
- if link.is_wheel:
- # can raise InvalidWheelFilename
- wheel = Wheel(link.filename)
- if not wheel.supported(valid_tags):
- raise UnsupportedWheel(
- "%s is not a supported wheel for this platform. It "
- "can't be sorted." % wheel.filename
- )
- if self._prefer_binary:
- binary_preference = 1
- pri = -(wheel.support_index_min(valid_tags))
- if wheel.build_tag is not None:
- match = re.match(r'^(\d+)(.*)$', wheel.build_tag)
- build_tag_groups = match.groups()
- build_tag = (int(build_tag_groups[0]), build_tag_groups[1])
- else: # sdist
- pri = -(support_num)
- has_allowed_hash = int(link.is_hash_allowed(self._hashes))
- yank_value = -1 * int(link.is_yanked) # -1 for yanked.
- return (
- has_allowed_hash, yank_value, binary_preference, candidate.version,
- build_tag, pri,
- )
-
- def get_best_candidate(
- self,
- candidates, # type: List[InstallationCandidate]
- ):
- # type: (...) -> Optional[InstallationCandidate]
- """
- Return the best candidate per the instance's sort order, or None if
- no candidate is acceptable.
- """
- if not candidates:
- return None
-
- best_candidate = max(candidates, key=self._sort_key)
-
- # Log a warning per PEP 592 if necessary before returning.
- link = best_candidate.link
- if link.is_yanked:
- reason = link.yanked_reason or ''
- msg = (
- # Mark this as a unicode string to prevent
- # "UnicodeEncodeError: 'ascii' codec can't encode character"
- # in Python 2 when the reason contains non-ascii characters.
- u'The candidate selected for download or install is a '
- 'yanked version: {candidate}\n'
- 'Reason for being yanked: {reason}'
- ).format(candidate=best_candidate, reason=reason)
- logger.warning(msg)
-
- return best_candidate
-
-
-class FoundCandidates(object):
- """A collection of candidates, returned by `PackageFinder.find_candidates`.
-
- This class is only intended to be instantiated by CandidateEvaluator's
- `make_found_candidates()` method.
- """
-
- def __init__(
- self,
- candidates, # type: List[InstallationCandidate]
- applicable_candidates, # type: List[InstallationCandidate]
- evaluator, # type: CandidateEvaluator
- ):
- # type: (...) -> None
- """
- :param candidates: A sequence of all available candidates found.
- :param applicable_candidates: The applicable candidates.
- :param evaluator: A CandidateEvaluator object to sort applicable
- candidates by order of preference.
- """
- self._applicable_candidates = applicable_candidates
- self._candidates = candidates
- self._evaluator = evaluator
-
- def iter_all(self):
- # type: () -> Iterable[InstallationCandidate]
- """Iterate through all candidates.
- """
- return iter(self._candidates)
-
- def iter_applicable(self):
- # type: () -> Iterable[InstallationCandidate]
- """Iterate through the applicable candidates.
- """
- return iter(self._applicable_candidates)
-
- def get_best(self):
- # type: () -> Optional[InstallationCandidate]
- """Return the best candidate available, or None if no applicable
- candidates are found.
- """
- candidates = list(self.iter_applicable())
- return self._evaluator.get_best_candidate(candidates)
-
-
-class PackageFinder(object):
- """This finds packages.
-
- This is meant to match easy_install's technique for looking for
- packages, by reading pages and looking for appropriate links.
- """
-
- def __init__(
- self,
- search_scope, # type: SearchScope
- session, # type: PipSession
- target_python, # type: TargetPython
- allow_yanked, # type: bool
- format_control=None, # type: Optional[FormatControl]
- trusted_hosts=None, # type: Optional[List[str]]
- candidate_prefs=None, # type: CandidatePreferences
- ignore_requires_python=None, # type: Optional[bool]
- ):
- # type: (...) -> None
- """
- This constructor is primarily meant to be used by the create() class
- method and from tests.
-
- :param session: The Session to use to make requests.
- :param format_control: A FormatControl object, used to control
- the selection of source packages / binary packages when consulting
- the index and links.
- :param candidate_prefs: Options to use when creating a
- CandidateEvaluator object.
- """
- if trusted_hosts is None:
- trusted_hosts = []
- if candidate_prefs is None:
- candidate_prefs = CandidatePreferences()
-
- format_control = format_control or FormatControl(set(), set())
-
- self._allow_yanked = allow_yanked
- self._candidate_prefs = candidate_prefs
- self._ignore_requires_python = ignore_requires_python
- self._target_python = target_python
-
- self.search_scope = search_scope
- self.session = session
- self.format_control = format_control
- self.trusted_hosts = trusted_hosts
-
- # These are boring links that have already been logged somehow.
- self._logged_links = set() # type: Set[Link]
-
- # Don't include an allow_yanked default value to make sure each call
- # site considers whether yanked releases are allowed. This also causes
- # that decision to be made explicit in the calling code, which helps
- # people when reading the code.
- @classmethod
- def create(
- cls,
- search_scope, # type: SearchScope
- selection_prefs, # type: SelectionPreferences
- trusted_hosts=None, # type: Optional[List[str]]
- session=None, # type: Optional[PipSession]
- target_python=None, # type: Optional[TargetPython]
- ):
- # type: (...) -> PackageFinder
- """Create a PackageFinder.
-
- :param selection_prefs: The candidate selection preferences, as a
- SelectionPreferences object.
- :param trusted_hosts: Domains not to emit warnings for when not using
- HTTPS.
- :param session: The Session to use to make requests.
- :param target_python: The target Python interpreter to use when
- checking compatibility. If None (the default), a TargetPython
- object will be constructed from the running Python.
- """
- if session is None:
- raise TypeError(
- "PackageFinder.create() missing 1 required keyword argument: "
- "'session'"
- )
- if target_python is None:
- target_python = TargetPython()
-
- candidate_prefs = CandidatePreferences(
- prefer_binary=selection_prefs.prefer_binary,
- allow_all_prereleases=selection_prefs.allow_all_prereleases,
- )
-
- return cls(
- candidate_prefs=candidate_prefs,
- search_scope=search_scope,
- session=session,
- target_python=target_python,
- allow_yanked=selection_prefs.allow_yanked,
- format_control=selection_prefs.format_control,
- trusted_hosts=trusted_hosts,
- ignore_requires_python=selection_prefs.ignore_requires_python,
- )
-
- @property
- def find_links(self):
- # type: () -> List[str]
- return self.search_scope.find_links
-
- @property
- def index_urls(self):
- # type: () -> List[str]
- return self.search_scope.index_urls
-
- @property
- def allow_all_prereleases(self):
- # type: () -> bool
- return self._candidate_prefs.allow_all_prereleases
-
- def set_allow_all_prereleases(self):
- # type: () -> None
- self._candidate_prefs.allow_all_prereleases = True
-
- def add_trusted_host(self, host, source=None):
- # type: (str, Optional[str]) -> None
- """
- :param source: An optional source string, for logging where the host
- string came from.
- """
- # It is okay to add a previously added host because PipSession stores
- # the resulting prefixes in a dict.
- msg = 'adding trusted host: {!r}'.format(host)
- if source is not None:
- msg += ' (from {})'.format(source)
- logger.info(msg)
- self.session.add_insecure_host(host)
- if host in self.trusted_hosts:
- return
-
- self.trusted_hosts.append(host)
-
- def iter_secure_origins(self):
- # type: () -> Iterator[SecureOrigin]
- for secure_origin in SECURE_ORIGINS:
- yield secure_origin
- for host in self.trusted_hosts:
- yield ('*', host, '*')
-
- @staticmethod
- def _sort_locations(locations, expand_dir=False):
- # type: (Sequence[str], bool) -> Tuple[List[str], List[str]]
- """
- Sort locations into "files" (archives) and "urls", and return
- a pair of lists (files,urls)
- """
- files = []
- urls = []
-
- # puts the url for the given file path into the appropriate list
- def sort_path(path):
- url = path_to_url(path)
- if mimetypes.guess_type(url, strict=False)[0] == 'text/html':
- urls.append(url)
- else:
- files.append(url)
-
- for url in locations:
-
- is_local_path = os.path.exists(url)
- is_file_url = url.startswith('file:')
-
- if is_local_path or is_file_url:
- if is_local_path:
- path = url
- else:
- path = url_to_path(url)
- if os.path.isdir(path):
- if expand_dir:
- path = os.path.realpath(path)
- for item in os.listdir(path):
- sort_path(os.path.join(path, item))
- elif is_file_url:
- urls.append(url)
- else:
- logger.warning(
- "Path '{0}' is ignored: "
- "it is a directory.".format(path),
- )
- elif os.path.isfile(path):
- sort_path(path)
- else:
- logger.warning(
- "Url '%s' is ignored: it is neither a file "
- "nor a directory.", url,
- )
- elif is_url(url):
- # Only add url with clear scheme
- urls.append(url)
- else:
- logger.warning(
- "Url '%s' is ignored. It is either a non-existing "
- "path or lacks a specific scheme.", url,
- )
-
- return files, urls
-
- def _validate_secure_origin(self, logger, location):
- # type: (Logger, Link) -> bool
- # Determine if this url used a secure transport mechanism
- parsed = urllib_parse.urlparse(str(location))
- origin = (parsed.scheme, parsed.hostname, parsed.port)
-
- # The protocol to use to see if the protocol matches.
- # Don't count the repository type as part of the protocol: in
- # cases such as "git+ssh", only use "ssh". (I.e., Only verify against
- # the last scheme.)
- protocol = origin[0].rsplit('+', 1)[-1]
-
- # Determine if our origin is a secure origin by looking through our
- # hardcoded list of secure origins, as well as any additional ones
- # configured on this PackageFinder instance.
- for secure_origin in self.iter_secure_origins():
- if protocol != secure_origin[0] and secure_origin[0] != "*":
- continue
-
- try:
- # We need to do this decode dance to ensure that we have a
- # unicode object, even on Python 2.x.
- addr = ipaddress.ip_address(
- origin[1]
- if (
- isinstance(origin[1], six.text_type) or
- origin[1] is None
- )
- else origin[1].decode("utf8")
- )
- network = ipaddress.ip_network(
- secure_origin[1]
- if isinstance(secure_origin[1], six.text_type)
- # setting secure_origin[1] to proper Union[bytes, str]
- # creates problems in other places
- else secure_origin[1].decode("utf8") # type: ignore
- )
- except ValueError:
- # We don't have both a valid address or a valid network, so
- # we'll check this origin against hostnames.
- if (origin[1] and
- origin[1].lower() != secure_origin[1].lower() and
- secure_origin[1] != "*"):
- continue
- else:
- # We have a valid address and network, so see if the address
- # is contained within the network.
- if addr not in network:
- continue
-
- # Check to see if the port patches
- if (origin[2] != secure_origin[2] and
- secure_origin[2] != "*" and
- secure_origin[2] is not None):
- continue
-
- # If we've gotten here, then this origin matches the current
- # secure origin and we should return True
- return True
-
- # If we've gotten to this point, then the origin isn't secure and we
- # will not accept it as a valid location to search. We will however
- # log a warning that we are ignoring it.
- logger.warning(
- "The repository located at %s is not a trusted or secure host and "
- "is being ignored. If this repository is available via HTTPS we "
- "recommend you use HTTPS instead, otherwise you may silence "
- "this warning and allow it anyway with '--trusted-host %s'.",
- parsed.hostname,
- parsed.hostname,
- )
-
- return False
-
- def make_link_evaluator(self, project_name):
- # type: (str) -> LinkEvaluator
- canonical_name = canonicalize_name(project_name)
- formats = self.format_control.get_allowed_formats(canonical_name)
-
- return LinkEvaluator(
- project_name=project_name,
- canonical_name=canonical_name,
- formats=formats,
- target_python=self._target_python,
- allow_yanked=self._allow_yanked,
- ignore_requires_python=self._ignore_requires_python,
- )
-
- def find_all_candidates(self, project_name):
- # type: (str) -> List[InstallationCandidate]
- """Find all available InstallationCandidate for project_name
-
- This checks index_urls and find_links.
- All versions found are returned as an InstallationCandidate list.
-
- See LinkEvaluator.evaluate_link() for details on which files
- are accepted.
- """
- search_scope = self.search_scope
- index_locations = search_scope.get_index_urls_locations(project_name)
- index_file_loc, index_url_loc = self._sort_locations(index_locations)
- fl_file_loc, fl_url_loc = self._sort_locations(
- self.find_links, expand_dir=True,
- )
-
- file_locations = (Link(url) for url in itertools.chain(
- index_file_loc, fl_file_loc,
- ))
-
- # We trust every url that the user has given us whether it was given
- # via --index-url or --find-links.
- # We want to filter out any thing which does not have a secure origin.
- url_locations = [
- link for link in itertools.chain(
- (Link(url) for url in index_url_loc),
- (Link(url) for url in fl_url_loc),
- )
- if self._validate_secure_origin(logger, link)
- ]
-
- logger.debug('%d location(s) to search for versions of %s:',
- len(url_locations), project_name)
-
- for location in url_locations:
- logger.debug('* %s', location)
-
- link_evaluator = self.make_link_evaluator(project_name)
- find_links_versions = self._package_versions(
- link_evaluator,
- # We trust every directly linked archive in find_links
- (Link(url, '-f') for url in self.find_links),
- )
-
- page_versions = []
- for page in self._get_pages(url_locations, project_name):
- logger.debug('Analyzing links from page %s', page.url)
- with indent_log():
- page_versions.extend(
- self._package_versions(link_evaluator, page.iter_links())
- )
-
- file_versions = self._package_versions(link_evaluator, file_locations)
- if file_versions:
- file_versions.sort(reverse=True)
- logger.debug(
- 'Local files found: %s',
- ', '.join([
- url_to_path(candidate.link.url)
- for candidate in file_versions
- ])
- )
-
- # This is an intentional priority ordering
- return file_versions + find_links_versions + page_versions
-
- def make_candidate_evaluator(
- self,
- project_name, # type: str
- specifier=None, # type: Optional[specifiers.BaseSpecifier]
- hashes=None, # type: Optional[Hashes]
- ):
- # type: (...) -> CandidateEvaluator
- """Create a CandidateEvaluator object to use.
- """
- candidate_prefs = self._candidate_prefs
- return CandidateEvaluator.create(
- project_name=project_name,
- target_python=self._target_python,
- prefer_binary=candidate_prefs.prefer_binary,
- allow_all_prereleases=candidate_prefs.allow_all_prereleases,
- specifier=specifier,
- hashes=hashes,
- )
-
- def find_candidates(
- self,
- project_name, # type: str
- specifier=None, # type: Optional[specifiers.BaseSpecifier]
- hashes=None, # type: Optional[Hashes]
- ):
- # type: (...) -> FoundCandidates
- """Find matches for the given project and specifier.
-
- :param specifier: An optional object implementing `filter`
- (e.g. `packaging.specifiers.SpecifierSet`) to filter applicable
- versions.
-
- :return: A `FoundCandidates` instance.
- """
- candidates = self.find_all_candidates(project_name)
- candidate_evaluator = self.make_candidate_evaluator(
- project_name=project_name,
- specifier=specifier,
- hashes=hashes,
- )
- return candidate_evaluator.make_found_candidates(candidates)
-
- def find_requirement(self, req, upgrade):
- # type: (InstallRequirement, bool) -> Optional[Link]
- """Try to find a Link matching req
-
- Expects req, an InstallRequirement and upgrade, a boolean
- Returns a Link if found,
- Raises DistributionNotFound or BestVersionAlreadyInstalled otherwise
- """
- hashes = req.hashes(trust_internet=False)
- candidates = self.find_candidates(
- req.name, specifier=req.specifier, hashes=hashes,
- )
- best_candidate = candidates.get_best()
-
- installed_version = None # type: Optional[_BaseVersion]
- if req.satisfied_by is not None:
- installed_version = parse_version(req.satisfied_by.version)
-
- def _format_versions(cand_iter):
- # This repeated parse_version and str() conversion is needed to
- # handle different vendoring sources from pip and pkg_resources.
- # If we stop using the pkg_resources provided specifier and start
- # using our own, we can drop the cast to str().
- return ", ".join(sorted(
- {str(c.version) for c in cand_iter},
- key=parse_version,
- )) or "none"
-
- if installed_version is None and best_candidate is None:
- logger.critical(
- 'Could not find a version that satisfies the requirement %s '
- '(from versions: %s)',
- req,
- _format_versions(candidates.iter_all()),
- )
-
- raise DistributionNotFound(
- 'No matching distribution found for %s' % req
- )
-
- best_installed = False
- if installed_version and (
- best_candidate is None or
- best_candidate.version <= installed_version):
- best_installed = True
-
- if not upgrade and installed_version is not None:
- if best_installed:
- logger.debug(
- 'Existing installed version (%s) is most up-to-date and '
- 'satisfies requirement',
- installed_version,
- )
- else:
- logger.debug(
- 'Existing installed version (%s) satisfies requirement '
- '(most up-to-date version is %s)',
- installed_version,
- best_candidate.version,
- )
- return None
-
- if best_installed:
- # We have an existing version, and its the best version
- logger.debug(
- 'Installed version (%s) is most up-to-date (past versions: '
- '%s)',
- installed_version,
- _format_versions(candidates.iter_applicable()),
- )
- raise BestVersionAlreadyInstalled
-
- logger.debug(
- 'Using version %s (newest of versions: %s)',
- best_candidate.version,
- _format_versions(candidates.iter_applicable()),
- )
- return best_candidate.link
-
- def _get_pages(self, locations, project_name):
- # type: (Iterable[Link], str) -> Iterable[HTMLPage]
- """
- Yields (page, page_url) from the given locations, skipping
- locations that have errors.
- """
- seen = set() # type: Set[Link]
- for location in locations:
- if location in seen:
- continue
- seen.add(location)
-
- page = _get_html_page(location, session=self.session)
- if page is None:
- continue
-
- yield page
-
- def _sort_links(self, links):
- # type: (Iterable[Link]) -> List[Link]
- """
- Returns elements of links in order, non-egg links first, egg links
- second, while eliminating duplicates
- """
- eggs, no_eggs = [], []
- seen = set() # type: Set[Link]
- for link in links:
- if link not in seen:
- seen.add(link)
- if link.egg_fragment:
- eggs.append(link)
- else:
- no_eggs.append(link)
- return no_eggs + eggs
-
- def _log_skipped_link(self, link, reason):
- # type: (Link, Text) -> None
- if link not in self._logged_links:
- # Mark this as a unicode string to prevent "UnicodeEncodeError:
- # 'ascii' codec can't encode character" in Python 2 when
- # the reason contains non-ascii characters.
- # Also, put the link at the end so the reason is more visible
- # and because the link string is usually very long.
- logger.debug(u'Skipping link: %s: %s', reason, link)
- self._logged_links.add(link)
-
- def get_install_candidate(self, link_evaluator, link):
- # type: (LinkEvaluator, Link) -> Optional[InstallationCandidate]
- """
- If the link is a candidate for install, convert it to an
- InstallationCandidate and return it. Otherwise, return None.
- """
- is_candidate, result = link_evaluator.evaluate_link(link)
- if not is_candidate:
- if result:
- self._log_skipped_link(link, reason=result)
- return None
-
- return InstallationCandidate(
- project=link_evaluator.project_name,
- link=link,
- # Convert the Text result to str since InstallationCandidate
- # accepts str.
- version=str(result),
- )
-
- def _package_versions(self, link_evaluator, links):
- # type: (LinkEvaluator, Iterable[Link]) -> List[InstallationCandidate]
- result = []
- for link in self._sort_links(links):
- candidate = self.get_install_candidate(link_evaluator, link)
- if candidate is not None:
- result.append(candidate)
- return result
-
-
-def _find_name_version_sep(fragment, canonical_name):
- # type: (str, str) -> int
- """Find the separator's index based on the package's canonical name.
-
- :param fragment: A + filename "fragment" (stem) or
- egg fragment.
- :param canonical_name: The package's canonical name.
-
- This function is needed since the canonicalized name does not necessarily
- have the same length as the egg info's name part. An example::
-
- >>> fragment = 'foo__bar-1.0'
- >>> canonical_name = 'foo-bar'
- >>> _find_name_version_sep(fragment, canonical_name)
- 8
- """
- # Project name and version must be separated by one single dash. Find all
- # occurrences of dashes; if the string in front of it matches the canonical
- # name, this is the one separating the name and version parts.
- for i, c in enumerate(fragment):
- if c != "-":
- continue
- if canonicalize_name(fragment[:i]) == canonical_name:
- return i
- raise ValueError("{} does not match {}".format(fragment, canonical_name))
-
-
-def _extract_version_from_fragment(fragment, canonical_name):
- # type: (str, str) -> Optional[str]
- """Parse the version string from a + filename
- "fragment" (stem) or egg fragment.
-
- :param fragment: The string to parse. E.g. foo-2.1
- :param canonical_name: The canonicalized name of the package this
- belongs to.
- """
- try:
- version_start = _find_name_version_sep(fragment, canonical_name) + 1
- except ValueError:
- return None
- version = fragment[version_start:]
- if not version:
- return None
- return version
-
-
-def _determine_base_url(document, page_url):
- """Determine the HTML document's base URL.
-
- This looks for a `` `` tag in the HTML document. If present, its href
- attribute denotes the base URL of anchor tags in the document. If there is
- no such tag (or if it does not have a valid href attribute), the HTML
- file's URL is used as the base URL.
-
- :param document: An HTML document representation. The current
- implementation expects the result of ``html5lib.parse()``.
- :param page_url: The URL of the HTML document.
- """
- for base in document.findall(".//base"):
- href = base.get("href")
- if href is not None:
- return href
- return page_url
-
-
-def _get_encoding_from_headers(headers):
- """Determine if we have any encoding information in our headers.
- """
- if headers and "Content-Type" in headers:
- content_type, params = cgi.parse_header(headers["Content-Type"])
- if "charset" in params:
- return params['charset']
- return None
-
-
-def _clean_link(url):
- # type: (str) -> str
- """Makes sure a link is fully encoded. That is, if a ' ' shows up in
- the link, it will be rewritten to %20 (while not over-quoting
- % or other characters)."""
- # Split the URL into parts according to the general structure
- # `scheme://netloc/path;parameters?query#fragment`. Note that the
- # `netloc` can be empty and the URI will then refer to a local
- # filesystem path.
- result = urllib_parse.urlparse(url)
- # In both cases below we unquote prior to quoting to make sure
- # nothing is double quoted.
- if result.netloc == "":
- # On Windows the path part might contain a drive letter which
- # should not be quoted. On Linux where drive letters do not
- # exist, the colon should be quoted. We rely on urllib.request
- # to do the right thing here.
- path = urllib_request.pathname2url(
- urllib_request.url2pathname(result.path))
- else:
- # In addition to the `/` character we protect `@` so that
- # revision strings in VCS URLs are properly parsed.
- path = urllib_parse.quote(urllib_parse.unquote(result.path), safe="/@")
- return urllib_parse.urlunparse(result._replace(path=path))
-
-
-def _create_link_from_element(
- anchor, # type: HTMLElement
- page_url, # type: str
- base_url, # type: str
-):
- # type: (...) -> Optional[Link]
- """
- Convert an anchor element in a simple repository page to a Link.
- """
- href = anchor.get("href")
- if not href:
- return None
-
- url = _clean_link(urllib_parse.urljoin(base_url, href))
- pyrequire = anchor.get('data-requires-python')
- pyrequire = unescape(pyrequire) if pyrequire else None
-
- yanked_reason = anchor.get('data-yanked')
- if yanked_reason:
- # This is a unicode string in Python 2 (and 3).
- yanked_reason = unescape(yanked_reason)
-
- link = Link(
- url,
- comes_from=page_url,
- requires_python=pyrequire,
- yanked_reason=yanked_reason,
- )
-
- return link
-
-
-class HTMLPage(object):
- """Represents one page, along with its URL"""
-
- def __init__(self, content, url, headers=None):
- # type: (bytes, str, MutableMapping[str, str]) -> None
- self.content = content
- self.url = url
- self.headers = headers
-
- def __str__(self):
- return redact_password_from_url(self.url)
-
- def iter_links(self):
- # type: () -> Iterable[Link]
- """Yields all links in the page"""
- document = html5lib.parse(
- self.content,
- transport_encoding=_get_encoding_from_headers(self.headers),
- namespaceHTMLElements=False,
- )
- base_url = _determine_base_url(document, self.url)
- for anchor in document.findall(".//a"):
- link = _create_link_from_element(
- anchor,
- page_url=self.url,
- base_url=base_url,
- )
- if link is None:
- continue
- yield link
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/legacy_resolve.py b/venv/lib/python3.8/site-packages/pip/_internal/legacy_resolve.py
deleted file mode 100644
index 1d9229c..0000000
--- a/venv/lib/python3.8/site-packages/pip/_internal/legacy_resolve.py
+++ /dev/null
@@ -1,457 +0,0 @@
-"""Dependency Resolution
-
-The dependency resolution in pip is performed as follows:
-
-for top-level requirements:
- a. only one spec allowed per project, regardless of conflicts or not.
- otherwise a "double requirement" exception is raised
- b. they override sub-dependency requirements.
-for sub-dependencies
- a. "first found, wins" (where the order is breadth first)
-"""
-
-import logging
-import sys
-from collections import defaultdict
-from itertools import chain
-
-from pip._vendor.packaging import specifiers
-
-from pip._internal.exceptions import (
- BestVersionAlreadyInstalled, DistributionNotFound, HashError, HashErrors,
- UnsupportedPythonVersion,
-)
-from pip._internal.req.constructors import install_req_from_req_string
-from pip._internal.utils.logging import indent_log
-from pip._internal.utils.misc import (
- dist_in_usersite, ensure_dir, normalize_version_info,
-)
-from pip._internal.utils.packaging import (
- check_requires_python, get_requires_python,
-)
-from pip._internal.utils.typing import MYPY_CHECK_RUNNING
-
-if MYPY_CHECK_RUNNING:
- from typing import DefaultDict, List, Optional, Set, Tuple
- from pip._vendor import pkg_resources
-
- from pip._internal.cache import WheelCache
- from pip._internal.distributions import AbstractDistribution
- from pip._internal.download import PipSession
- from pip._internal.index import PackageFinder
- from pip._internal.operations.prepare import RequirementPreparer
- from pip._internal.req.req_install import InstallRequirement
- from pip._internal.req.req_set import RequirementSet
-
-logger = logging.getLogger(__name__)
-
-
-def _check_dist_requires_python(
- dist, # type: pkg_resources.Distribution
- version_info, # type: Tuple[int, int, int]
- ignore_requires_python=False, # type: bool
-):
- # type: (...) -> None
- """
- Check whether the given Python version is compatible with a distribution's
- "Requires-Python" value.
-
- :param version_info: A 3-tuple of ints representing the Python
- major-minor-micro version to check.
- :param ignore_requires_python: Whether to ignore the "Requires-Python"
- value if the given Python version isn't compatible.
-
- :raises UnsupportedPythonVersion: When the given Python version isn't
- compatible.
- """
- requires_python = get_requires_python(dist)
- try:
- is_compatible = check_requires_python(
- requires_python, version_info=version_info,
- )
- except specifiers.InvalidSpecifier as exc:
- logger.warning(
- "Package %r has an invalid Requires-Python: %s",
- dist.project_name, exc,
- )
- return
-
- if is_compatible:
- return
-
- version = '.'.join(map(str, version_info))
- if ignore_requires_python:
- logger.debug(
- 'Ignoring failed Requires-Python check for package %r: '
- '%s not in %r',
- dist.project_name, version, requires_python,
- )
- return
-
- raise UnsupportedPythonVersion(
- 'Package {!r} requires a different Python: {} not in {!r}'.format(
- dist.project_name, version, requires_python,
- ))
-
-
-class Resolver(object):
- """Resolves which packages need to be installed/uninstalled to perform \
- the requested operation without breaking the requirements of any package.
- """
-
- _allowed_strategies = {"eager", "only-if-needed", "to-satisfy-only"}
-
- def __init__(
- self,
- preparer, # type: RequirementPreparer
- session, # type: PipSession
- finder, # type: PackageFinder
- wheel_cache, # type: Optional[WheelCache]
- use_user_site, # type: bool
- ignore_dependencies, # type: bool
- ignore_installed, # type: bool
- ignore_requires_python, # type: bool
- force_reinstall, # type: bool
- isolated, # type: bool
- upgrade_strategy, # type: str
- use_pep517=None, # type: Optional[bool]
- py_version_info=None, # type: Optional[Tuple[int, ...]]
- ):
- # type: (...) -> None
- super(Resolver, self).__init__()
- assert upgrade_strategy in self._allowed_strategies
-
- if py_version_info is None:
- py_version_info = sys.version_info[:3]
- else:
- py_version_info = normalize_version_info(py_version_info)
-
- self._py_version_info = py_version_info
-
- self.preparer = preparer
- self.finder = finder
- self.session = session
-
- # NOTE: This would eventually be replaced with a cache that can give
- # information about both sdist and wheels transparently.
- self.wheel_cache = wheel_cache
-
- # This is set in resolve
- self.require_hashes = None # type: Optional[bool]
-
- self.upgrade_strategy = upgrade_strategy
- self.force_reinstall = force_reinstall
- self.isolated = isolated
- self.ignore_dependencies = ignore_dependencies
- self.ignore_installed = ignore_installed
- self.ignore_requires_python = ignore_requires_python
- self.use_user_site = use_user_site
- self.use_pep517 = use_pep517
-
- self._discovered_dependencies = \
- defaultdict(list) # type: DefaultDict[str, List]
-
- def resolve(self, requirement_set):
- # type: (RequirementSet) -> None
- """Resolve what operations need to be done
-
- As a side-effect of this method, the packages (and their dependencies)
- are downloaded, unpacked and prepared for installation. This
- preparation is done by ``pip.operations.prepare``.
-
- Once PyPI has static dependency metadata available, it would be
- possible to move the preparation to become a step separated from
- dependency resolution.
- """
- # make the wheelhouse
- if self.preparer.wheel_download_dir:
- ensure_dir(self.preparer.wheel_download_dir)
-
- # If any top-level requirement has a hash specified, enter
- # hash-checking mode, which requires hashes from all.
- root_reqs = (
- requirement_set.unnamed_requirements +
- list(requirement_set.requirements.values())
- )
- self.require_hashes = (
- requirement_set.require_hashes or
- any(req.has_hash_options for req in root_reqs)
- )
-
- # Display where finder is looking for packages
- search_scope = self.finder.search_scope
- locations = search_scope.get_formatted_locations()
- if locations:
- logger.info(locations)
-
- # Actually prepare the files, and collect any exceptions. Most hash
- # exceptions cannot be checked ahead of time, because
- # req.populate_link() needs to be called before we can make decisions
- # based on link type.
- discovered_reqs = [] # type: List[InstallRequirement]
- hash_errors = HashErrors()
- for req in chain(root_reqs, discovered_reqs):
- try:
- discovered_reqs.extend(
- self._resolve_one(requirement_set, req)
- )
- except HashError as exc:
- exc.req = req
- hash_errors.append(exc)
-
- if hash_errors:
- raise hash_errors
-
- def _is_upgrade_allowed(self, req):
- # type: (InstallRequirement) -> bool
- if self.upgrade_strategy == "to-satisfy-only":
- return False
- elif self.upgrade_strategy == "eager":
- return True
- else:
- assert self.upgrade_strategy == "only-if-needed"
- return req.is_direct
-
- def _set_req_to_reinstall(self, req):
- # type: (InstallRequirement) -> None
- """
- Set a requirement to be installed.
- """
- # Don't uninstall the conflict if doing a user install and the
- # conflict is not a user install.
- if not self.use_user_site or dist_in_usersite(req.satisfied_by):
- req.conflicts_with = req.satisfied_by
- req.satisfied_by = None
-
- # XXX: Stop passing requirement_set for options
- def _check_skip_installed(self, req_to_install):
- # type: (InstallRequirement) -> Optional[str]
- """Check if req_to_install should be skipped.
-
- This will check if the req is installed, and whether we should upgrade
- or reinstall it, taking into account all the relevant user options.
-
- After calling this req_to_install will only have satisfied_by set to
- None if the req_to_install is to be upgraded/reinstalled etc. Any
- other value will be a dist recording the current thing installed that
- satisfies the requirement.
-
- Note that for vcs urls and the like we can't assess skipping in this
- routine - we simply identify that we need to pull the thing down,
- then later on it is pulled down and introspected to assess upgrade/
- reinstalls etc.
-
- :return: A text reason for why it was skipped, or None.
- """
- if self.ignore_installed:
- return None
-
- req_to_install.check_if_exists(self.use_user_site)
- if not req_to_install.satisfied_by:
- return None
-
- if self.force_reinstall:
- self._set_req_to_reinstall(req_to_install)
- return None
-
- if not self._is_upgrade_allowed(req_to_install):
- if self.upgrade_strategy == "only-if-needed":
- return 'already satisfied, skipping upgrade'
- return 'already satisfied'
-
- # Check for the possibility of an upgrade. For link-based
- # requirements we have to pull the tree down and inspect to assess
- # the version #, so it's handled way down.
- if not req_to_install.link:
- try:
- self.finder.find_requirement(req_to_install, upgrade=True)
- except BestVersionAlreadyInstalled:
- # Then the best version is installed.
- return 'already up-to-date'
- except DistributionNotFound:
- # No distribution found, so we squash the error. It will
- # be raised later when we re-try later to do the install.
- # Why don't we just raise here?
- pass
-
- self._set_req_to_reinstall(req_to_install)
- return None
-
- def _get_abstract_dist_for(self, req):
- # type: (InstallRequirement) -> AbstractDistribution
- """Takes a InstallRequirement and returns a single AbstractDist \
- representing a prepared variant of the same.
- """
- assert self.require_hashes is not None, (
- "require_hashes should have been set in Resolver.resolve()"
- )
-
- if req.editable:
- return self.preparer.prepare_editable_requirement(
- req, self.require_hashes, self.use_user_site, self.finder,
- )
-
- # satisfied_by is only evaluated by calling _check_skip_installed,
- # so it must be None here.
- assert req.satisfied_by is None
- skip_reason = self._check_skip_installed(req)
-
- if req.satisfied_by:
- return self.preparer.prepare_installed_requirement(
- req, self.require_hashes, skip_reason
- )
-
- upgrade_allowed = self._is_upgrade_allowed(req)
- abstract_dist = self.preparer.prepare_linked_requirement(
- req, self.session, self.finder, upgrade_allowed,
- self.require_hashes
- )
-
- # NOTE
- # The following portion is for determining if a certain package is
- # going to be re-installed/upgraded or not and reporting to the user.
- # This should probably get cleaned up in a future refactor.
-
- # req.req is only avail after unpack for URL
- # pkgs repeat check_if_exists to uninstall-on-upgrade
- # (#14)
- if not self.ignore_installed:
- req.check_if_exists(self.use_user_site)
-
- if req.satisfied_by:
- should_modify = (
- self.upgrade_strategy != "to-satisfy-only" or
- self.force_reinstall or
- self.ignore_installed or
- req.link.scheme == 'file'
- )
- if should_modify:
- self._set_req_to_reinstall(req)
- else:
- logger.info(
- 'Requirement already satisfied (use --upgrade to upgrade):'
- ' %s', req,
- )
-
- return abstract_dist
-
- def _resolve_one(
- self,
- requirement_set, # type: RequirementSet
- req_to_install # type: InstallRequirement
- ):
- # type: (...) -> List[InstallRequirement]
- """Prepare a single requirements file.
-
- :return: A list of additional InstallRequirements to also install.
- """
- # Tell user what we are doing for this requirement:
- # obtain (editable), skipping, processing (local url), collecting
- # (remote url or package name)
- if req_to_install.constraint or req_to_install.prepared:
- return []
-
- req_to_install.prepared = True
-
- # register tmp src for cleanup in case something goes wrong
- requirement_set.reqs_to_cleanup.append(req_to_install)
-
- abstract_dist = self._get_abstract_dist_for(req_to_install)
-
- # Parse and return dependencies
- dist = abstract_dist.get_pkg_resources_distribution()
- # This will raise UnsupportedPythonVersion if the given Python
- # version isn't compatible with the distribution's Requires-Python.
- _check_dist_requires_python(
- dist, version_info=self._py_version_info,
- ignore_requires_python=self.ignore_requires_python,
- )
-
- more_reqs = [] # type: List[InstallRequirement]
-
- def add_req(subreq, extras_requested):
- sub_install_req = install_req_from_req_string(
- str(subreq),
- req_to_install,
- isolated=self.isolated,
- wheel_cache=self.wheel_cache,
- use_pep517=self.use_pep517
- )
- parent_req_name = req_to_install.name
- to_scan_again, add_to_parent = requirement_set.add_requirement(
- sub_install_req,
- parent_req_name=parent_req_name,
- extras_requested=extras_requested,
- )
- if parent_req_name and add_to_parent:
- self._discovered_dependencies[parent_req_name].append(
- add_to_parent
- )
- more_reqs.extend(to_scan_again)
-
- with indent_log():
- # We add req_to_install before its dependencies, so that we
- # can refer to it when adding dependencies.
- if not requirement_set.has_requirement(req_to_install.name):
- # 'unnamed' requirements will get added here
- req_to_install.is_direct = True
- requirement_set.add_requirement(
- req_to_install, parent_req_name=None,
- )
-
- if not self.ignore_dependencies:
- if req_to_install.extras:
- logger.debug(
- "Installing extra requirements: %r",
- ','.join(req_to_install.extras),
- )
- missing_requested = sorted(
- set(req_to_install.extras) - set(dist.extras)
- )
- for missing in missing_requested:
- logger.warning(
- '%s does not provide the extra \'%s\'',
- dist, missing
- )
-
- available_requested = sorted(
- set(dist.extras) & set(req_to_install.extras)
- )
- for subreq in dist.requires(available_requested):
- add_req(subreq, extras_requested=available_requested)
-
- if not req_to_install.editable and not req_to_install.satisfied_by:
- # XXX: --no-install leads this to report 'Successfully
- # downloaded' for only non-editable reqs, even though we took
- # action on them.
- requirement_set.successfully_downloaded.append(req_to_install)
-
- return more_reqs
-
- def get_installation_order(self, req_set):
- # type: (RequirementSet) -> List[InstallRequirement]
- """Create the installation order.
-
- The installation order is topological - requirements are installed
- before the requiring thing. We break cycles at an arbitrary point,
- and make no other guarantees.
- """
- # The current implementation, which we may change at any point
- # installs the user specified things in the order given, except when
- # dependencies must come earlier to achieve topological order.
- order = []
- ordered_reqs = set() # type: Set[InstallRequirement]
-
- def schedule(req):
- if req.satisfied_by or req in ordered_reqs:
- return
- if req.constraint:
- return
- ordered_reqs.add(req)
- for dep in self._discovered_dependencies[req.name]:
- schedule(dep)
- order.append(req)
-
- for install_req in req_set.requirements.values():
- schedule(install_req)
- return order
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/locations.py b/venv/lib/python3.8/site-packages/pip/_internal/locations.py
index 5f843d7..0c12354 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/locations.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/locations.py
@@ -1,4 +1,8 @@
"""Locations where we look for configs, install stuff, etc"""
+
+# The following comment should be removed at some point in the future.
+# mypy: strict-optional=False
+
from __future__ import absolute_import
import os
@@ -9,21 +13,35 @@ import sys
import sysconfig
from distutils import sysconfig as distutils_sysconfig
from distutils.command.install import SCHEME_KEYS # type: ignore
+from distutils.command.install import install as distutils_install_command
+from pip._internal.models.scheme import Scheme
from pip._internal.utils import appdirs
from pip._internal.utils.compat import WINDOWS
-from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING, cast
from pip._internal.utils.virtualenv import running_under_virtualenv
if MYPY_CHECK_RUNNING:
- from typing import Any, Union, Dict, List, Optional
+ from typing import Dict, List, Optional, Union
+
+ from distutils.cmd import Command as DistutilsCommand
# Application Directories
USER_CACHE_DIR = appdirs.user_cache_dir("pip")
+def get_major_minor_version():
+ # type: () -> str
+ """
+ Return the major-minor version of the current Python as a string, e.g.
+ "3.7" or "3.10".
+ """
+ return '{}.{}'.format(*sys.version_info)
+
+
def get_src_prefix():
+ # type: () -> str
if running_under_virtualenv():
src_prefix = os.path.join(sys.prefix, 'src')
else:
@@ -74,29 +92,25 @@ else:
bin_py = '/usr/local/bin'
-def distutils_scheme(dist_name, user=False, home=None, root=None,
- isolated=False, prefix=None):
- # type:(str, bool, str, str, bool, str) -> dict
+def distutils_scheme(
+ dist_name, user=False, home=None, root=None, isolated=False, prefix=None
+):
+ # type:(str, bool, str, str, bool, str) -> Dict[str, str]
"""
Return a distutils install scheme
"""
from distutils.dist import Distribution
- scheme = {}
-
- if isolated:
- extra_dist_args = {"script_args": ["--no-user-cfg"]}
- else:
- extra_dist_args = {}
dist_args = {'name': dist_name} # type: Dict[str, Union[str, List[str]]]
- dist_args.update(extra_dist_args)
+ if isolated:
+ dist_args["script_args"] = ["--no-user-cfg"]
d = Distribution(dist_args)
- # Ignoring, typeshed issue reported python/typeshed/issues/2567
d.parse_config_files()
- # NOTE: Ignoring type since mypy can't find attributes on 'Command'
- i = d.get_command_obj('install', create=True) # type: Any
- assert i is not None
+ obj = None # type: Optional[DistutilsCommand]
+ obj = d.get_command_obj('install', create=True)
+ assert obj is not None
+ i = cast(distutils_install_command, obj)
# NOTE: setting user or home has the side-effect of creating the home dir
# or user base for installations during finalize_options()
# ideally, we'd prefer a scheme class that has no side-effects.
@@ -109,6 +123,8 @@ def distutils_scheme(dist_name, user=False, home=None, root=None,
i.home = home or i.home
i.root = root or i.root
i.finalize_options()
+
+ scheme = {}
for key in SCHEME_KEYS:
scheme[key] = getattr(i, 'install_' + key)
@@ -117,17 +133,15 @@ def distutils_scheme(dist_name, user=False, home=None, root=None,
# platlib). Note, i.install_lib is *always* set after
# finalize_options(); we only want to override here if the user
# has explicitly requested it hence going back to the config
-
- # Ignoring, typeshed issue reported python/typeshed/issues/2567
- if 'install_lib' in d.get_option_dict('install'): # type: ignore
+ if 'install_lib' in d.get_option_dict('install'):
scheme.update(dict(purelib=i.install_lib, platlib=i.install_lib))
if running_under_virtualenv():
scheme['headers'] = os.path.join(
- sys.prefix,
+ i.prefix,
'include',
'site',
- 'python' + sys.version[:3],
+ 'python{}'.format(get_major_minor_version()),
dist_name,
)
@@ -140,3 +154,41 @@ def distutils_scheme(dist_name, user=False, home=None, root=None,
)
return scheme
+
+
+def get_scheme(
+ dist_name, # type: str
+ user=False, # type: bool
+ home=None, # type: Optional[str]
+ root=None, # type: Optional[str]
+ isolated=False, # type: bool
+ prefix=None, # type: Optional[str]
+):
+ # type: (...) -> Scheme
+ """
+ Get the "scheme" corresponding to the input parameters. The distutils
+ documentation provides the context for the available schemes:
+ https://docs.python.org/3/install/index.html#alternate-installation
+
+ :param dist_name: the name of the package to retrieve the scheme for, used
+ in the headers scheme path
+ :param user: indicates to use the "user" scheme
+ :param home: indicates to use the "home" scheme and provides the base
+ directory for the same
+ :param root: root under which other directories are re-based
+ :param isolated: equivalent to --no-user-cfg, i.e. do not consider
+ ~/.pydistutils.cfg (posix) or ~/pydistutils.cfg (non-posix) for
+ scheme paths
+ :param prefix: indicates to use the "prefix" scheme and provides the
+ base directory for the same
+ """
+ scheme = distutils_scheme(
+ dist_name, user, home, root, isolated, prefix
+ )
+ return Scheme(
+ platlib=scheme["platlib"],
+ purelib=scheme["purelib"],
+ headers=scheme["headers"],
+ scripts=scheme["scripts"],
+ data=scheme["data"],
+ )
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/__init__.cpython-38.pyc
index 9fe42a4..2f3f0dd 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/candidate.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/candidate.cpython-38.pyc
index 02d28d2..5c3d147 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/candidate.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/candidate.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/format_control.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/format_control.cpython-38.pyc
index 62e7023..a17b624 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/format_control.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/format_control.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/index.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/index.cpython-38.pyc
index eb396b2..8197db5 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/index.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/index.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/link.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/link.cpython-38.pyc
index 0158fbc..068adde 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/link.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/link.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-38.pyc
index be25041..bdab8d6 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-38.pyc
index 8fcc83f..3792be4 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/target_python.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/target_python.cpython-38.pyc
index fa47f73..3a76a1a 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/target_python.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/models/__pycache__/target_python.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/candidate.py b/venv/lib/python3.8/site-packages/pip/_internal/models/candidate.py
index 1b99690..9149e0f 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/models/candidate.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/models/candidate.py
@@ -6,31 +6,33 @@ from pip._internal.utils.typing import MYPY_CHECK_RUNNING
if MYPY_CHECK_RUNNING:
from pip._vendor.packaging.version import _BaseVersion
from pip._internal.models.link import Link
- from typing import Any
class InstallationCandidate(KeyBasedCompareMixin):
"""Represents a potential "candidate" for installation.
"""
- def __init__(self, project, version, link):
- # type: (Any, str, Link) -> None
- self.project = project
+ __slots__ = ["name", "version", "link"]
+
+ def __init__(self, name, version, link):
+ # type: (str, str, Link) -> None
+ self.name = name
self.version = parse_version(version) # type: _BaseVersion
self.link = link
super(InstallationCandidate, self).__init__(
- key=(self.project, self.version, self.link),
+ key=(self.name, self.version, self.link),
defining_class=InstallationCandidate
)
def __repr__(self):
# type: () -> str
return "".format(
- self.project, self.version, self.link,
+ self.name, self.version, self.link,
)
def __str__(self):
+ # type: () -> str
return '{!r} candidate (version {} at {})'.format(
- self.project, self.version, self.link,
+ self.name, self.version, self.link,
)
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/format_control.py b/venv/lib/python3.8/site-packages/pip/_internal/models/format_control.py
index 53138e4..c6275e7 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/models/format_control.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/models/format_control.py
@@ -1,5 +1,6 @@
from pip._vendor.packaging.utils import canonicalize_name
+from pip._internal.exceptions import CommandError
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
if MYPY_CHECK_RUNNING:
@@ -10,8 +11,10 @@ class FormatControl(object):
"""Helper for managing formats from which a package can be installed.
"""
+ __slots__ = ["no_binary", "only_binary"]
+
def __init__(self, no_binary=None, only_binary=None):
- # type: (Optional[Set], Optional[Set]) -> None
+ # type: (Optional[Set[str]], Optional[Set[str]]) -> None
if no_binary is None:
no_binary = set()
if only_binary is None:
@@ -21,12 +24,24 @@ class FormatControl(object):
self.only_binary = only_binary
def __eq__(self, other):
- return self.__dict__ == other.__dict__
+ # type: (object) -> bool
+ if not isinstance(other, self.__class__):
+ return NotImplemented
+
+ if self.__slots__ != other.__slots__:
+ return False
+
+ return all(
+ getattr(self, k) == getattr(other, k)
+ for k in self.__slots__
+ )
def __ne__(self, other):
+ # type: (object) -> bool
return not self.__eq__(other)
def __repr__(self):
+ # type: () -> str
return "{}({}, {})".format(
self.__class__.__name__,
self.no_binary,
@@ -35,7 +50,11 @@ class FormatControl(object):
@staticmethod
def handle_mutual_excludes(value, target, other):
- # type: (str, Optional[Set], Optional[Set]) -> None
+ # type: (str, Set[str], Set[str]) -> None
+ if value.startswith('-'):
+ raise CommandError(
+ "--no-binary / --only-binary option requires 1 argument."
+ )
new = value.split(',')
while ':all:' in new:
other.clear()
@@ -54,7 +73,7 @@ class FormatControl(object):
target.add(name)
def get_allowed_formats(self, canonical_name):
- # type: (str) -> FrozenSet
+ # type: (str) -> FrozenSet[str]
result = {"binary", "source"}
if canonical_name in self.only_binary:
result.discard('source')
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/index.py b/venv/lib/python3.8/site-packages/pip/_internal/models/index.py
index ead1efb..5b4a1fe 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/models/index.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/models/index.py
@@ -5,6 +5,9 @@ class PackageIndex(object):
"""Represents a Package Index and provides easier access to endpoints
"""
+ __slots__ = ['url', 'netloc', 'simple_url', 'pypi_url',
+ 'file_storage_domain']
+
def __init__(self, url, file_storage_domain):
# type: (str, str) -> None
super(PackageIndex, self).__init__()
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/link.py b/venv/lib/python3.8/site-packages/pip/_internal/models/link.py
index d42be28..c0d278a 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/models/link.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/models/link.py
@@ -1,18 +1,22 @@
+import os
import posixpath
import re
from pip._vendor.six.moves.urllib import parse as urllib_parse
+from pip._internal.utils.filetypes import WHEEL_EXTENSION
from pip._internal.utils.misc import (
- WHEEL_EXTENSION, path_to_url, redact_password_from_url,
- split_auth_from_netloc, splitext,
+ redact_auth_from_url,
+ split_auth_from_netloc,
+ splitext,
)
from pip._internal.utils.models import KeyBasedCompareMixin
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+from pip._internal.utils.urls import path_to_url, url_to_path
if MYPY_CHECK_RUNNING:
from typing import Optional, Text, Tuple, Union
- from pip._internal.index import HTMLPage
+ from pip._internal.index.collector import HTMLPage
from pip._internal.utils.hashes import Hashes
@@ -20,12 +24,22 @@ class Link(KeyBasedCompareMixin):
"""Represents a parsed link from a Package Index's simple URL
"""
+ __slots__ = [
+ "_parsed_url",
+ "_url",
+ "comes_from",
+ "requires_python",
+ "yanked_reason",
+ "cache_link_parsing",
+ ]
+
def __init__(
self,
url, # type: str
comes_from=None, # type: Optional[Union[str, HTMLPage]]
requires_python=None, # type: Optional[str]
yanked_reason=None, # type: Optional[Text]
+ cache_link_parsing=True, # type: bool
):
# type: (...) -> None
"""
@@ -42,6 +56,11 @@ class Link(KeyBasedCompareMixin):
a simple repository HTML link. If the file has been yanked but
no reason was provided, this should be the empty string. See
PEP 592 for more information and the specification.
+ :param cache_link_parsing: A flag that is used elsewhere to determine
+ whether resources retrieved from this link
+ should be cached. PyPI index urls should
+ generally have this set to False, for
+ example.
"""
# url can be a UNC windows share
@@ -59,19 +78,23 @@ class Link(KeyBasedCompareMixin):
super(Link, self).__init__(key=url, defining_class=Link)
+ self.cache_link_parsing = cache_link_parsing
+
def __str__(self):
+ # type: () -> str
if self.requires_python:
- rp = ' (requires-python:%s)' % self.requires_python
+ rp = ' (requires-python:{})'.format(self.requires_python)
else:
rp = ''
if self.comes_from:
- return '%s (from %s)%s' % (redact_password_from_url(self._url),
- self.comes_from, rp)
+ return '{} (from {}){}'.format(
+ redact_auth_from_url(self._url), self.comes_from, rp)
else:
- return redact_password_from_url(str(self._url))
+ return redact_auth_from_url(str(self._url))
def __repr__(self):
- return ' ' % self
+ # type: () -> str
+ return ' '.format(self)
@property
def url(self):
@@ -90,9 +113,15 @@ class Link(KeyBasedCompareMixin):
return netloc
name = urllib_parse.unquote(name)
- assert name, ('URL %r produced no filename' % self._url)
+ assert name, (
+ 'URL {self._url!r} produced no filename'.format(**locals()))
return name
+ @property
+ def file_path(self):
+ # type: () -> str
+ return url_to_path(self.url)
+
@property
def scheme(self):
# type: () -> str
@@ -168,27 +197,29 @@ class Link(KeyBasedCompareMixin):
@property
def show_url(self):
- # type: () -> Optional[str]
+ # type: () -> str
return posixpath.basename(self._url.split('#', 1)[0].split('?', 1)[0])
+ @property
+ def is_file(self):
+ # type: () -> bool
+ return self.scheme == 'file'
+
+ def is_existing_dir(self):
+ # type: () -> bool
+ return self.is_file and os.path.isdir(self.file_path)
+
@property
def is_wheel(self):
# type: () -> bool
return self.ext == WHEEL_EXTENSION
@property
- def is_artifact(self):
+ def is_vcs(self):
# type: () -> bool
- """
- Determines if this points to an actual artifact (e.g. a tarball) or if
- it points to an "abstract" thing like a path or a VCS location.
- """
from pip._internal.vcs import vcs
- if self.scheme in vcs.all_schemes:
- return False
-
- return True
+ return self.scheme in vcs.all_schemes
@property
def is_yanked(self):
@@ -197,6 +228,7 @@ class Link(KeyBasedCompareMixin):
@property
def has_hash(self):
+ # type: () -> bool
return self.hash_name is not None
def is_hash_allowed(self, hashes):
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/search_scope.py b/venv/lib/python3.8/site-packages/pip/_internal/models/search_scope.py
index 6215244..d732504 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/models/search_scope.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/models/search_scope.py
@@ -7,8 +7,8 @@ from pip._vendor.packaging.utils import canonicalize_name
from pip._vendor.six.moves.urllib import parse as urllib_parse
from pip._internal.models.index import PyPI
-from pip._internal.utils.compat import HAS_TLS
-from pip._internal.utils.misc import normalize_path, redact_password_from_url
+from pip._internal.utils.compat import has_tls
+from pip._internal.utils.misc import normalize_path, redact_auth_from_url
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
if MYPY_CHECK_RUNNING:
@@ -24,6 +24,8 @@ class SearchScope(object):
Encapsulates the locations that pip is configured to search.
"""
+ __slots__ = ["find_links", "index_urls"]
+
@classmethod
def create(
cls,
@@ -49,7 +51,7 @@ class SearchScope(object):
# If we don't have TLS enabled, then WARN if anyplace we're looking
# relies on TLS.
- if not HAS_TLS:
+ if not has_tls():
for link in itertools.chain(index_urls, built_find_links):
parsed = urllib_parse.urlparse(link)
if parsed.scheme == 'https':
@@ -77,15 +79,34 @@ class SearchScope(object):
def get_formatted_locations(self):
# type: () -> str
lines = []
+ redacted_index_urls = []
if self.index_urls and self.index_urls != [PyPI.simple_url]:
- lines.append(
- 'Looking in indexes: {}'.format(', '.join(
- redact_password_from_url(url) for url in self.index_urls))
- )
+ for url in self.index_urls:
+
+ redacted_index_url = redact_auth_from_url(url)
+
+ # Parse the URL
+ purl = urllib_parse.urlsplit(redacted_index_url)
+
+ # URL is generally invalid if scheme and netloc is missing
+ # there are issues with Python and URL parsing, so this test
+ # is a bit crude. See bpo-20271, bpo-23505. Python doesn't
+ # always parse invalid URLs correctly - it should raise
+ # exceptions for malformed URLs
+ if not purl.scheme and not purl.netloc:
+ logger.warning(
+ 'The index url "%s" seems invalid, '
+ 'please provide a scheme.', redacted_index_url)
+
+ redacted_index_urls.append(redacted_index_url)
+
+ lines.append('Looking in indexes: {}'.format(
+ ', '.join(redacted_index_urls)))
+
if self.find_links:
lines.append(
'Looking in links: {}'.format(', '.join(
- redact_password_from_url(url) for url in self.find_links))
+ redact_auth_from_url(url) for url in self.find_links))
)
return '\n'.join(lines)
@@ -98,6 +119,7 @@ class SearchScope(object):
"""
def mkurl_pypi_url(url):
+ # type: (str) -> str
loc = posixpath.join(
url,
urllib_parse.quote(canonicalize_name(project_name)))
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/selection_prefs.py b/venv/lib/python3.8/site-packages/pip/_internal/models/selection_prefs.py
index f58fdce..5db3ca9 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/models/selection_prefs.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/models/selection_prefs.py
@@ -6,12 +6,14 @@ if MYPY_CHECK_RUNNING:
class SelectionPreferences(object):
-
"""
Encapsulates the candidate selection preferences for downloading
and installing files.
"""
+ __slots__ = ['allow_yanked', 'allow_all_prereleases', 'format_control',
+ 'prefer_binary', 'ignore_requires_python']
+
# Don't include an allow_yanked default value to make sure each call
# site considers whether yanked releases are allowed. This also causes
# that decision to be made explicit in the calling code, which helps
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/models/target_python.py b/venv/lib/python3.8/site-packages/pip/_internal/models/target_python.py
index a23b79c..6d1ca79 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/models/target_python.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/models/target_python.py
@@ -1,12 +1,16 @@
import sys
-from pip._internal.pep425tags import get_supported, version_info_to_nodot
+from pip._internal.utils.compatibility_tags import (
+ get_supported,
+ version_info_to_nodot,
+)
from pip._internal.utils.misc import normalize_version_info
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
if MYPY_CHECK_RUNNING:
from typing import List, Optional, Tuple
- from pip._internal.pep425tags import Pep425Tag
+
+ from pip._vendor.packaging.tags import Tag
class TargetPython(object):
@@ -16,6 +20,16 @@ class TargetPython(object):
for a package install, download, etc.
"""
+ __slots__ = [
+ "_given_py_version_info",
+ "abi",
+ "implementation",
+ "platform",
+ "py_version",
+ "py_version_info",
+ "_valid_tags",
+ ]
+
def __init__(
self,
platform=None, # type: Optional[str]
@@ -33,10 +47,10 @@ class TargetPython(object):
:param py_version_info: An optional tuple of ints representing the
Python version information to use (e.g. `sys.version_info[:3]`).
This can have length 1, 2, or 3 when provided.
- :param abi: A string or None. This is passed to pep425tags.py's
+ :param abi: A string or None. This is passed to compatibility_tags.py's
get_supported() function as is.
:param implementation: A string or None. This is passed to
- pep425tags.py's get_supported() function as is.
+ compatibility_tags.py's get_supported() function as is.
"""
# Store the given py_version_info for when we call get_supported().
self._given_py_version_info = py_version_info
@@ -55,7 +69,7 @@ class TargetPython(object):
self.py_version_info = py_version_info
# This is used to cache the return value of get_tags().
- self._valid_tags = None # type: Optional[List[Pep425Tag]]
+ self._valid_tags = None # type: Optional[List[Tag]]
def format_given(self):
# type: () -> str
@@ -80,7 +94,7 @@ class TargetPython(object):
)
def get_tags(self):
- # type: () -> List[Pep425Tag]
+ # type: () -> List[Tag]
"""
Return the supported PEP 425 tags to check wheel candidates against.
@@ -91,12 +105,12 @@ class TargetPython(object):
# versions=None uses special default logic.
py_version_info = self._given_py_version_info
if py_version_info is None:
- versions = None
+ version = None
else:
- versions = [version_info_to_nodot(py_version_info)]
+ version = version_info_to_nodot(py_version_info)
tags = get_supported(
- versions=versions,
+ version=version,
platform=self.platform,
abi=self.abi,
impl=self.implementation,
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-38.pyc
index 5cdba66..1ced638 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/__pycache__/check.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/operations/__pycache__/check.cpython-38.pyc
index 43331db..db7cae8 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/operations/__pycache__/check.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/operations/__pycache__/check.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-38.pyc
index 2117e82..746dd14 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-38.pyc
index 53048fb..1d15676 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/check.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/check.py
index 7b8b369..0d59632 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/operations/check.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/operations/check.py
@@ -29,6 +29,7 @@ if MYPY_CHECK_RUNNING:
MissingDict = Dict[str, List[Missing]]
ConflictingDict = Dict[str, List[Conflicting]]
CheckResult = Tuple[MissingDict, ConflictingDict]
+ ConflictDetails = Tuple[PackageSet, CheckResult]
PackageDetails = namedtuple('PackageDetails', ['version', 'requires'])
@@ -47,9 +48,9 @@ def create_package_set_from_installed(**kwargs):
name = canonicalize_name(dist.project_name)
try:
package_set[name] = PackageDetails(dist.version, dist.requires())
- except RequirementParseError as e:
- # Don't crash on broken metadata
- logging.warning("Error parsing requirements for %s: %s", name, e)
+ except (OSError, RequirementParseError) as e:
+ # Don't crash on unreadable or broken metadata
+ logger.warning("Error parsing requirements for %s: %s", name, e)
problems = True
return package_set, problems
@@ -61,19 +62,16 @@ def check_package_set(package_set, should_ignore=None):
If should_ignore is passed, it should be a callable that takes a
package name and returns a boolean.
"""
- if should_ignore is None:
- def should_ignore(name):
- return False
- missing = dict()
- conflicting = dict()
+ missing = {}
+ conflicting = {}
for package_name in package_set:
# Info about dependencies of package_name
missing_deps = set() # type: Set[Missing]
conflicting_deps = set() # type: Set[Conflicting]
- if should_ignore(package_name):
+ if should_ignore and should_ignore(package_name):
continue
for req in package_set[package_name].requires:
@@ -102,7 +100,7 @@ def check_package_set(package_set, should_ignore=None):
def check_install_conflicts(to_install):
- # type: (List[InstallRequirement]) -> Tuple[PackageSet, CheckResult]
+ # type: (List[InstallRequirement]) -> ConflictDetails
"""For checking if the dependency graph would be consistent after \
installing given requirements
"""
@@ -135,6 +133,7 @@ def _simulate_installation_of(to_install, package_set):
abstract_dist = make_distribution_for_install_requirement(inst_req)
dist = abstract_dist.get_pkg_resources_distribution()
+ assert dist is not None
name = canonicalize_name(dist.key)
package_set[name] = PackageDetails(dist.version, dist.requires())
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py
index 6f5a3dd..ddb9cb2 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/operations/freeze.py
@@ -3,7 +3,6 @@ from __future__ import absolute_import
import collections
import logging
import os
-import re
from pip._vendor import six
from pip._vendor.packaging.utils import canonicalize_name
@@ -11,11 +10,17 @@ from pip._vendor.pkg_resources import RequirementParseError
from pip._internal.exceptions import BadCommand, InstallationError
from pip._internal.req.constructors import (
- install_req_from_editable, install_req_from_line,
+ install_req_from_editable,
+ install_req_from_line,
)
from pip._internal.req.req_file import COMMENT_RE
+from pip._internal.utils.direct_url_helpers import (
+ direct_url_as_pep440_direct_reference,
+ dist_get_direct_url,
+)
from pip._internal.utils.misc import (
- dist_is_editable, get_installed_distributions,
+ dist_is_editable,
+ get_installed_distributions,
)
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
@@ -37,10 +42,9 @@ logger = logging.getLogger(__name__)
def freeze(
requirement=None, # type: Optional[List[str]]
find_links=None, # type: Optional[List[str]]
- local_only=None, # type: Optional[bool]
- user_only=None, # type: Optional[bool]
+ local_only=False, # type: bool
+ user_only=False, # type: bool
paths=None, # type: Optional[List[str]]
- skip_regex=None, # type: Optional[str]
isolated=False, # type: bool
wheel_cache=None, # type: Optional[WheelCache]
exclude_editable=False, # type: bool
@@ -48,18 +52,17 @@ def freeze(
):
# type: (...) -> Iterator[str]
find_links = find_links or []
- skip_match = None
-
- if skip_regex:
- skip_match = re.compile(skip_regex).search
for link in find_links:
- yield '-f %s' % link
+ yield '-f {}'.format(link)
installations = {} # type: Dict[str, FrozenRequirement]
- for dist in get_installed_distributions(local_only=local_only,
- skip=(),
- user_only=user_only,
- paths=paths):
+
+ for dist in get_installed_distributions(
+ local_only=local_only,
+ skip=(),
+ user_only=user_only,
+ paths=paths
+ ):
try:
req = FrozenRequirement.from_dist(dist)
except RequirementParseError as exc:
@@ -74,7 +77,7 @@ def freeze(
continue
if exclude_editable and req.editable:
continue
- installations[req.name] = req
+ installations[req.canonical_name] = req
if requirement:
# the options that don't get turned into an InstallRequirement
@@ -90,16 +93,15 @@ def freeze(
for line in req_file:
if (not line.strip() or
line.strip().startswith('#') or
- (skip_match and skip_match(line)) or
line.startswith((
'-r', '--requirement',
- '-Z', '--always-unzip',
'-f', '--find-links',
'-i', '--index-url',
'--pre',
'--trusted-host',
'--process-dependency-links',
- '--extra-index-url'))):
+ '--extra-index-url',
+ '--use-feature'))):
line = line.rstrip()
if line not in emitted_options:
emitted_options.add(line)
@@ -114,13 +116,11 @@ def freeze(
line_req = install_req_from_editable(
line,
isolated=isolated,
- wheel_cache=wheel_cache,
)
else:
line_req = install_req_from_line(
COMMENT_RE.sub('', line).strip(),
isolated=isolated,
- wheel_cache=wheel_cache,
)
if not line_req.name:
@@ -133,22 +133,27 @@ def freeze(
" (add #egg=PackageName to the URL to avoid"
" this warning)"
)
- elif line_req.name not in installations:
- # either it's not installed, or it is installed
- # but has been processed already
- if not req_files[line_req.name]:
- logger.warning(
- "Requirement file [%s] contains %s, but "
- "package %r is not installed",
- req_file_path,
- COMMENT_RE.sub('', line).strip(), line_req.name
- )
- else:
- req_files[line_req.name].append(req_file_path)
else:
- yield str(installations[line_req.name]).rstrip()
- del installations[line_req.name]
- req_files[line_req.name].append(req_file_path)
+ line_req_canonical_name = canonicalize_name(
+ line_req.name)
+ if line_req_canonical_name not in installations:
+ # either it's not installed, or it is installed
+ # but has been processed already
+ if not req_files[line_req.name]:
+ logger.warning(
+ "Requirement file [%s] contains %s, but "
+ "package %r is not installed",
+ req_file_path,
+ COMMENT_RE.sub('', line).strip(),
+ line_req.name
+ )
+ else:
+ req_files[line_req.name].append(req_file_path)
+ else:
+ yield str(installations[
+ line_req_canonical_name]).rstrip()
+ del installations[line_req_canonical_name]
+ req_files[line_req.name].append(req_file_path)
# Warn about requirements that were included multiple times (in a
# single requirements file or in different requirements files).
@@ -163,7 +168,7 @@ def freeze(
)
for installation in sorted(
installations.values(), key=lambda x: x.name.lower()):
- if canonicalize_name(installation.name) not in skip:
+ if installation.canonical_name not in skip:
yield str(installation).rstrip()
@@ -233,6 +238,7 @@ class FrozenRequirement(object):
def __init__(self, name, req, editable, comments=()):
# type: (str, Union[str, Requirement], bool, Iterable[str]) -> None
self.name = name
+ self.canonical_name = canonicalize_name(name)
self.req = req
self.editable = editable
self.comments = comments
@@ -240,14 +246,27 @@ class FrozenRequirement(object):
@classmethod
def from_dist(cls, dist):
# type: (Distribution) -> FrozenRequirement
+ # TODO `get_requirement_info` is taking care of editable requirements.
+ # TODO This should be refactored when we will add detection of
+ # editable that provide .dist-info metadata.
req, editable, comments = get_requirement_info(dist)
+ if req is None and not editable:
+ # if PEP 610 metadata is present, attempt to use it
+ direct_url = dist_get_direct_url(dist)
+ if direct_url:
+ req = direct_url_as_pep440_direct_reference(
+ direct_url, dist.project_name
+ )
+ comments = []
if req is None:
+ # name==version requirement
req = dist.as_requirement()
return cls(dist.project_name, req, editable, comments=comments)
def __str__(self):
+ # type: () -> str
req = self.req
if self.editable:
- req = '-e %s' % req
+ req = '-e {}'.format(req)
return '\n'.join(list(self.comments) + [str(req)]) + '\n'
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/operations/prepare.py b/venv/lib/python3.8/site-packages/pip/_internal/operations/prepare.py
index 6cf5f0e..a5455fc 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/operations/prepare.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/operations/prepare.py
@@ -1,40 +1,319 @@
"""Prepares a distribution for installation
"""
-import logging
-import os
+# The following comment should be removed at some point in the future.
+# mypy: strict-optional=False
-from pip._vendor import requests
+import logging
+import mimetypes
+import os
+import shutil
+
+from pip._vendor.six import PY2
from pip._internal.distributions import (
make_distribution_for_install_requirement,
)
from pip._internal.distributions.installed import InstalledDistribution
-from pip._internal.download import (
- is_dir_url, is_file_url, is_vcs_url, unpack_url, url_to_path,
-)
from pip._internal.exceptions import (
- DirectoryUrlHashUnsupported, HashUnpinned, InstallationError,
- PreviousBuildDirError, VcsHashUnsupported,
+ DirectoryUrlHashUnsupported,
+ HashMismatch,
+ HashUnpinned,
+ InstallationError,
+ NetworkConnectionError,
+ PreviousBuildDirError,
+ VcsHashUnsupported,
)
-from pip._internal.utils.compat import expanduser
+from pip._internal.utils.filesystem import copy2_fixed
from pip._internal.utils.hashes import MissingHashes
from pip._internal.utils.logging import indent_log
-from pip._internal.utils.misc import display_path, normalize_path
+from pip._internal.utils.misc import (
+ display_path,
+ hide_url,
+ path_to_display,
+ rmtree,
+)
+from pip._internal.utils.temp_dir import TempDirectory
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+from pip._internal.utils.unpacking import unpack_file
+from pip._internal.vcs import vcs
if MYPY_CHECK_RUNNING:
- from typing import Optional
+ from typing import (
+ Callable, List, Optional, Tuple,
+ )
+
+ from mypy_extensions import TypedDict
from pip._internal.distributions import AbstractDistribution
- from pip._internal.download import PipSession
- from pip._internal.index import PackageFinder
+ from pip._internal.index.package_finder import PackageFinder
+ from pip._internal.models.link import Link
+ from pip._internal.network.download import Downloader
from pip._internal.req.req_install import InstallRequirement
from pip._internal.req.req_tracker import RequirementTracker
+ from pip._internal.utils.hashes import Hashes
+
+ if PY2:
+ CopytreeKwargs = TypedDict(
+ 'CopytreeKwargs',
+ {
+ 'ignore': Callable[[str, List[str]], List[str]],
+ 'symlinks': bool,
+ },
+ total=False,
+ )
+ else:
+ CopytreeKwargs = TypedDict(
+ 'CopytreeKwargs',
+ {
+ 'copy_function': Callable[[str, str], None],
+ 'ignore': Callable[[str, List[str]], List[str]],
+ 'ignore_dangling_symlinks': bool,
+ 'symlinks': bool,
+ },
+ total=False,
+ )
logger = logging.getLogger(__name__)
+def _get_prepared_distribution(
+ req, # type: InstallRequirement
+ req_tracker, # type: RequirementTracker
+ finder, # type: PackageFinder
+ build_isolation # type: bool
+):
+ # type: (...) -> AbstractDistribution
+ """Prepare a distribution for installation.
+ """
+ abstract_dist = make_distribution_for_install_requirement(req)
+ with req_tracker.track(req):
+ abstract_dist.prepare_distribution_metadata(finder, build_isolation)
+ return abstract_dist
+
+
+def unpack_vcs_link(link, location):
+ # type: (Link, str) -> None
+ vcs_backend = vcs.get_backend_for_scheme(link.scheme)
+ assert vcs_backend is not None
+ vcs_backend.unpack(location, url=hide_url(link.url))
+
+
+class File(object):
+ def __init__(self, path, content_type):
+ # type: (str, str) -> None
+ self.path = path
+ self.content_type = content_type
+
+
+def get_http_url(
+ link, # type: Link
+ downloader, # type: Downloader
+ download_dir=None, # type: Optional[str]
+ hashes=None, # type: Optional[Hashes]
+):
+ # type: (...) -> File
+ temp_dir = TempDirectory(kind="unpack", globally_managed=True)
+ # If a download dir is specified, is the file already downloaded there?
+ already_downloaded_path = None
+ if download_dir:
+ already_downloaded_path = _check_download_dir(
+ link, download_dir, hashes
+ )
+
+ if already_downloaded_path:
+ from_path = already_downloaded_path
+ content_type = mimetypes.guess_type(from_path)[0]
+ else:
+ # let's download to a tmp dir
+ from_path, content_type = _download_http_url(
+ link, downloader, temp_dir.path, hashes
+ )
+
+ return File(from_path, content_type)
+
+
+def _copy2_ignoring_special_files(src, dest):
+ # type: (str, str) -> None
+ """Copying special files is not supported, but as a convenience to users
+ we skip errors copying them. This supports tools that may create e.g.
+ socket files in the project source directory.
+ """
+ try:
+ copy2_fixed(src, dest)
+ except shutil.SpecialFileError as e:
+ # SpecialFileError may be raised due to either the source or
+ # destination. If the destination was the cause then we would actually
+ # care, but since the destination directory is deleted prior to
+ # copy we ignore all of them assuming it is caused by the source.
+ logger.warning(
+ "Ignoring special file error '%s' encountered copying %s to %s.",
+ str(e),
+ path_to_display(src),
+ path_to_display(dest),
+ )
+
+
+def _copy_source_tree(source, target):
+ # type: (str, str) -> None
+ target_abspath = os.path.abspath(target)
+ target_basename = os.path.basename(target_abspath)
+ target_dirname = os.path.dirname(target_abspath)
+
+ def ignore(d, names):
+ # type: (str, List[str]) -> List[str]
+ skipped = [] # type: List[str]
+ if d == source:
+ # Pulling in those directories can potentially be very slow,
+ # exclude the following directories if they appear in the top
+ # level dir (and only it).
+ # See discussion at https://github.com/pypa/pip/pull/6770
+ skipped += ['.tox', '.nox']
+ if os.path.abspath(d) == target_dirname:
+ # Prevent an infinite recursion if the target is in source.
+ # This can happen when TMPDIR is set to ${PWD}/...
+ # and we copy PWD to TMPDIR.
+ skipped += [target_basename]
+ return skipped
+
+ kwargs = dict(ignore=ignore, symlinks=True) # type: CopytreeKwargs
+
+ if not PY2:
+ # Python 2 does not support copy_function, so we only ignore
+ # errors on special file copy in Python 3.
+ kwargs['copy_function'] = _copy2_ignoring_special_files
+
+ shutil.copytree(source, target, **kwargs)
+
+
+def get_file_url(
+ link, # type: Link
+ download_dir=None, # type: Optional[str]
+ hashes=None # type: Optional[Hashes]
+):
+ # type: (...) -> File
+ """Get file and optionally check its hash.
+ """
+ # If a download dir is specified, is the file already there and valid?
+ already_downloaded_path = None
+ if download_dir:
+ already_downloaded_path = _check_download_dir(
+ link, download_dir, hashes
+ )
+
+ if already_downloaded_path:
+ from_path = already_downloaded_path
+ else:
+ from_path = link.file_path
+
+ # If --require-hashes is off, `hashes` is either empty, the
+ # link's embedded hash, or MissingHashes; it is required to
+ # match. If --require-hashes is on, we are satisfied by any
+ # hash in `hashes` matching: a URL-based or an option-based
+ # one; no internet-sourced hash will be in `hashes`.
+ if hashes:
+ hashes.check_against_path(from_path)
+
+ content_type = mimetypes.guess_type(from_path)[0]
+
+ return File(from_path, content_type)
+
+
+def unpack_url(
+ link, # type: Link
+ location, # type: str
+ downloader, # type: Downloader
+ download_dir=None, # type: Optional[str]
+ hashes=None, # type: Optional[Hashes]
+):
+ # type: (...) -> Optional[File]
+ """Unpack link into location, downloading if required.
+
+ :param hashes: A Hashes object, one of whose embedded hashes must match,
+ or HashMismatch will be raised. If the Hashes is empty, no matches are
+ required, and unhashable types of requirements (like VCS ones, which
+ would ordinarily raise HashUnsupported) are allowed.
+ """
+ # non-editable vcs urls
+ if link.is_vcs:
+ unpack_vcs_link(link, location)
+ return None
+
+ # If it's a url to a local directory
+ if link.is_existing_dir():
+ if os.path.isdir(location):
+ rmtree(location)
+ _copy_source_tree(link.file_path, location)
+ return None
+
+ # file urls
+ if link.is_file:
+ file = get_file_url(link, download_dir, hashes=hashes)
+
+ # http urls
+ else:
+ file = get_http_url(
+ link,
+ downloader,
+ download_dir,
+ hashes=hashes,
+ )
+
+ # unpack the archive to the build dir location. even when only downloading
+ # archives, they have to be unpacked to parse dependencies, except wheels
+ if not link.is_wheel:
+ unpack_file(file.path, location, file.content_type)
+
+ return file
+
+
+def _download_http_url(
+ link, # type: Link
+ downloader, # type: Downloader
+ temp_dir, # type: str
+ hashes, # type: Optional[Hashes]
+):
+ # type: (...) -> Tuple[str, str]
+ """Download link url into temp_dir using provided session"""
+ download = downloader(link)
+
+ file_path = os.path.join(temp_dir, download.filename)
+ with open(file_path, 'wb') as content_file:
+ for chunk in download.chunks:
+ content_file.write(chunk)
+
+ if hashes:
+ hashes.check_against_path(file_path)
+
+ return file_path, download.response.headers.get('content-type', '')
+
+
+def _check_download_dir(link, download_dir, hashes):
+ # type: (Link, str, Optional[Hashes]) -> Optional[str]
+ """ Check download_dir for previously downloaded file with correct hash
+ If a correct file is found return its path else None
+ """
+ download_path = os.path.join(download_dir, link.filename)
+
+ if not os.path.exists(download_path):
+ return None
+
+ # If already downloaded, does its hash match?
+ logger.info('File was already downloaded %s', download_path)
+ if hashes:
+ try:
+ hashes.check_against_path(download_path)
+ except HashMismatch:
+ logger.warning(
+ 'Previously-downloaded file %s has bad hash. '
+ 'Re-downloading.',
+ download_path
+ )
+ os.unlink(download_path)
+ return None
+ return download_path
+
+
class RequirementPreparer(object):
"""Prepares a Requirement
"""
@@ -45,9 +324,12 @@ class RequirementPreparer(object):
download_dir, # type: Optional[str]
src_dir, # type: str
wheel_download_dir, # type: Optional[str]
- progress_bar, # type: str
build_isolation, # type: bool
- req_tracker # type: RequirementTracker
+ req_tracker, # type: RequirementTracker
+ downloader, # type: Downloader
+ finder, # type: PackageFinder
+ require_hashes, # type: bool
+ use_user_site, # type: bool
):
# type: (...) -> None
super(RequirementPreparer, self).__init__()
@@ -55,16 +337,16 @@ class RequirementPreparer(object):
self.src_dir = src_dir
self.build_dir = build_dir
self.req_tracker = req_tracker
+ self.downloader = downloader
+ self.finder = finder
- # Where still packed archives should be written to. If None, they are
+ # Where still-packed archives should be written to. If None, they are
# not saved, and are deleted immediately after unpacking.
self.download_dir = download_dir
# Where still-packed .whl files should be written to. If None, they are
# written to the download_dir parameter. Separate to download_dir to
# permit only keeping wheel archives for pip wheel.
- if wheel_download_dir:
- wheel_download_dir = normalize_path(wheel_download_dir)
self.wheel_download_dir = wheel_download_dir
# NOTE
@@ -72,160 +354,156 @@ class RequirementPreparer(object):
# be combined if we're willing to have non-wheel archives present in
# the wheelhouse output by 'pip wheel'.
- self.progress_bar = progress_bar
-
# Is build isolation allowed?
self.build_isolation = build_isolation
+ # Should hash-checking be required?
+ self.require_hashes = require_hashes
+
+ # Should install in user site-packages?
+ self.use_user_site = use_user_site
+
@property
def _download_should_save(self):
# type: () -> bool
- # TODO: Modify to reduce indentation needed
- if self.download_dir:
- self.download_dir = expanduser(self.download_dir)
- if os.path.exists(self.download_dir):
- return True
- else:
- logger.critical('Could not find download directory')
- raise InstallationError(
- "Could not find or access download directory '%s'"
- % display_path(self.download_dir))
- return False
+ if not self.download_dir:
+ return False
- def prepare_linked_requirement(
- self,
- req, # type: InstallRequirement
- session, # type: PipSession
- finder, # type: PackageFinder
- upgrade_allowed, # type: bool
- require_hashes # type: bool
- ):
- # type: (...) -> AbstractDistribution
- """Prepare a requirement that would be obtained from req.link
- """
- # TODO: Breakup into smaller functions
- if req.link and req.link.scheme == 'file':
- path = url_to_path(req.link.url)
+ if os.path.exists(self.download_dir):
+ return True
+
+ logger.critical('Could not find download directory')
+ raise InstallationError(
+ "Could not find or access download directory '{}'"
+ .format(self.download_dir))
+
+ def _log_preparing_link(self, req):
+ # type: (InstallRequirement) -> None
+ """Log the way the link prepared."""
+ if req.link.is_file:
+ path = req.link.file_path
logger.info('Processing %s', display_path(path))
else:
- logger.info('Collecting %s', req)
+ logger.info('Collecting %s', req.req or req)
+
+ def _ensure_link_req_src_dir(self, req, download_dir, parallel_builds):
+ # type: (InstallRequirement, Optional[str], bool) -> None
+ """Ensure source_dir of a linked InstallRequirement."""
+ # Since source_dir is only set for editable requirements.
+ if req.link.is_wheel:
+ # We don't need to unpack wheels, so no need for a source
+ # directory.
+ return
+ assert req.source_dir is None
+ # We always delete unpacked sdists after pip runs.
+ req.ensure_has_source_dir(
+ self.build_dir,
+ autodelete=True,
+ parallel_builds=parallel_builds,
+ )
+
+ # If a checkout exists, it's unwise to keep going. version
+ # inconsistencies are logged later, but do not fail the
+ # installation.
+ # FIXME: this won't upgrade when there's an existing
+ # package unpacked in `req.source_dir`
+ if os.path.exists(os.path.join(req.source_dir, 'setup.py')):
+ raise PreviousBuildDirError(
+ "pip can't proceed with requirements '{}' due to a"
+ "pre-existing build directory ({}). This is likely "
+ "due to a previous installation that failed . pip is "
+ "being responsible and not assuming it can delete this. "
+ "Please delete it and try again.".format(req, req.source_dir)
+ )
+
+ def _get_linked_req_hashes(self, req):
+ # type: (InstallRequirement) -> Hashes
+ # By the time this is called, the requirement's link should have
+ # been checked so we can tell what kind of requirements req is
+ # and raise some more informative errors than otherwise.
+ # (For example, we can raise VcsHashUnsupported for a VCS URL
+ # rather than HashMissing.)
+ if not self.require_hashes:
+ return req.hashes(trust_internet=True)
+
+ # We could check these first 2 conditions inside unpack_url
+ # and save repetition of conditions, but then we would
+ # report less-useful error messages for unhashable
+ # requirements, complaining that there's no hash provided.
+ if req.link.is_vcs:
+ raise VcsHashUnsupported()
+ if req.link.is_existing_dir():
+ raise DirectoryUrlHashUnsupported()
+
+ # Unpinned packages are asking for trouble when a new version
+ # is uploaded. This isn't a security check, but it saves users
+ # a surprising hash mismatch in the future.
+ # file:/// URLs aren't pinnable, so don't complain about them
+ # not being pinned.
+ if req.original_link is None and not req.is_pinned:
+ raise HashUnpinned()
+
+ # If known-good hashes are missing for this requirement,
+ # shim it with a facade object that will provoke hash
+ # computation and then raise a HashMissing exception
+ # showing the user what the hash should be.
+ return req.hashes(trust_internet=False) or MissingHashes()
+
+ def prepare_linked_requirement(self, req, parallel_builds=False):
+ # type: (InstallRequirement, bool) -> AbstractDistribution
+ """Prepare a requirement to be obtained from req.link."""
+ assert req.link
+ link = req.link
+ self._log_preparing_link(req)
+ if link.is_wheel and self.wheel_download_dir:
+ # Download wheels to a dedicated dir when doing `pip wheel`.
+ download_dir = self.wheel_download_dir
+ else:
+ download_dir = self.download_dir
with indent_log():
- # @@ if filesystem packages are not marked
- # editable in a req, a non deterministic error
- # occurs when the script attempts to unpack the
- # build directory
- req.ensure_has_source_dir(self.build_dir)
- # If a checkout exists, it's unwise to keep going. version
- # inconsistencies are logged later, but do not fail the
- # installation.
- # FIXME: this won't upgrade when there's an existing
- # package unpacked in `req.source_dir`
- # package unpacked in `req.source_dir`
- if os.path.exists(os.path.join(req.source_dir, 'setup.py')):
- raise PreviousBuildDirError(
- "pip can't proceed with requirements '%s' due to a"
- " pre-existing build directory (%s). This is "
- "likely due to a previous installation that failed"
- ". pip is being responsible and not assuming it "
- "can delete this. Please delete it and try again."
- % (req, req.source_dir)
- )
- req.populate_link(finder, upgrade_allowed, require_hashes)
-
- # We can't hit this spot and have populate_link return None.
- # req.satisfied_by is None here (because we're
- # guarded) and upgrade has no impact except when satisfied_by
- # is not None.
- # Then inside find_requirement existing_applicable -> False
- # If no new versions are found, DistributionNotFound is raised,
- # otherwise a result is guaranteed.
- assert req.link
- link = req.link
-
- # Now that we have the real link, we can tell what kind of
- # requirements we have and raise some more informative errors
- # than otherwise. (For example, we can raise VcsHashUnsupported
- # for a VCS URL rather than HashMissing.)
- if require_hashes:
- # We could check these first 2 conditions inside
- # unpack_url and save repetition of conditions, but then
- # we would report less-useful error messages for
- # unhashable requirements, complaining that there's no
- # hash provided.
- if is_vcs_url(link):
- raise VcsHashUnsupported()
- elif is_file_url(link) and is_dir_url(link):
- raise DirectoryUrlHashUnsupported()
- if not req.original_link and not req.is_pinned:
- # Unpinned packages are asking for trouble when a new
- # version is uploaded. This isn't a security check, but
- # it saves users a surprising hash mismatch in the
- # future.
- #
- # file:/// URLs aren't pinnable, so don't complain
- # about them not being pinned.
- raise HashUnpinned()
-
- hashes = req.hashes(trust_internet=not require_hashes)
- if require_hashes and not hashes:
- # Known-good hashes are missing for this requirement, so
- # shim it with a facade object that will provoke hash
- # computation and then raise a HashMissing exception
- # showing the user what the hash should be.
- hashes = MissingHashes()
-
+ self._ensure_link_req_src_dir(req, download_dir, parallel_builds)
try:
- download_dir = self.download_dir
- # We always delete unpacked sdists after pip ran.
- autodelete_unpacked = True
- if req.link.is_wheel and self.wheel_download_dir:
- # when doing 'pip wheel` we download wheels to a
- # dedicated dir.
- download_dir = self.wheel_download_dir
- if req.link.is_wheel:
- if download_dir:
- # When downloading, we only unpack wheels to get
- # metadata.
- autodelete_unpacked = True
- else:
- # When installing a wheel, we use the unpacked
- # wheel.
- autodelete_unpacked = False
- unpack_url(
- req.link, req.source_dir,
- download_dir, autodelete_unpacked,
- session=session, hashes=hashes,
- progress_bar=self.progress_bar
- )
- except requests.HTTPError as exc:
- logger.critical(
- 'Could not install requirement %s because of error %s',
- req,
- exc,
+ local_file = unpack_url(
+ link, req.source_dir, self.downloader, download_dir,
+ hashes=self._get_linked_req_hashes(req)
)
+ except NetworkConnectionError as exc:
raise InstallationError(
- 'Could not install requirement %s because of HTTP '
- 'error %s for URL %s' %
- (req, exc, req.link)
- )
- abstract_dist = make_distribution_for_install_requirement(req)
- with self.req_tracker.track(req):
- abstract_dist.prepare_distribution_metadata(
- finder, self.build_isolation,
+ 'Could not install requirement {} because of HTTP '
+ 'error {} for URL {}'.format(req, exc, link)
)
+
+ # For use in later processing, preserve the file path on the
+ # requirement.
+ if local_file:
+ req.local_file_path = local_file.path
+
+ abstract_dist = _get_prepared_distribution(
+ req, self.req_tracker, self.finder, self.build_isolation,
+ )
+
+ if download_dir:
+ if link.is_existing_dir():
+ logger.info('Link is a directory, ignoring download_dir')
+ elif local_file:
+ download_location = os.path.join(
+ download_dir, link.filename
+ )
+ if not os.path.exists(download_location):
+ shutil.copy(local_file.path, download_location)
+ download_path = display_path(download_location)
+ logger.info('Saved %s', download_path)
+
if self._download_should_save:
# Make a .zip of the source_dir we already created.
- if not req.link.is_artifact:
+ if link.is_vcs:
req.archive(self.download_dir)
return abstract_dist
def prepare_editable_requirement(
self,
req, # type: InstallRequirement
- require_hashes, # type: bool
- use_user_site, # type: bool
- finder # type: PackageFinder
):
# type: (...) -> AbstractDistribution
"""Prepare an editable requirement
@@ -235,31 +513,28 @@ class RequirementPreparer(object):
logger.info('Obtaining %s', req)
with indent_log():
- if require_hashes:
+ if self.require_hashes:
raise InstallationError(
- 'The editable requirement %s cannot be installed when '
+ 'The editable requirement {} cannot be installed when '
'requiring hashes, because there is no single file to '
- 'hash.' % req
+ 'hash.'.format(req)
)
req.ensure_has_source_dir(self.src_dir)
req.update_editable(not self._download_should_save)
- abstract_dist = make_distribution_for_install_requirement(req)
- with self.req_tracker.track(req):
- abstract_dist.prepare_distribution_metadata(
- finder, self.build_isolation,
- )
+ abstract_dist = _get_prepared_distribution(
+ req, self.req_tracker, self.finder, self.build_isolation,
+ )
if self._download_should_save:
req.archive(self.download_dir)
- req.check_if_exists(use_user_site)
+ req.check_if_exists(self.use_user_site)
return abstract_dist
def prepare_installed_requirement(
self,
req, # type: InstallRequirement
- require_hashes, # type: bool
skip_reason # type: str
):
# type: (...) -> AbstractDistribution
@@ -268,14 +543,14 @@ class RequirementPreparer(object):
assert req.satisfied_by, "req should have been satisfied but isn't"
assert skip_reason is not None, (
"did not get skip reason skipped but req.satisfied_by "
- "is set to %r" % (req.satisfied_by,)
+ "is set to {}".format(req.satisfied_by)
)
logger.info(
'Requirement %s: %s (%s)',
skip_reason, req, req.satisfied_by.version
)
with indent_log():
- if require_hashes:
+ if self.require_hashes:
logger.debug(
'Since it is already installed, we are trusting this '
'package without checking its hash. To ensure a '
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/pep425tags.py b/venv/lib/python3.8/site-packages/pip/_internal/pep425tags.py
deleted file mode 100644
index c6e58bf..0000000
--- a/venv/lib/python3.8/site-packages/pip/_internal/pep425tags.py
+++ /dev/null
@@ -1,384 +0,0 @@
-"""Generate and work with PEP 425 Compatibility Tags."""
-from __future__ import absolute_import
-
-import distutils.util
-import logging
-import platform
-import re
-import sys
-import sysconfig
-import warnings
-from collections import OrderedDict
-
-import pip._internal.utils.glibc
-from pip._internal.utils.compat import get_extension_suffixes
-from pip._internal.utils.typing import MYPY_CHECK_RUNNING
-
-if MYPY_CHECK_RUNNING:
- from typing import (
- Tuple, Callable, List, Optional, Union, Dict
- )
-
- Pep425Tag = Tuple[str, str, str]
-
-logger = logging.getLogger(__name__)
-
-_osx_arch_pat = re.compile(r'(.+)_(\d+)_(\d+)_(.+)')
-
-
-def get_config_var(var):
- # type: (str) -> Optional[str]
- try:
- return sysconfig.get_config_var(var)
- except IOError as e: # Issue #1074
- warnings.warn("{}".format(e), RuntimeWarning)
- return None
-
-
-def get_abbr_impl():
- # type: () -> str
- """Return abbreviated implementation name."""
- if hasattr(sys, 'pypy_version_info'):
- pyimpl = 'pp'
- elif sys.platform.startswith('java'):
- pyimpl = 'jy'
- elif sys.platform == 'cli':
- pyimpl = 'ip'
- else:
- pyimpl = 'cp'
- return pyimpl
-
-
-def version_info_to_nodot(version_info):
- # type: (Tuple[int, ...]) -> str
- # Only use up to the first two numbers.
- return ''.join(map(str, version_info[:2]))
-
-
-def get_impl_ver():
- # type: () -> str
- """Return implementation version."""
- impl_ver = get_config_var("py_version_nodot")
- if not impl_ver or get_abbr_impl() == 'pp':
- impl_ver = ''.join(map(str, get_impl_version_info()))
- return impl_ver
-
-
-def get_impl_version_info():
- # type: () -> Tuple[int, ...]
- """Return sys.version_info-like tuple for use in decrementing the minor
- version."""
- if get_abbr_impl() == 'pp':
- # as per https://github.com/pypa/pip/issues/2882
- # attrs exist only on pypy
- return (sys.version_info[0],
- sys.pypy_version_info.major, # type: ignore
- sys.pypy_version_info.minor) # type: ignore
- else:
- return sys.version_info[0], sys.version_info[1]
-
-
-def get_impl_tag():
- # type: () -> str
- """
- Returns the Tag for this specific implementation.
- """
- return "{}{}".format(get_abbr_impl(), get_impl_ver())
-
-
-def get_flag(var, fallback, expected=True, warn=True):
- # type: (str, Callable[..., bool], Union[bool, int], bool) -> bool
- """Use a fallback method for determining SOABI flags if the needed config
- var is unset or unavailable."""
- val = get_config_var(var)
- if val is None:
- if warn:
- logger.debug("Config variable '%s' is unset, Python ABI tag may "
- "be incorrect", var)
- return fallback()
- return val == expected
-
-
-def get_abi_tag():
- # type: () -> Optional[str]
- """Return the ABI tag based on SOABI (if available) or emulate SOABI
- (CPython 2, PyPy)."""
- soabi = get_config_var('SOABI')
- impl = get_abbr_impl()
- if not soabi and impl in {'cp', 'pp'} and hasattr(sys, 'maxunicode'):
- d = ''
- m = ''
- u = ''
- is_cpython = (impl == 'cp')
- if get_flag(
- 'Py_DEBUG', lambda: hasattr(sys, 'gettotalrefcount'),
- warn=is_cpython):
- d = 'd'
- if sys.version_info < (3, 8) and get_flag(
- 'WITH_PYMALLOC', lambda: is_cpython, warn=is_cpython):
- m = 'm'
- if sys.version_info < (3, 3) and get_flag(
- 'Py_UNICODE_SIZE', lambda: sys.maxunicode == 0x10ffff,
- expected=4, warn=is_cpython):
- u = 'u'
- abi = '%s%s%s%s%s' % (impl, get_impl_ver(), d, m, u)
- elif soabi and soabi.startswith('cpython-'):
- abi = 'cp' + soabi.split('-')[1]
- elif soabi:
- abi = soabi.replace('.', '_').replace('-', '_')
- else:
- abi = None
- return abi
-
-
-def _is_running_32bit():
- # type: () -> bool
- return sys.maxsize == 2147483647
-
-
-def get_platform():
- # type: () -> str
- """Return our platform name 'win32', 'linux_x86_64'"""
- if sys.platform == 'darwin':
- # distutils.util.get_platform() returns the release based on the value
- # of MACOSX_DEPLOYMENT_TARGET on which Python was built, which may
- # be significantly older than the user's current machine.
- release, _, machine = platform.mac_ver()
- split_ver = release.split('.')
-
- if machine == "x86_64" and _is_running_32bit():
- machine = "i386"
- elif machine == "ppc64" and _is_running_32bit():
- machine = "ppc"
-
- return 'macosx_{}_{}_{}'.format(split_ver[0], split_ver[1], machine)
-
- # XXX remove distutils dependency
- result = distutils.util.get_platform().replace('.', '_').replace('-', '_')
- if result == "linux_x86_64" and _is_running_32bit():
- # 32 bit Python program (running on a 64 bit Linux): pip should only
- # install and run 32 bit compiled extensions in that case.
- result = "linux_i686"
-
- return result
-
-
-def is_manylinux1_compatible():
- # type: () -> bool
- # Only Linux, and only x86-64 / i686
- if get_platform() not in {"linux_x86_64", "linux_i686"}:
- return False
-
- # Check for presence of _manylinux module
- try:
- import _manylinux
- return bool(_manylinux.manylinux1_compatible)
- except (ImportError, AttributeError):
- # Fall through to heuristic check below
- pass
-
- # Check glibc version. CentOS 5 uses glibc 2.5.
- return pip._internal.utils.glibc.have_compatible_glibc(2, 5)
-
-
-def is_manylinux2010_compatible():
- # type: () -> bool
- # Only Linux, and only x86-64 / i686
- if get_platform() not in {"linux_x86_64", "linux_i686"}:
- return False
-
- # Check for presence of _manylinux module
- try:
- import _manylinux
- return bool(_manylinux.manylinux2010_compatible)
- except (ImportError, AttributeError):
- # Fall through to heuristic check below
- pass
-
- # Check glibc version. CentOS 6 uses glibc 2.12.
- return pip._internal.utils.glibc.have_compatible_glibc(2, 12)
-
-
-def get_darwin_arches(major, minor, machine):
- # type: (int, int, str) -> List[str]
- """Return a list of supported arches (including group arches) for
- the given major, minor and machine architecture of an macOS machine.
- """
- arches = []
-
- def _supports_arch(major, minor, arch):
- # type: (int, int, str) -> bool
- # Looking at the application support for macOS versions in the chart
- # provided by https://en.wikipedia.org/wiki/OS_X#Versions it appears
- # our timeline looks roughly like:
- #
- # 10.0 - Introduces ppc support.
- # 10.4 - Introduces ppc64, i386, and x86_64 support, however the ppc64
- # and x86_64 support is CLI only, and cannot be used for GUI
- # applications.
- # 10.5 - Extends ppc64 and x86_64 support to cover GUI applications.
- # 10.6 - Drops support for ppc64
- # 10.7 - Drops support for ppc
- #
- # Given that we do not know if we're installing a CLI or a GUI
- # application, we must be conservative and assume it might be a GUI
- # application and behave as if ppc64 and x86_64 support did not occur
- # until 10.5.
- #
- # Note: The above information is taken from the "Application support"
- # column in the chart not the "Processor support" since I believe
- # that we care about what instruction sets an application can use
- # not which processors the OS supports.
- if arch == 'ppc':
- return (major, minor) <= (10, 5)
- if arch == 'ppc64':
- return (major, minor) == (10, 5)
- if arch == 'i386':
- return (major, minor) >= (10, 4)
- if arch == 'x86_64':
- return (major, minor) >= (10, 5)
- if arch in groups:
- for garch in groups[arch]:
- if _supports_arch(major, minor, garch):
- return True
- return False
-
- groups = OrderedDict([
- ("fat", ("i386", "ppc")),
- ("intel", ("x86_64", "i386")),
- ("fat64", ("x86_64", "ppc64")),
- ("fat32", ("x86_64", "i386", "ppc")),
- ]) # type: Dict[str, Tuple[str, ...]]
-
- if _supports_arch(major, minor, machine):
- arches.append(machine)
-
- for garch in groups:
- if machine in groups[garch] and _supports_arch(major, minor, garch):
- arches.append(garch)
-
- arches.append('universal')
-
- return arches
-
-
-def get_all_minor_versions_as_strings(version_info):
- # type: (Tuple[int, ...]) -> List[str]
- versions = []
- major = version_info[:-1]
- # Support all previous minor Python versions.
- for minor in range(version_info[-1], -1, -1):
- versions.append(''.join(map(str, major + (minor,))))
- return versions
-
-
-def get_supported(
- versions=None, # type: Optional[List[str]]
- noarch=False, # type: bool
- platform=None, # type: Optional[str]
- impl=None, # type: Optional[str]
- abi=None # type: Optional[str]
-):
- # type: (...) -> List[Pep425Tag]
- """Return a list of supported tags for each version specified in
- `versions`.
-
- :param versions: a list of string versions, of the form ["33", "32"],
- or None. The first version will be assumed to support our ABI.
- :param platform: specify the exact platform you want valid
- tags for, or None. If None, use the local system platform.
- :param impl: specify the exact implementation you want valid
- tags for, or None. If None, use the local interpreter impl.
- :param abi: specify the exact abi you want valid
- tags for, or None. If None, use the local interpreter abi.
- """
- supported = []
-
- # Versions must be given with respect to the preference
- if versions is None:
- version_info = get_impl_version_info()
- versions = get_all_minor_versions_as_strings(version_info)
-
- impl = impl or get_abbr_impl()
-
- abis = [] # type: List[str]
-
- abi = abi or get_abi_tag()
- if abi:
- abis[0:0] = [abi]
-
- abi3s = set()
- for suffix in get_extension_suffixes():
- if suffix.startswith('.abi'):
- abi3s.add(suffix.split('.', 2)[1])
-
- abis.extend(sorted(list(abi3s)))
-
- abis.append('none')
-
- if not noarch:
- arch = platform or get_platform()
- arch_prefix, arch_sep, arch_suffix = arch.partition('_')
- if arch.startswith('macosx'):
- # support macosx-10.6-intel on macosx-10.9-x86_64
- match = _osx_arch_pat.match(arch)
- if match:
- name, major, minor, actual_arch = match.groups()
- tpl = '{}_{}_%i_%s'.format(name, major)
- arches = []
- for m in reversed(range(int(minor) + 1)):
- for a in get_darwin_arches(int(major), m, actual_arch):
- arches.append(tpl % (m, a))
- else:
- # arch pattern didn't match (?!)
- arches = [arch]
- elif arch_prefix == 'manylinux2010':
- # manylinux1 wheels run on most manylinux2010 systems with the
- # exception of wheels depending on ncurses. PEP 571 states
- # manylinux1 wheels should be considered manylinux2010 wheels:
- # https://www.python.org/dev/peps/pep-0571/#backwards-compatibility-with-manylinux1-wheels
- arches = [arch, 'manylinux1' + arch_sep + arch_suffix]
- elif platform is None:
- arches = []
- if is_manylinux2010_compatible():
- arches.append('manylinux2010' + arch_sep + arch_suffix)
- if is_manylinux1_compatible():
- arches.append('manylinux1' + arch_sep + arch_suffix)
- arches.append(arch)
- else:
- arches = [arch]
-
- # Current version, current API (built specifically for our Python):
- for abi in abis:
- for arch in arches:
- supported.append(('%s%s' % (impl, versions[0]), abi, arch))
-
- # abi3 modules compatible with older version of Python
- for version in versions[1:]:
- # abi3 was introduced in Python 3.2
- if version in {'31', '30'}:
- break
- for abi in abi3s: # empty set if not Python 3
- for arch in arches:
- supported.append(("%s%s" % (impl, version), abi, arch))
-
- # Has binaries, does not use the Python API:
- for arch in arches:
- supported.append(('py%s' % (versions[0][0]), 'none', arch))
-
- # No abi / arch, but requires our implementation:
- supported.append(('%s%s' % (impl, versions[0]), 'none', 'any'))
- # Tagged specifically as being cross-version compatible
- # (with just the major version specified)
- supported.append(('%s%s' % (impl, versions[0][0]), 'none', 'any'))
-
- # No abi / arch, generic Python
- for i, version in enumerate(versions):
- supported.append(('py%s' % (version,), 'none', 'any'))
- if i == 0:
- supported.append(('py%s' % (version[0]), 'none', 'any'))
-
- return supported
-
-
-implementation_tag = get_impl_tag()
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/pyproject.py b/venv/lib/python3.8/site-packages/pip/_internal/pyproject.py
index 43efbed..6b4faf7 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/pyproject.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/pyproject.py
@@ -3,14 +3,16 @@ from __future__ import absolute_import
import io
import os
import sys
+from collections import namedtuple
-from pip._vendor import pytoml, six
+from pip._vendor import six, toml
+from pip._vendor.packaging.requirements import InvalidRequirement, Requirement
from pip._internal.exceptions import InstallationError
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
if MYPY_CHECK_RUNNING:
- from typing import Any, Tuple, Optional, List
+ from typing import Any, Optional, List
def _is_list_of_str(obj):
@@ -21,9 +23,9 @@ def _is_list_of_str(obj):
)
-def make_pyproject_path(setup_py_dir):
+def make_pyproject_path(unpacked_source_directory):
# type: (str) -> str
- path = os.path.join(setup_py_dir, 'pyproject.toml')
+ path = os.path.join(unpacked_source_directory, 'pyproject.toml')
# Python2 __file__ should not be unicode
if six.PY2 and isinstance(path, six.text_type):
@@ -32,13 +34,18 @@ def make_pyproject_path(setup_py_dir):
return path
+BuildSystemDetails = namedtuple('BuildSystemDetails', [
+ 'requires', 'backend', 'check', 'backend_path'
+])
+
+
def load_pyproject_toml(
use_pep517, # type: Optional[bool]
pyproject_toml, # type: str
setup_py, # type: str
req_name # type: str
):
- # type: (...) -> Optional[Tuple[List[str], str, List[str]]]
+ # type: (...) -> Optional[BuildSystemDetails]
"""Load the pyproject.toml file.
Parameters:
@@ -56,6 +63,8 @@ def load_pyproject_toml(
name of PEP 517 backend,
requirements we should check are installed after setting
up the build environment
+ directory paths to import the backend from (backend-path),
+ relative to the project root.
)
"""
has_pyproject = os.path.isfile(pyproject_toml)
@@ -63,7 +72,7 @@ def load_pyproject_toml(
if has_pyproject:
with io.open(pyproject_toml, encoding="utf-8") as f:
- pp_toml = pytoml.load(f)
+ pp_toml = toml.load(f)
build_system = pp_toml.get("build-system")
else:
build_system = None
@@ -150,7 +159,23 @@ def load_pyproject_toml(
reason="'build-system.requires' is not a list of strings.",
))
+ # Each requirement must be valid as per PEP 508
+ for requirement in requires:
+ try:
+ Requirement(requirement)
+ except InvalidRequirement:
+ raise InstallationError(
+ error_template.format(
+ package=req_name,
+ reason=(
+ "'build-system.requires' contains an invalid "
+ "requirement: {!r}".format(requirement)
+ ),
+ )
+ )
+
backend = build_system.get("build-backend")
+ backend_path = build_system.get("backend-path", [])
check = [] # type: List[str]
if backend is None:
# If the user didn't specify a backend, we assume they want to use
@@ -168,4 +193,4 @@ def load_pyproject_toml(
backend = "setuptools.build_meta:__legacy__"
check = ["setuptools>=40.8.0", "wheel"]
- return (requires, backend, check)
+ return BuildSystemDetails(requires, backend, check, backend_path)
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/req/__init__.py
index c39f63f..8568d3f 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/req/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/req/__init__.py
@@ -1,15 +1,17 @@
from __future__ import absolute_import
+import collections
import logging
-from .req_install import InstallRequirement
-from .req_set import RequirementSet
-from .req_file import parse_requirements
from pip._internal.utils.logging import indent_log
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+from .req_file import parse_requirements
+from .req_install import InstallRequirement
+from .req_set import RequirementSet
+
if MYPY_CHECK_RUNNING:
- from typing import Any, List, Sequence
+ from typing import Iterator, List, Optional, Sequence, Tuple
__all__ = [
"RequirementSet", "InstallRequirement",
@@ -19,60 +21,83 @@ __all__ = [
logger = logging.getLogger(__name__)
-def install_given_reqs(
- to_install, # type: List[InstallRequirement]
- install_options, # type: List[str]
- global_options=(), # type: Sequence[str]
- *args, # type: Any
- **kwargs # type: Any
+class InstallationResult(object):
+ def __init__(self, name):
+ # type: (str) -> None
+ self.name = name
+
+ def __repr__(self):
+ # type: () -> str
+ return "InstallationResult(name={!r})".format(self.name)
+
+
+def _validate_requirements(
+ requirements, # type: List[InstallRequirement]
):
- # type: (...) -> List[InstallRequirement]
+ # type: (...) -> Iterator[Tuple[str, InstallRequirement]]
+ for req in requirements:
+ assert req.name, "invalid to-be-installed requirement: {}".format(req)
+ yield req.name, req
+
+
+def install_given_reqs(
+ requirements, # type: List[InstallRequirement]
+ install_options, # type: List[str]
+ global_options, # type: Sequence[str]
+ root, # type: Optional[str]
+ home, # type: Optional[str]
+ prefix, # type: Optional[str]
+ warn_script_location, # type: bool
+ use_user_site, # type: bool
+ pycompile, # type: bool
+):
+ # type: (...) -> List[InstallationResult]
"""
Install everything in the given list.
(to be called after having downloaded and unpacked the packages)
"""
+ to_install = collections.OrderedDict(_validate_requirements(requirements))
if to_install:
logger.info(
'Installing collected packages: %s',
- ', '.join([req.name for req in to_install]),
+ ', '.join(to_install.keys()),
)
+ installed = []
+
with indent_log():
- for requirement in to_install:
- if requirement.conflicts_with:
- logger.info(
- 'Found existing installation: %s',
- requirement.conflicts_with,
- )
+ for req_name, requirement in to_install.items():
+ if requirement.should_reinstall:
+ logger.info('Attempting uninstall: %s', req_name)
with indent_log():
uninstalled_pathset = requirement.uninstall(
auto_confirm=True
)
+ else:
+ uninstalled_pathset = None
+
try:
requirement.install(
install_options,
global_options,
- *args,
- **kwargs
+ root=root,
+ home=home,
+ prefix=prefix,
+ warn_script_location=warn_script_location,
+ use_user_site=use_user_site,
+ pycompile=pycompile,
)
except Exception:
- should_rollback = (
- requirement.conflicts_with and
- not requirement.install_succeeded
- )
# if install did not succeed, rollback previous uninstall
- if should_rollback:
+ if uninstalled_pathset and not requirement.install_succeeded:
uninstalled_pathset.rollback()
raise
else:
- should_commit = (
- requirement.conflicts_with and
- requirement.install_succeeded
- )
- if should_commit:
+ if uninstalled_pathset and requirement.install_succeeded:
uninstalled_pathset.commit()
- requirement.remove_temporary_source()
- return to_install
+ installed.append(InstallationResult(req_name))
+
+ return installed
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/__init__.cpython-38.pyc
index 9047918..152a0a4 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/constructors.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/constructors.cpython-38.pyc
index 94eed9c..3ae73f3 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/constructors.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/constructors.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_file.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_file.cpython-38.pyc
index 7f45de8..7c3717e 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_file.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_file.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_install.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_install.cpython-38.pyc
index 7ae4ee6..03be2c7 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_install.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_install.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_set.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_set.cpython-38.pyc
index ac68ddc..ade8ce0 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_set.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_set.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_tracker.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_tracker.cpython-38.pyc
index 09d0b2d..7ccf691 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_tracker.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_tracker.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-38.pyc
index 1705189..b92d7c8 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/constructors.py b/venv/lib/python3.8/site-packages/pip/_internal/req/constructors.py
index cd0ab50..7a4641e 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/req/constructors.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/req/constructors.py
@@ -17,22 +17,24 @@ from pip._vendor.packaging.requirements import InvalidRequirement, Requirement
from pip._vendor.packaging.specifiers import Specifier
from pip._vendor.pkg_resources import RequirementParseError, parse_requirements
-from pip._internal.download import is_archive_file, is_url, url_to_path
from pip._internal.exceptions import InstallationError
from pip._internal.models.index import PyPI, TestPyPI
from pip._internal.models.link import Link
+from pip._internal.models.wheel import Wheel
from pip._internal.pyproject import make_pyproject_path
from pip._internal.req.req_install import InstallRequirement
-from pip._internal.utils.misc import is_installable_dir, path_to_url
+from pip._internal.utils.deprecation import deprecated
+from pip._internal.utils.filetypes import ARCHIVE_EXTENSIONS
+from pip._internal.utils.misc import is_installable_dir, splitext
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
-from pip._internal.vcs import vcs
-from pip._internal.wheel import Wheel
+from pip._internal.utils.urls import path_to_url
+from pip._internal.vcs import is_url, vcs
if MYPY_CHECK_RUNNING:
from typing import (
Any, Dict, Optional, Set, Tuple, Union,
)
- from pip._internal.cache import WheelCache
+ from pip._internal.req.req_file import ParsedRequirement
__all__ = [
@@ -44,6 +46,15 @@ logger = logging.getLogger(__name__)
operators = Specifier._operators.keys()
+def is_archive_file(name):
+ # type: (str) -> bool
+ """Return True if `name` is a considered as an archive file."""
+ ext = splitext(name)[1].lower()
+ if ext in ARCHIVE_EXTENSIONS:
+ return True
+ return False
+
+
def _strip_extras(path):
# type: (str) -> Tuple[str, Optional[str]]
m = re.match(r'^(.+)(\[[^\]]+\])$', path)
@@ -57,8 +68,15 @@ def _strip_extras(path):
return path_no_extras, extras
+def convert_extras(extras):
+ # type: (Optional[str]) -> Set[str]
+ if not extras:
+ return set()
+ return Requirement("placeholder" + extras.lower()).extras
+
+
def parse_editable(editable_req):
- # type: (str) -> Tuple[Optional[str], str, Optional[Set[str]]]
+ # type: (str) -> Tuple[Optional[str], str, Set[str]]
"""Parses an editable requirement into:
- a requirement name
- an URL
@@ -100,11 +118,11 @@ def parse_editable(editable_req):
Requirement("placeholder" + extras.lower()).extras,
)
else:
- return package_name, url_no_extras, None
+ return package_name, url_no_extras, set()
for version_control in vcs:
- if url.lower().startswith('%s:' % version_control):
- url = '%s+%s' % (version_control, url)
+ if url.lower().startswith('{}:'.format(version_control)):
+ url = '{}+{}'.format(version_control, url)
break
if '+' not in url:
@@ -117,18 +135,19 @@ def parse_editable(editable_req):
vc_type = url.split('+', 1)[0].lower()
if not vcs.get_backend(vc_type):
- error_message = 'For --editable=%s only ' % editable_req + \
- ', '.join([backend.name + '+URL' for backend in vcs.backends]) + \
- ' is currently supported'
+ backends = ", ".join([bends.name + '+URL' for bends in vcs.backends])
+ error_message = "For --editable={}, " \
+ "only {} are currently supported".format(
+ editable_req, backends)
raise InstallationError(error_message)
package_name = Link(url).egg_fragment
if not package_name:
raise InstallationError(
- "Could not detect requirement name for '%s', please specify one "
- "with #egg=your_package_name" % editable_req
+ "Could not detect requirement name for '{}', please specify one "
+ "with #egg=your_package_name".format(editable_req)
)
- return package_name, url, None
+ return package_name, url, set()
def deduce_helpful_msg(req):
@@ -146,75 +165,141 @@ def deduce_helpful_msg(req):
with open(req, 'r') as fp:
# parse first line only
next(parse_requirements(fp.read()))
- msg += " The argument you provided " + \
- "(%s) appears to be a" % (req) + \
- " requirements file. If that is the" + \
- " case, use the '-r' flag to install" + \
+ msg += (
+ "The argument you provided "
+ "({}) appears to be a"
+ " requirements file. If that is the"
+ " case, use the '-r' flag to install"
" the packages specified within it."
+ ).format(req)
except RequirementParseError:
- logger.debug("Cannot parse '%s' as requirements \
- file" % (req), exc_info=True)
+ logger.debug(
+ "Cannot parse '%s' as requirements file", req, exc_info=True
+ )
else:
- msg += " File '%s' does not exist." % (req)
+ msg += " File '{}' does not exist.".format(req)
return msg
+class RequirementParts(object):
+ def __init__(
+ self,
+ requirement, # type: Optional[Requirement]
+ link, # type: Optional[Link]
+ markers, # type: Optional[Marker]
+ extras, # type: Set[str]
+ ):
+ self.requirement = requirement
+ self.link = link
+ self.markers = markers
+ self.extras = extras
+
+
+def parse_req_from_editable(editable_req):
+ # type: (str) -> RequirementParts
+ name, url, extras_override = parse_editable(editable_req)
+
+ if name is not None:
+ try:
+ req = Requirement(name)
+ except InvalidRequirement:
+ raise InstallationError("Invalid requirement: '{}'".format(name))
+ else:
+ req = None
+
+ link = Link(url)
+
+ return RequirementParts(req, link, None, extras_override)
+
+
# ---- The actual constructors follow ----
def install_req_from_editable(
editable_req, # type: str
- comes_from=None, # type: Optional[str]
+ comes_from=None, # type: Optional[Union[InstallRequirement, str]]
use_pep517=None, # type: Optional[bool]
isolated=False, # type: bool
options=None, # type: Optional[Dict[str, Any]]
- wheel_cache=None, # type: Optional[WheelCache]
- constraint=False # type: bool
+ constraint=False, # type: bool
+ user_supplied=False, # type: bool
):
# type: (...) -> InstallRequirement
- name, url, extras_override = parse_editable(editable_req)
- if url.startswith('file:'):
- source_dir = url_to_path(url)
- else:
- source_dir = None
- if name is not None:
- try:
- req = Requirement(name)
- except InvalidRequirement:
- raise InstallationError("Invalid requirement: '%s'" % name)
- else:
- req = None
+ parts = parse_req_from_editable(editable_req)
+
return InstallRequirement(
- req, comes_from, source_dir=source_dir,
+ parts.requirement,
+ comes_from=comes_from,
+ user_supplied=user_supplied,
editable=True,
- link=Link(url),
+ link=parts.link,
constraint=constraint,
use_pep517=use_pep517,
isolated=isolated,
- options=options if options else {},
- wheel_cache=wheel_cache,
- extras=extras_override or (),
+ install_options=options.get("install_options", []) if options else [],
+ global_options=options.get("global_options", []) if options else [],
+ hash_options=options.get("hashes", {}) if options else {},
+ extras=parts.extras,
)
-def install_req_from_line(
- name, # type: str
- comes_from=None, # type: Optional[Union[str, InstallRequirement]]
- use_pep517=None, # type: Optional[bool]
- isolated=False, # type: bool
- options=None, # type: Optional[Dict[str, Any]]
- wheel_cache=None, # type: Optional[WheelCache]
- constraint=False, # type: bool
- line_source=None, # type: Optional[str]
-):
- # type: (...) -> InstallRequirement
- """Creates an InstallRequirement from a name, which might be a
- requirement, directory containing 'setup.py', filename, or URL.
+def _looks_like_path(name):
+ # type: (str) -> bool
+ """Checks whether the string "looks like" a path on the filesystem.
- :param line_source: An optional string describing where the line is from,
- for logging purposes in case of an error.
+ This does not check whether the target actually exists, only judge from the
+ appearance.
+
+ Returns true if any of the following conditions is true:
+ * a path separator is found (either os.path.sep or os.path.altsep);
+ * a dot is found (which represents the current directory).
"""
+ if os.path.sep in name:
+ return True
+ if os.path.altsep is not None and os.path.altsep in name:
+ return True
+ if name.startswith("."):
+ return True
+ return False
+
+
+def _get_url_from_path(path, name):
+ # type: (str, str) -> Optional[str]
+ """
+ First, it checks whether a provided path is an installable directory
+ (e.g. it has a setup.py). If it is, returns the path.
+
+ If false, check if the path is an archive file (such as a .whl).
+ The function checks if the path is a file. If false, if the path has
+ an @, it will treat it as a PEP 440 URL requirement and return the path.
+ """
+ if _looks_like_path(name) and os.path.isdir(path):
+ if is_installable_dir(path):
+ return path_to_url(path)
+ raise InstallationError(
+ "Directory {name!r} is not installable. Neither 'setup.py' "
+ "nor 'pyproject.toml' found.".format(**locals())
+ )
+ if not is_archive_file(path):
+ return None
+ if os.path.isfile(path):
+ return path_to_url(path)
+ urlreq_parts = name.split('@', 1)
+ if len(urlreq_parts) >= 2 and not _looks_like_path(urlreq_parts[0]):
+ # If the path contains '@' and the part before it does not look
+ # like a path, try to treat it as a PEP 440 URL req instead.
+ return None
+ logger.warning(
+ 'Requirement %r looks like a filename, but the '
+ 'file does not exist',
+ name
+ )
+ return path_to_url(path)
+
+
+def parse_req_from_line(name, line_source):
+ # type: (str, Optional[str]) -> RequirementParts
if is_url(name):
marker_sep = '; '
else:
@@ -238,26 +323,9 @@ def install_req_from_line(
link = Link(name)
else:
p, extras_as_string = _strip_extras(path)
- looks_like_dir = os.path.isdir(p) and (
- os.path.sep in name or
- (os.path.altsep is not None and os.path.altsep in name) or
- name.startswith('.')
- )
- if looks_like_dir:
- if not is_installable_dir(p):
- raise InstallationError(
- "Directory %r is not installable. Neither 'setup.py' "
- "nor 'pyproject.toml' found." % name
- )
- link = Link(path_to_url(p))
- elif is_archive_file(p):
- if not os.path.isfile(p):
- logger.warning(
- 'Requirement %r looks like a filename, but the '
- 'file does not exist',
- name
- )
- link = Link(path_to_url(p))
+ url = _get_url_from_path(p, name)
+ if url is not None:
+ link = Link(url)
# it's a local file, dir, or url
if link:
@@ -268,7 +336,7 @@ def install_req_from_line(
# wheel file
if link.is_wheel:
wheel = Wheel(link.filename) # can raise InvalidWheelFilename
- req_as_string = "%s==%s" % (wheel.name, wheel.version)
+ req_as_string = "{wheel.name}=={wheel.version}".format(**locals())
else:
# set the req to the egg fragment. when it's not there, this
# will become an 'unnamed' requirement
@@ -278,10 +346,14 @@ def install_req_from_line(
else:
req_as_string = name
- if extras_as_string:
- extras = Requirement("placeholder" + extras_as_string.lower()).extras
- else:
- extras = ()
+ extras = convert_extras(extras_as_string)
+
+ def with_source(text):
+ # type: (str) -> str
+ if not line_source:
+ return text
+ return '{} (from {})'.format(text, line_source)
+
if req_as_string is not None:
try:
req = Requirement(req_as_string)
@@ -294,26 +366,57 @@ def install_req_from_line(
add_msg = "= is not a valid operator. Did you mean == ?"
else:
add_msg = ''
- if line_source is None:
- source = ''
- else:
- source = ' (from {})'.format(line_source)
- msg = (
- 'Invalid requirement: {!r}{}'.format(req_as_string, source)
+ msg = with_source(
+ 'Invalid requirement: {!r}'.format(req_as_string)
)
if add_msg:
msg += '\nHint: {}'.format(add_msg)
raise InstallationError(msg)
+ else:
+ # Deprecate extras after specifiers: "name>=1.0[extras]"
+ # This currently works by accident because _strip_extras() parses
+ # any extras in the end of the string and those are saved in
+ # RequirementParts
+ for spec in req.specifier:
+ spec_str = str(spec)
+ if spec_str.endswith(']'):
+ msg = "Extras after version '{}'.".format(spec_str)
+ replace = "moving the extras before version specifiers"
+ deprecated(msg, replacement=replace, gone_in="21.0")
else:
req = None
+ return RequirementParts(req, link, markers, extras)
+
+
+def install_req_from_line(
+ name, # type: str
+ comes_from=None, # type: Optional[Union[str, InstallRequirement]]
+ use_pep517=None, # type: Optional[bool]
+ isolated=False, # type: bool
+ options=None, # type: Optional[Dict[str, Any]]
+ constraint=False, # type: bool
+ line_source=None, # type: Optional[str]
+ user_supplied=False, # type: bool
+):
+ # type: (...) -> InstallRequirement
+ """Creates an InstallRequirement from a name, which might be a
+ requirement, directory containing 'setup.py', filename, or URL.
+
+ :param line_source: An optional string describing where the line is from,
+ for logging purposes in case of an error.
+ """
+ parts = parse_req_from_line(name, line_source)
+
return InstallRequirement(
- req, comes_from, link=link, markers=markers,
+ parts.requirement, comes_from, link=parts.link, markers=parts.markers,
use_pep517=use_pep517, isolated=isolated,
- options=options if options else {},
- wheel_cache=wheel_cache,
+ install_options=options.get("install_options", []) if options else [],
+ global_options=options.get("global_options", []) if options else [],
+ hash_options=options.get("hashes", {}) if options else {},
constraint=constraint,
- extras=extras,
+ extras=parts.extras,
+ user_supplied=user_supplied,
)
@@ -321,14 +424,14 @@ def install_req_from_req_string(
req_string, # type: str
comes_from=None, # type: Optional[InstallRequirement]
isolated=False, # type: bool
- wheel_cache=None, # type: Optional[WheelCache]
- use_pep517=None # type: Optional[bool]
+ use_pep517=None, # type: Optional[bool]
+ user_supplied=False, # type: bool
):
# type: (...) -> InstallRequirement
try:
req = Requirement(req_string)
except InvalidRequirement:
- raise InstallationError("Invalid requirement: '%s'" % req_string)
+ raise InstallationError("Invalid requirement: '{}'".format(req_string))
domains_not_allowed = [
PyPI.file_storage_domain,
@@ -340,10 +443,44 @@ def install_req_from_req_string(
raise InstallationError(
"Packages installed from PyPI cannot depend on packages "
"which are not also hosted on PyPI.\n"
- "%s depends on %s " % (comes_from.name, req)
+ "{} depends on {} ".format(comes_from.name, req)
)
return InstallRequirement(
- req, comes_from, isolated=isolated, wheel_cache=wheel_cache,
- use_pep517=use_pep517
+ req,
+ comes_from,
+ isolated=isolated,
+ use_pep517=use_pep517,
+ user_supplied=user_supplied,
)
+
+
+def install_req_from_parsed_requirement(
+ parsed_req, # type: ParsedRequirement
+ isolated=False, # type: bool
+ use_pep517=None, # type: Optional[bool]
+ user_supplied=False, # type: bool
+):
+ # type: (...) -> InstallRequirement
+ if parsed_req.is_editable:
+ req = install_req_from_editable(
+ parsed_req.requirement,
+ comes_from=parsed_req.comes_from,
+ use_pep517=use_pep517,
+ constraint=parsed_req.constraint,
+ isolated=isolated,
+ user_supplied=user_supplied,
+ )
+
+ else:
+ req = install_req_from_line(
+ parsed_req.requirement,
+ comes_from=parsed_req.comes_from,
+ use_pep517=use_pep517,
+ isolated=isolated,
+ options=parsed_req.options,
+ constraint=parsed_req.constraint,
+ line_source=parsed_req.line_source,
+ user_supplied=user_supplied,
+ )
+ return req
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/req_file.py b/venv/lib/python3.8/site-packages/pip/_internal/req/req_file.py
index 5a9920f..1050582 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/req/req_file.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/req/req_file.py
@@ -10,29 +10,33 @@ import re
import shlex
import sys
-from pip._vendor.six.moves import filterfalse
from pip._vendor.six.moves.urllib import parse as urllib_parse
from pip._internal.cli import cmdoptions
-from pip._internal.download import get_file_content
-from pip._internal.exceptions import RequirementsFileParseError
-from pip._internal.models.search_scope import SearchScope
-from pip._internal.req.constructors import (
- install_req_from_editable, install_req_from_line,
+from pip._internal.exceptions import (
+ InstallationError,
+ RequirementsFileParseError,
)
+from pip._internal.models.search_scope import SearchScope
+from pip._internal.network.utils import raise_for_status
+from pip._internal.utils.encoding import auto_decode
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+from pip._internal.utils.urls import get_url_scheme
if MYPY_CHECK_RUNNING:
+ from optparse import Values
from typing import (
- Any, Callable, Iterator, List, NoReturn, Optional, Text, Tuple,
+ Any, Callable, Dict, Iterator, List, NoReturn, Optional, Text, Tuple,
)
- from pip._internal.req import InstallRequirement
- from pip._internal.cache import WheelCache
- from pip._internal.index import PackageFinder
- from pip._internal.download import PipSession
+
+ from pip._internal.index.package_finder import PackageFinder
+ from pip._internal.network.session import PipSession
ReqFileLines = Iterator[Tuple[int, Text]]
+ LineParser = Callable[[Text], Tuple[str, Values]]
+
+
__all__ = ['parse_requirements']
SCHEME_RE = re.compile(r'^(http|https|file):', re.I)
@@ -45,19 +49,20 @@ COMMENT_RE = re.compile(r'(^|\s+)#.*$')
ENV_VAR_RE = re.compile(r'(?P\$\{(?P[A-Z0-9_]+)\})')
SUPPORTED_OPTIONS = [
- cmdoptions.constraints,
- cmdoptions.editable,
- cmdoptions.requirements,
- cmdoptions.no_index,
cmdoptions.index_url,
- cmdoptions.find_links,
cmdoptions.extra_index_url,
- cmdoptions.always_unzip,
+ cmdoptions.no_index,
+ cmdoptions.constraints,
+ cmdoptions.requirements,
+ cmdoptions.editable,
+ cmdoptions.find_links,
cmdoptions.no_binary,
cmdoptions.only_binary,
+ cmdoptions.prefer_binary,
+ cmdoptions.require_hashes,
cmdoptions.pre,
cmdoptions.trusted_host,
- cmdoptions.require_hashes,
+ cmdoptions.use_new_feature,
] # type: List[Callable[..., optparse.Option]]
# options to be passed to requirements
@@ -71,174 +76,167 @@ SUPPORTED_OPTIONS_REQ = [
SUPPORTED_OPTIONS_REQ_DEST = [str(o().dest) for o in SUPPORTED_OPTIONS_REQ]
+class ParsedRequirement(object):
+ def __init__(
+ self,
+ requirement, # type:str
+ is_editable, # type: bool
+ comes_from, # type: str
+ constraint, # type: bool
+ options=None, # type: Optional[Dict[str, Any]]
+ line_source=None, # type: Optional[str]
+ ):
+ # type: (...) -> None
+ self.requirement = requirement
+ self.is_editable = is_editable
+ self.comes_from = comes_from
+ self.options = options
+ self.constraint = constraint
+ self.line_source = line_source
+
+
+class ParsedLine(object):
+ def __init__(
+ self,
+ filename, # type: str
+ lineno, # type: int
+ comes_from, # type: Optional[str]
+ args, # type: str
+ opts, # type: Values
+ constraint, # type: bool
+ ):
+ # type: (...) -> None
+ self.filename = filename
+ self.lineno = lineno
+ self.comes_from = comes_from
+ self.opts = opts
+ self.constraint = constraint
+
+ if args:
+ self.is_requirement = True
+ self.is_editable = False
+ self.requirement = args
+ elif opts.editables:
+ self.is_requirement = True
+ self.is_editable = True
+ # We don't support multiple -e on one line
+ self.requirement = opts.editables[0]
+ else:
+ self.is_requirement = False
+
+
def parse_requirements(
filename, # type: str
+ session, # type: PipSession
finder=None, # type: Optional[PackageFinder]
comes_from=None, # type: Optional[str]
options=None, # type: Optional[optparse.Values]
- session=None, # type: Optional[PipSession]
constraint=False, # type: bool
- wheel_cache=None, # type: Optional[WheelCache]
- use_pep517=None # type: Optional[bool]
):
- # type: (...) -> Iterator[InstallRequirement]
- """Parse a requirements file and yield InstallRequirement instances.
+ # type: (...) -> Iterator[ParsedRequirement]
+ """Parse a requirements file and yield ParsedRequirement instances.
:param filename: Path or url of requirements file.
+ :param session: PipSession instance.
:param finder: Instance of pip.index.PackageFinder.
:param comes_from: Origin description of requirements.
:param options: cli options.
- :param session: Instance of pip.download.PipSession.
:param constraint: If true, parsing a constraint file rather than
requirements file.
- :param wheel_cache: Instance of pip.wheel.WheelCache
- :param use_pep517: Value of the --use-pep517 option.
"""
- if session is None:
- raise TypeError(
- "parse_requirements() missing 1 required keyword argument: "
- "'session'"
+ line_parser = get_line_parser(finder)
+ parser = RequirementsFileParser(session, line_parser, comes_from)
+
+ for parsed_line in parser.parse(filename, constraint):
+ parsed_req = handle_line(
+ parsed_line,
+ options=options,
+ finder=finder,
+ session=session
)
-
- _, content = get_file_content(
- filename, comes_from=comes_from, session=session
- )
-
- lines_enum = preprocess(content, options)
-
- for line_number, line in lines_enum:
- req_iter = process_line(line, filename, line_number, finder,
- comes_from, options, session, wheel_cache,
- use_pep517=use_pep517, constraint=constraint)
- for req in req_iter:
- yield req
+ if parsed_req is not None:
+ yield parsed_req
-def preprocess(content, options):
- # type: (Text, Optional[optparse.Values]) -> ReqFileLines
+def preprocess(content):
+ # type: (Text) -> ReqFileLines
"""Split, filter, and join lines, and return a line iterator
:param content: the content of the requirements file
- :param options: cli options
"""
lines_enum = enumerate(content.splitlines(), start=1) # type: ReqFileLines
lines_enum = join_lines(lines_enum)
lines_enum = ignore_comments(lines_enum)
- lines_enum = skip_regex(lines_enum, options)
lines_enum = expand_env_variables(lines_enum)
return lines_enum
-def process_line(
- line, # type: Text
- filename, # type: str
- line_number, # type: int
- finder=None, # type: Optional[PackageFinder]
- comes_from=None, # type: Optional[str]
+def handle_requirement_line(
+ line, # type: ParsedLine
options=None, # type: Optional[optparse.Values]
- session=None, # type: Optional[PipSession]
- wheel_cache=None, # type: Optional[WheelCache]
- use_pep517=None, # type: Optional[bool]
- constraint=False, # type: bool
):
- # type: (...) -> Iterator[InstallRequirement]
- """Process a single requirements line; This can result in creating/yielding
- requirements, or updating the finder.
-
- For lines that contain requirements, the only options that have an effect
- are from SUPPORTED_OPTIONS_REQ, and they are scoped to the
- requirement. Other options from SUPPORTED_OPTIONS may be present, but are
- ignored.
-
- For lines that do not contain requirements, the only options that have an
- effect are from SUPPORTED_OPTIONS. Options from SUPPORTED_OPTIONS_REQ may
- be present, but are ignored. These lines may contain multiple options
- (although our docs imply only one is supported), and all our parsed and
- affect the finder.
-
- :param constraint: If True, parsing a constraints file.
- :param options: OptionParser options that we may update
- """
- parser = build_parser(line)
- defaults = parser.get_default_values()
- defaults.index_url = None
- if finder:
- defaults.format_control = finder.format_control
- args_str, options_str = break_args_options(line)
- # Prior to 2.7.3, shlex cannot deal with unicode entries
- if sys.version_info < (2, 7, 3):
- # https://github.com/python/mypy/issues/1174
- options_str = options_str.encode('utf8') # type: ignore
- # https://github.com/python/mypy/issues/1174
- opts, _ = parser.parse_args(
- shlex.split(options_str), defaults) # type: ignore
+ # type: (...) -> ParsedRequirement
# preserve for the nested code path
- line_comes_from = '%s %s (line %s)' % (
- '-c' if constraint else '-r', filename, line_number,
+ line_comes_from = '{} {} (line {})'.format(
+ '-c' if line.constraint else '-r', line.filename, line.lineno,
)
- # yield a line requirement
- if args_str:
- isolated = options.isolated_mode if options else False
+ assert line.is_requirement
+
+ if line.is_editable:
+ # For editable requirements, we don't support per-requirement
+ # options, so just return the parsed requirement.
+ return ParsedRequirement(
+ requirement=line.requirement,
+ is_editable=line.is_editable,
+ comes_from=line_comes_from,
+ constraint=line.constraint,
+ )
+ else:
if options:
- cmdoptions.check_install_build_global(options, opts)
+ # Disable wheels if the user has specified build options
+ cmdoptions.check_install_build_global(options, line.opts)
+
# get the options that apply to requirements
req_options = {}
for dest in SUPPORTED_OPTIONS_REQ_DEST:
- if dest in opts.__dict__ and opts.__dict__[dest]:
- req_options[dest] = opts.__dict__[dest]
- line_source = 'line {} of {}'.format(line_number, filename)
- yield install_req_from_line(
- args_str,
+ if dest in line.opts.__dict__ and line.opts.__dict__[dest]:
+ req_options[dest] = line.opts.__dict__[dest]
+
+ line_source = 'line {} of {}'.format(line.lineno, line.filename)
+ return ParsedRequirement(
+ requirement=line.requirement,
+ is_editable=line.is_editable,
comes_from=line_comes_from,
- use_pep517=use_pep517,
- isolated=isolated,
+ constraint=line.constraint,
options=req_options,
- wheel_cache=wheel_cache,
- constraint=constraint,
line_source=line_source,
)
- # yield an editable requirement
- elif opts.editables:
- isolated = options.isolated_mode if options else False
- yield install_req_from_editable(
- opts.editables[0], comes_from=line_comes_from,
- use_pep517=use_pep517,
- constraint=constraint, isolated=isolated, wheel_cache=wheel_cache
- )
- # parse a nested requirements file
- elif opts.requirements or opts.constraints:
- if opts.requirements:
- req_path = opts.requirements[0]
- nested_constraint = False
- else:
- req_path = opts.constraints[0]
- nested_constraint = True
- # original file is over http
- if SCHEME_RE.search(filename):
- # do a url join so relative paths work
- req_path = urllib_parse.urljoin(filename, req_path)
- # original file and nested file are paths
- elif not SCHEME_RE.search(req_path):
- # do a join so relative paths work
- req_path = os.path.join(os.path.dirname(filename), req_path)
- # TODO: Why not use `comes_from='-r {} (line {})'` here as well?
- parsed_reqs = parse_requirements(
- req_path, finder, comes_from, options, session,
- constraint=nested_constraint, wheel_cache=wheel_cache
- )
- for req in parsed_reqs:
- yield req
+def handle_option_line(
+ opts, # type: Values
+ filename, # type: str
+ lineno, # type: int
+ finder=None, # type: Optional[PackageFinder]
+ options=None, # type: Optional[optparse.Values]
+ session=None, # type: Optional[PipSession]
+):
+ # type: (...) -> None
- # percolate hash-checking option upward
- elif opts.require_hashes:
- options.require_hashes = opts.require_hashes
+ if options:
+ # percolate options upward
+ if opts.require_hashes:
+ options.require_hashes = opts.require_hashes
+ if opts.features_enabled:
+ options.features_enabled.extend(
+ f for f in opts.features_enabled
+ if f not in options.features_enabled
+ )
# set finder options
- elif finder:
+ if finder:
find_links = finder.find_links
index_urls = finder.index_urls
if opts.index_url:
@@ -266,9 +264,164 @@ def process_line(
if opts.pre:
finder.set_allow_all_prereleases()
- for host in opts.trusted_hosts or []:
- source = 'line {} of {}'.format(line_number, filename)
- finder.add_trusted_host(host, source=source)
+
+ if opts.prefer_binary:
+ finder.set_prefer_binary()
+
+ if session:
+ for host in opts.trusted_hosts or []:
+ source = 'line {} of {}'.format(lineno, filename)
+ session.add_trusted_host(host, source=source)
+
+
+def handle_line(
+ line, # type: ParsedLine
+ options=None, # type: Optional[optparse.Values]
+ finder=None, # type: Optional[PackageFinder]
+ session=None, # type: Optional[PipSession]
+):
+ # type: (...) -> Optional[ParsedRequirement]
+ """Handle a single parsed requirements line; This can result in
+ creating/yielding requirements, or updating the finder.
+
+ :param line: The parsed line to be processed.
+ :param options: CLI options.
+ :param finder: The finder - updated by non-requirement lines.
+ :param session: The session - updated by non-requirement lines.
+
+ Returns a ParsedRequirement object if the line is a requirement line,
+ otherwise returns None.
+
+ For lines that contain requirements, the only options that have an effect
+ are from SUPPORTED_OPTIONS_REQ, and they are scoped to the
+ requirement. Other options from SUPPORTED_OPTIONS may be present, but are
+ ignored.
+
+ For lines that do not contain requirements, the only options that have an
+ effect are from SUPPORTED_OPTIONS. Options from SUPPORTED_OPTIONS_REQ may
+ be present, but are ignored. These lines may contain multiple options
+ (although our docs imply only one is supported), and all our parsed and
+ affect the finder.
+ """
+
+ if line.is_requirement:
+ parsed_req = handle_requirement_line(line, options)
+ return parsed_req
+ else:
+ handle_option_line(
+ line.opts,
+ line.filename,
+ line.lineno,
+ finder,
+ options,
+ session,
+ )
+ return None
+
+
+class RequirementsFileParser(object):
+ def __init__(
+ self,
+ session, # type: PipSession
+ line_parser, # type: LineParser
+ comes_from, # type: Optional[str]
+ ):
+ # type: (...) -> None
+ self._session = session
+ self._line_parser = line_parser
+ self._comes_from = comes_from
+
+ def parse(self, filename, constraint):
+ # type: (str, bool) -> Iterator[ParsedLine]
+ """Parse a given file, yielding parsed lines.
+ """
+ for line in self._parse_and_recurse(filename, constraint):
+ yield line
+
+ def _parse_and_recurse(self, filename, constraint):
+ # type: (str, bool) -> Iterator[ParsedLine]
+ for line in self._parse_file(filename, constraint):
+ if (
+ not line.is_requirement and
+ (line.opts.requirements or line.opts.constraints)
+ ):
+ # parse a nested requirements file
+ if line.opts.requirements:
+ req_path = line.opts.requirements[0]
+ nested_constraint = False
+ else:
+ req_path = line.opts.constraints[0]
+ nested_constraint = True
+
+ # original file is over http
+ if SCHEME_RE.search(filename):
+ # do a url join so relative paths work
+ req_path = urllib_parse.urljoin(filename, req_path)
+ # original file and nested file are paths
+ elif not SCHEME_RE.search(req_path):
+ # do a join so relative paths work
+ req_path = os.path.join(
+ os.path.dirname(filename), req_path,
+ )
+
+ for inner_line in self._parse_and_recurse(
+ req_path, nested_constraint,
+ ):
+ yield inner_line
+ else:
+ yield line
+
+ def _parse_file(self, filename, constraint):
+ # type: (str, bool) -> Iterator[ParsedLine]
+ _, content = get_file_content(
+ filename, self._session, comes_from=self._comes_from
+ )
+
+ lines_enum = preprocess(content)
+
+ for line_number, line in lines_enum:
+ try:
+ args_str, opts = self._line_parser(line)
+ except OptionParsingError as e:
+ # add offending line
+ msg = 'Invalid requirement: {}\n{}'.format(line, e.msg)
+ raise RequirementsFileParseError(msg)
+
+ yield ParsedLine(
+ filename,
+ line_number,
+ self._comes_from,
+ args_str,
+ opts,
+ constraint,
+ )
+
+
+def get_line_parser(finder):
+ # type: (Optional[PackageFinder]) -> LineParser
+ def parse_line(line):
+ # type: (Text) -> Tuple[str, Values]
+ # Build new parser for each line since it accumulates appendable
+ # options.
+ parser = build_parser()
+ defaults = parser.get_default_values()
+ defaults.index_url = None
+ if finder:
+ defaults.format_control = finder.format_control
+
+ args_str, options_str = break_args_options(line)
+ # Prior to 2.7.3, shlex cannot deal with unicode entries
+ if sys.version_info < (2, 7, 3):
+ # https://github.com/python/mypy/issues/1174
+ options_str = options_str.encode('utf8') # type: ignore
+
+ # https://github.com/python/mypy/issues/1174
+ opts, _ = parser.parse_args(
+ shlex.split(options_str), defaults) # type: ignore
+
+ return args_str, opts
+
+ return parse_line
def break_args_options(line):
@@ -289,8 +442,14 @@ def break_args_options(line):
return ' '.join(args), ' '.join(options) # type: ignore
-def build_parser(line):
- # type: (Text) -> optparse.OptionParser
+class OptionParsingError(Exception):
+ def __init__(self, msg):
+ # type: (str) -> None
+ self.msg = msg
+
+
+def build_parser():
+ # type: () -> optparse.OptionParser
"""
Return a parser for parsing requirement lines
"""
@@ -305,9 +464,7 @@ def build_parser(line):
# that in our own exception.
def parser_exit(self, msg):
# type: (Any, str) -> NoReturn
- # add offending line
- msg = 'Invalid requirement: %s\n%s' % (line, msg)
- raise RequirementsFileParseError(msg)
+ raise OptionParsingError(msg)
# NOTE: mypy disallows assigning to a method
# https://github.com/python/mypy/issues/2427
parser.exit = parser_exit # type: ignore
@@ -329,6 +486,7 @@ def join_lines(lines_enum):
line = ' ' + line
if new_line:
new_line.append(line)
+ assert primary_line_number is not None
yield primary_line_number, ''.join(new_line)
new_line = []
else:
@@ -340,6 +498,7 @@ def join_lines(lines_enum):
# last line contains \
if new_line:
+ assert primary_line_number is not None
yield primary_line_number, ''.join(new_line)
# TODO: handle space after '\'.
@@ -357,20 +516,6 @@ def ignore_comments(lines_enum):
yield line_number, line
-def skip_regex(lines_enum, options):
- # type: (ReqFileLines, Optional[optparse.Values]) -> ReqFileLines
- """
- Skip lines that match '--skip-requirements-regex' pattern
-
- Note: the regex pattern is only built once
- """
- skip_regex = options.skip_requirements_regex if options else None
- if skip_regex:
- pattern = re.compile(skip_regex)
- lines_enum = filterfalse(lambda e: pattern.search(e[1]), lines_enum)
- return lines_enum
-
-
def expand_env_variables(lines_enum):
# type: (ReqFileLines) -> ReqFileLines
"""Replace all environment variables that can be retrieved via `os.getenv`.
@@ -397,3 +542,51 @@ def expand_env_variables(lines_enum):
line = line.replace(env_var, value)
yield line_number, line
+
+
+def get_file_content(url, session, comes_from=None):
+ # type: (str, PipSession, Optional[str]) -> Tuple[str, Text]
+ """Gets the content of a file; it may be a filename, file: URL, or
+ http: URL. Returns (location, content). Content is unicode.
+ Respects # -*- coding: declarations on the retrieved files.
+
+ :param url: File path or url.
+ :param session: PipSession instance.
+ :param comes_from: Origin description of requirements.
+ """
+ scheme = get_url_scheme(url)
+
+ if scheme in ['http', 'https']:
+ # FIXME: catch some errors
+ resp = session.get(url)
+ raise_for_status(resp)
+ return resp.url, resp.text
+
+ elif scheme == 'file':
+ if comes_from and comes_from.startswith('http'):
+ raise InstallationError(
+ 'Requirements file {} references URL {}, '
+ 'which is local'.format(comes_from, url)
+ )
+
+ path = url.split(':', 1)[1]
+ path = path.replace('\\', '/')
+ match = _url_slash_drive_re.match(path)
+ if match:
+ path = match.group(1) + ':' + path.split('|', 1)[1]
+ path = urllib_parse.unquote(path)
+ if path.startswith('/'):
+ path = '/' + path.lstrip('/')
+ url = path
+
+ try:
+ with open(url, 'rb') as f:
+ content = auto_decode(f.read())
+ except IOError as exc:
+ raise InstallationError(
+ 'Could not open requirements file: {}'.format(exc)
+ )
+ return url, content
+
+
+_url_slash_drive_re = re.compile(r'/*([a-z])\|', re.I)
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/req_install.py b/venv/lib/python3.8/site-packages/pip/_internal/req/req_install.py
index f5c9350..f25cec9 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/req/req_install.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/req/req_install.py
@@ -1,12 +1,14 @@
+# The following comment should be removed at some point in the future.
+# mypy: strict-optional=False
+
from __future__ import absolute_import
import logging
import os
import shutil
import sys
-import sysconfig
+import uuid
import zipfile
-from distutils.util import change_root
from pip._vendor import pkg_resources, six
from pip._vendor.packaging.requirements import Requirement
@@ -15,36 +17,46 @@ from pip._vendor.packaging.version import Version
from pip._vendor.packaging.version import parse as parse_version
from pip._vendor.pep517.wrappers import Pep517HookCaller
-from pip._internal import wheel
from pip._internal.build_env import NoOpBuildEnvironment
from pip._internal.exceptions import InstallationError
+from pip._internal.locations import get_scheme
from pip._internal.models.link import Link
+from pip._internal.operations.build.metadata import generate_metadata
+from pip._internal.operations.build.metadata_legacy import \
+ generate_metadata as generate_metadata_legacy
+from pip._internal.operations.install.editable_legacy import \
+ install_editable as install_editable_legacy
+from pip._internal.operations.install.legacy import LegacyInstallFailure
+from pip._internal.operations.install.legacy import install as install_legacy
+from pip._internal.operations.install.wheel import install_wheel
from pip._internal.pyproject import load_pyproject_toml, make_pyproject_path
from pip._internal.req.req_uninstall import UninstallPathSet
-from pip._internal.utils.compat import native_str
+from pip._internal.utils.deprecation import deprecated
+from pip._internal.utils.direct_url_helpers import direct_url_from_link
from pip._internal.utils.hashes import Hashes
from pip._internal.utils.logging import indent_log
-from pip._internal.utils.marker_files import PIP_DELETE_MARKER_FILENAME
from pip._internal.utils.misc import (
- _make_build_dir, ask_path_exists, backup_dir, call_subprocess,
- display_path, dist_in_site_packages, dist_in_usersite, ensure_dir,
- get_installed_version, redact_password_from_url, rmtree,
+ ask_path_exists,
+ backup_dir,
+ display_path,
+ dist_in_site_packages,
+ dist_in_usersite,
+ get_distribution,
+ get_installed_version,
+ hide_url,
+ redact_auth_from_url,
)
from pip._internal.utils.packaging import get_metadata
-from pip._internal.utils.setuptools_build import make_setuptools_shim_args
-from pip._internal.utils.temp_dir import TempDirectory
+from pip._internal.utils.temp_dir import TempDirectory, tempdir_kinds
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
-from pip._internal.utils.ui import open_spinner
from pip._internal.utils.virtualenv import running_under_virtualenv
from pip._internal.vcs import vcs
if MYPY_CHECK_RUNNING:
from typing import (
- Any, Dict, Iterable, List, Mapping, Optional, Sequence, Union,
+ Any, Dict, Iterable, List, Optional, Sequence, Union,
)
from pip._internal.build_env import BuildEnvironment
- from pip._internal.cache import WheelCache
- from pip._internal.index import PackageFinder
from pip._vendor.pkg_resources import Distribution
from pip._vendor.packaging.specifiers import SpecifierSet
from pip._vendor.packaging.markers import Marker
@@ -53,6 +65,33 @@ if MYPY_CHECK_RUNNING:
logger = logging.getLogger(__name__)
+def _get_dist(metadata_directory):
+ # type: (str) -> Distribution
+ """Return a pkg_resources.Distribution for the provided
+ metadata directory.
+ """
+ dist_dir = metadata_directory.rstrip(os.sep)
+
+ # Build a PathMetadata object, from path to metadata. :wink:
+ base_dir, dist_dir_name = os.path.split(dist_dir)
+ metadata = pkg_resources.PathMetadata(base_dir, dist_dir)
+
+ # Determine the correct Distribution object type.
+ if dist_dir.endswith(".egg-info"):
+ dist_cls = pkg_resources.Distribution
+ dist_name = os.path.splitext(dist_dir_name)[0]
+ else:
+ assert dist_dir.endswith(".dist-info")
+ dist_cls = pkg_resources.DistInfoDistribution
+ dist_name = os.path.splitext(dist_dir_name)[0].split("-")[0]
+
+ return dist_cls(
+ base_dir,
+ project_name=dist_name,
+ metadata=metadata,
+ )
+
+
class InstallRequirement(object):
"""
Represents something that may be installed later on, may have information
@@ -64,34 +103,49 @@ class InstallRequirement(object):
self,
req, # type: Optional[Requirement]
comes_from, # type: Optional[Union[str, InstallRequirement]]
- source_dir=None, # type: Optional[str]
editable=False, # type: bool
link=None, # type: Optional[Link]
- update=True, # type: bool
markers=None, # type: Optional[Marker]
use_pep517=None, # type: Optional[bool]
isolated=False, # type: bool
- options=None, # type: Optional[Dict[str, Any]]
- wheel_cache=None, # type: Optional[WheelCache]
+ install_options=None, # type: Optional[List[str]]
+ global_options=None, # type: Optional[List[str]]
+ hash_options=None, # type: Optional[Dict[str, List[str]]]
constraint=False, # type: bool
- extras=() # type: Iterable[str]
+ extras=(), # type: Iterable[str]
+ user_supplied=False, # type: bool
):
# type: (...) -> None
assert req is None or isinstance(req, Requirement), req
self.req = req
self.comes_from = comes_from
self.constraint = constraint
- if source_dir is None:
- self.source_dir = None # type: Optional[str]
- else:
- self.source_dir = os.path.normpath(os.path.abspath(source_dir))
self.editable = editable
+ self.legacy_install_reason = None # type: Optional[int]
+
+ # source_dir is the local directory where the linked requirement is
+ # located, or unpacked. In case unpacking is needed, creating and
+ # populating source_dir is done by the RequirementPreparer. Note this
+ # is not necessarily the directory where pyproject.toml or setup.py is
+ # located - that one is obtained via unpacked_source_directory.
+ self.source_dir = None # type: Optional[str]
+ if self.editable:
+ assert link
+ if link.is_file:
+ self.source_dir = os.path.normpath(
+ os.path.abspath(link.file_path)
+ )
- self._wheel_cache = wheel_cache
if link is None and req and req.url:
# PEP 508 URL requirement
link = Link(req.url)
self.link = self.original_link = link
+ self.original_link_is_in_wheel_cache = False
+
+ # Path to any downloaded or already-existing package.
+ self.local_file_path = None # type: Optional[str]
+ if self.link and self.link.is_file:
+ self.local_file_path = self.link.file_path
if extras:
self.extras = extras
@@ -105,28 +159,35 @@ class InstallRequirement(object):
markers = req.marker
self.markers = markers
- self._egg_info_path = None # type: Optional[str]
# This holds the pkg_resources.Distribution object if this requirement
# is already available:
- self.satisfied_by = None
- # This hold the pkg_resources.Distribution object if this requirement
- # conflicts with another installed distribution:
- self.conflicts_with = None
+ self.satisfied_by = None # type: Optional[Distribution]
+ # Whether the installation process should try to uninstall an existing
+ # distribution before installing this requirement.
+ self.should_reinstall = False
# Temporary build location
- self._temp_build_dir = TempDirectory(kind="req-build")
- # Used to store the global directory where the _temp_build_dir should
- # have been created. Cf _correct_build_location method.
- self._ideal_build_dir = None # type: Optional[str]
- # True if the editable should be updated:
- self.update = update
+ self._temp_build_dir = None # type: Optional[TempDirectory]
# Set to True after successful installation
self.install_succeeded = None # type: Optional[bool]
- # UninstallPathSet of uninstalled distribution (for possible rollback)
- self.uninstalled_pathset = None
- self.options = options if options else {}
+ # Supplied options
+ self.install_options = install_options if install_options else []
+ self.global_options = global_options if global_options else []
+ self.hash_options = hash_options if hash_options else {}
# Set to True after successful preparation of this requirement
self.prepared = False
- self.is_direct = False
+ # User supplied requirement are explicitly requested for installation
+ # by the user via CLI arguments or requirements files, as opposed to,
+ # e.g. dependencies, extras or constraints.
+ self.user_supplied = user_supplied
+
+ # Set by the legacy resolver when the requirement has been downloaded
+ # TODO: This introduces a strong coupling between the resolver and the
+ # requirement (the coupling was previously between the resolver
+ # and the requirement set). This should be refactored to allow
+ # the requirement to decide for itself when it has been
+ # successfully downloaded - but that is more tricky to get right,
+ # se we are making the change in stages.
+ self.successfully_downloaded = False
self.isolated = isolated
self.build_env = NoOpBuildEnvironment() # type: BuildEnvironment
@@ -158,25 +219,25 @@ class InstallRequirement(object):
if self.req:
s = str(self.req)
if self.link:
- s += ' from %s' % redact_password_from_url(self.link.url)
+ s += ' from {}'.format(redact_auth_from_url(self.link.url))
elif self.link:
- s = redact_password_from_url(self.link.url)
+ s = redact_auth_from_url(self.link.url)
else:
s = ''
if self.satisfied_by is not None:
- s += ' in %s' % display_path(self.satisfied_by.location)
+ s += ' in {}'.format(display_path(self.satisfied_by.location))
if self.comes_from:
if isinstance(self.comes_from, six.string_types):
comes_from = self.comes_from # type: Optional[str]
else:
comes_from = self.comes_from.from_path()
if comes_from:
- s += ' (from %s)' % comes_from
+ s += ' (from {})'.format(comes_from)
return s
def __repr__(self):
# type: () -> str
- return '<%s object: %s editable=%r>' % (
+ return '<{} object: {} editable={!r}>'.format(
self.__class__.__name__, str(self), self.editable)
def format_debug(self):
@@ -194,34 +255,13 @@ class InstallRequirement(object):
state=", ".join(state),
)
- def populate_link(self, finder, upgrade, require_hashes):
- # type: (PackageFinder, bool, bool) -> None
- """Ensure that if a link can be found for this, that it is found.
-
- Note that self.link may still be None - if Upgrade is False and the
- requirement is already installed.
-
- If require_hashes is True, don't use the wheel cache, because cached
- wheels, always built locally, have different hashes than the files
- downloaded from the index server and thus throw false hash mismatches.
- Furthermore, cached wheels at present have undeterministic contents due
- to file modification times.
- """
- if self.link is None:
- self.link = finder.find_requirement(self, upgrade)
- if self._wheel_cache is not None and not require_hashes:
- old_link = self.link
- self.link = self._wheel_cache.get(self.link, self.name)
- if old_link != self.link:
- logger.debug('Using cached wheel link: %s', self.link)
-
# Things that are valid for all kinds of requirements?
@property
def name(self):
# type: () -> Optional[str]
if self.req is None:
return None
- return native_str(pkg_resources.safe_name(self.req.name))
+ return six.ensure_str(pkg_resources.safe_name(self.req.name))
@property
def specifier(self):
@@ -266,7 +306,7 @@ class InstallRequirement(object):
URL do not.
"""
- return bool(self.options.get('hashes', {}))
+ return bool(self.hash_options)
def hashes(self, trust_internet=True):
# type: (bool) -> Hashes
@@ -284,7 +324,7 @@ class InstallRequirement(object):
downloaded from the internet, as by populate_link()
"""
- good_hashes = self.options.get('hashes', {}).copy()
+ good_hashes = self.hash_options.copy()
link = self.link if trust_internet else self.original_link
if link and link.hash:
good_hashes.setdefault(link.hash_name, []).append(link.hash)
@@ -306,130 +346,117 @@ class InstallRequirement(object):
s += '->' + comes_from
return s
- def build_location(self, build_dir):
- # type: (str) -> str
+ def ensure_build_location(self, build_dir, autodelete, parallel_builds):
+ # type: (str, bool, bool) -> str
assert build_dir is not None
- if self._temp_build_dir.path is not None:
+ if self._temp_build_dir is not None:
+ assert self._temp_build_dir.path
return self._temp_build_dir.path
if self.req is None:
- # for requirement via a path to a directory: the name of the
- # package is not available yet so we create a temp directory
- # Once run_egg_info will have run, we'll be able
- # to fix it via _correct_build_location
# Some systems have /tmp as a symlink which confuses custom
# builds (such as numpy). Thus, we ensure that the real path
# is returned.
- self._temp_build_dir.create()
- self._ideal_build_dir = build_dir
+ self._temp_build_dir = TempDirectory(
+ kind=tempdir_kinds.REQ_BUILD, globally_managed=True
+ )
return self._temp_build_dir.path
- if self.editable:
- name = self.name.lower()
- else:
- name = self.name
+
+ # When parallel builds are enabled, add a UUID to the build directory
+ # name so multiple builds do not interfere with each other.
+ dir_name = canonicalize_name(self.name)
+ if parallel_builds:
+ dir_name = "{}_{}".format(dir_name, uuid.uuid4().hex)
+
# FIXME: Is there a better place to create the build_dir? (hg and bzr
# need this)
if not os.path.exists(build_dir):
logger.debug('Creating directory %s', build_dir)
- _make_build_dir(build_dir)
- return os.path.join(build_dir, name)
+ os.makedirs(build_dir)
+ actual_build_dir = os.path.join(build_dir, dir_name)
+ # `None` indicates that we respect the globally-configured deletion
+ # settings, which is what we actually want when auto-deleting.
+ delete_arg = None if autodelete else False
+ return TempDirectory(
+ path=actual_build_dir,
+ delete=delete_arg,
+ kind=tempdir_kinds.REQ_BUILD,
+ globally_managed=True,
+ ).path
- def _correct_build_location(self):
+ def _set_requirement(self):
# type: () -> None
- """Move self._temp_build_dir to self._ideal_build_dir/self.req.name
-
- For some requirements (e.g. a path to a directory), the name of the
- package is not available until we run egg_info, so the build_location
- will return a temporary directory and store the _ideal_build_dir.
-
- This is only called by self.run_egg_info to fix the temporary build
- directory.
+ """Set requirement after generating metadata.
"""
- if self.source_dir is not None:
- return
- assert self.req is not None
- assert self._temp_build_dir.path
- assert (self._ideal_build_dir is not None and
- self._ideal_build_dir.path) # type: ignore
- old_location = self._temp_build_dir.path
- self._temp_build_dir.path = None
+ assert self.req is None
+ assert self.metadata is not None
+ assert self.source_dir is not None
- new_location = self.build_location(self._ideal_build_dir)
- if os.path.exists(new_location):
- raise InstallationError(
- 'A package already exists in %s; please remove it to continue'
- % display_path(new_location))
- logger.debug(
- 'Moving package %s from %s to new location %s',
- self, display_path(old_location), display_path(new_location),
+ # Construct a Requirement object from the generated metadata
+ if isinstance(parse_version(self.metadata["Version"]), Version):
+ op = "=="
+ else:
+ op = "==="
+
+ self.req = Requirement(
+ "".join([
+ self.metadata["Name"],
+ op,
+ self.metadata["Version"],
+ ])
)
- shutil.move(old_location, new_location)
- self._temp_build_dir.path = new_location
- self._ideal_build_dir = None
- self.source_dir = os.path.normpath(os.path.abspath(new_location))
- self._egg_info_path = None
- # Correct the metadata directory, if it exists
- if self.metadata_directory:
- old_meta = self.metadata_directory
- rel = os.path.relpath(old_meta, start=old_location)
- new_meta = os.path.join(new_location, rel)
- new_meta = os.path.normpath(os.path.abspath(new_meta))
- self.metadata_directory = new_meta
-
- def remove_temporary_source(self):
+ def warn_on_mismatching_name(self):
# type: () -> None
- """Remove the source files from this requirement, if they are marked
- for deletion"""
- if self.source_dir and os.path.exists(
- os.path.join(self.source_dir, PIP_DELETE_MARKER_FILENAME)):
- logger.debug('Removing source in %s', self.source_dir)
- rmtree(self.source_dir)
- self.source_dir = None
- self._temp_build_dir.cleanup()
- self.build_env.cleanup()
+ metadata_name = canonicalize_name(self.metadata["Name"])
+ if canonicalize_name(self.req.name) == metadata_name:
+ # Everything is fine.
+ return
+
+ # If we're here, there's a mismatch. Log a warning about it.
+ logger.warning(
+ 'Generating metadata for package %s '
+ 'produced metadata for project name %s. Fix your '
+ '#egg=%s fragments.',
+ self.name, metadata_name, self.name
+ )
+ self.req = Requirement(metadata_name)
def check_if_exists(self, use_user_site):
- # type: (bool) -> bool
+ # type: (bool) -> None
"""Find an installed distribution that satisfies or conflicts
with this requirement, and set self.satisfied_by or
- self.conflicts_with appropriately.
+ self.should_reinstall appropriately.
"""
if self.req is None:
- return False
- try:
- # get_distribution() will resolve the entire list of requirements
- # anyway, and we've already determined that we need the requirement
- # in question, so strip the marker so that we don't try to
- # evaluate it.
- no_marker = Requirement(str(self.req))
- no_marker.marker = None
- self.satisfied_by = pkg_resources.get_distribution(str(no_marker))
- if self.editable and self.satisfied_by:
- self.conflicts_with = self.satisfied_by
- # when installing editables, nothing pre-existing should ever
- # satisfy
- self.satisfied_by = None
- return True
- except pkg_resources.DistributionNotFound:
- return False
- except pkg_resources.VersionConflict:
- existing_dist = pkg_resources.get_distribution(
- self.req.name
- )
+ return
+ existing_dist = get_distribution(self.req.name)
+ if not existing_dist:
+ return
+
+ existing_version = existing_dist.parsed_version
+ if not self.req.specifier.contains(existing_version, prereleases=True):
+ self.satisfied_by = None
if use_user_site:
if dist_in_usersite(existing_dist):
- self.conflicts_with = existing_dist
+ self.should_reinstall = True
elif (running_under_virtualenv() and
dist_in_site_packages(existing_dist)):
raise InstallationError(
"Will not install to the user site because it will "
- "lack sys.path precedence to %s in %s" %
- (existing_dist.project_name, existing_dist.location)
+ "lack sys.path precedence to {} in {}".format(
+ existing_dist.project_name, existing_dist.location)
)
else:
- self.conflicts_with = existing_dist
- return True
+ self.should_reinstall = True
+ else:
+ if self.editable:
+ self.should_reinstall = True
+ # when installing editables, nothing pre-existing should ever
+ # satisfy
+ self.satisfied_by = None
+ else:
+ self.satisfied_by = existing_dist
# Things valid for wheels
@property
@@ -439,31 +466,9 @@ class InstallRequirement(object):
return False
return self.link.is_wheel
- def move_wheel_files(
- self,
- wheeldir, # type: str
- root=None, # type: Optional[str]
- home=None, # type: Optional[str]
- prefix=None, # type: Optional[str]
- warn_script_location=True, # type: bool
- use_user_site=False, # type: bool
- pycompile=True # type: bool
- ):
- # type: (...) -> None
- wheel.move_wheel_files(
- self.name, self.req, wheeldir,
- user=use_user_site,
- home=home,
- root=root,
- prefix=prefix,
- pycompile=pycompile,
- isolated=self.isolated,
- warn_script_location=warn_script_location,
- )
-
# Things valid for sdists
@property
- def setup_py_dir(self):
+ def unpacked_source_directory(self):
# type: () -> str
return os.path.join(
self.source_dir,
@@ -472,9 +477,8 @@ class InstallRequirement(object):
@property
def setup_py_path(self):
# type: () -> str
- assert self.source_dir, "No source dir for %s" % self
-
- setup_py = os.path.join(self.setup_py_dir, 'setup.py')
+ assert self.source_dir, "No source dir for {}".format(self)
+ setup_py = os.path.join(self.unpacked_source_directory, 'setup.py')
# Python2 __file__ should not be unicode
if six.PY2 and isinstance(setup_py, six.text_type):
@@ -485,9 +489,8 @@ class InstallRequirement(object):
@property
def pyproject_toml_path(self):
# type: () -> str
- assert self.source_dir, "No source dir for %s" % self
-
- return make_pyproject_path(self.setup_py_dir)
+ assert self.source_dir, "No source dir for {}".format(self)
+ return make_pyproject_path(self.unpacked_source_directory)
def load_pyproject_toml(self):
# type: () -> None
@@ -505,35 +508,39 @@ class InstallRequirement(object):
str(self)
)
- self.use_pep517 = (pyproject_toml_data is not None)
-
- if not self.use_pep517:
+ if pyproject_toml_data is None:
+ self.use_pep517 = False
return
- requires, backend, check = pyproject_toml_data
+ self.use_pep517 = True
+ requires, backend, check, backend_path = pyproject_toml_data
self.requirements_to_check = check
self.pyproject_requires = requires
- self.pep517_backend = Pep517HookCaller(self.setup_py_dir, backend)
+ self.pep517_backend = Pep517HookCaller(
+ self.unpacked_source_directory, backend, backend_path=backend_path,
+ )
- # Use a custom function to call subprocesses
- self.spin_message = ""
+ def _generate_metadata(self):
+ # type: () -> str
+ """Invokes metadata generator functions, with the required arguments.
+ """
+ if not self.use_pep517:
+ assert self.unpacked_source_directory
- def runner(
- cmd, # type: List[str]
- cwd=None, # type: Optional[str]
- extra_environ=None # type: Optional[Mapping[str, Any]]
- ):
- # type: (...) -> None
- with open_spinner(self.spin_message) as spinner:
- call_subprocess(
- cmd,
- cwd=cwd,
- extra_environ=extra_environ,
- spinner=spinner
- )
- self.spin_message = ""
+ return generate_metadata_legacy(
+ build_env=self.build_env,
+ setup_py_path=self.setup_py_path,
+ source_dir=self.unpacked_source_directory,
+ isolated=self.isolated,
+ details=self.name or "from {}".format(self.link)
+ )
- self.pep517_backend._subprocess_runner = runner
+ assert self.pep517_backend is not None
+
+ return generate_metadata(
+ build_env=self.build_env,
+ backend=self.pep517_backend,
+ )
def prepare_metadata(self):
# type: () -> None
@@ -545,140 +552,15 @@ class InstallRequirement(object):
assert self.source_dir
with indent_log():
- if self.use_pep517:
- self.prepare_pep517_metadata()
- else:
- self.run_egg_info()
+ self.metadata_directory = self._generate_metadata()
- if not self.req:
- if isinstance(parse_version(self.metadata["Version"]), Version):
- op = "=="
- else:
- op = "==="
- self.req = Requirement(
- "".join([
- self.metadata["Name"],
- op,
- self.metadata["Version"],
- ])
- )
- self._correct_build_location()
+ # Act on the newly generated metadata, based on the name and version.
+ if not self.name:
+ self._set_requirement()
else:
- metadata_name = canonicalize_name(self.metadata["Name"])
- if canonicalize_name(self.req.name) != metadata_name:
- logger.warning(
- 'Generating metadata for package %s '
- 'produced metadata for project name %s. Fix your '
- '#egg=%s fragments.',
- self.name, metadata_name, self.name
- )
- self.req = Requirement(metadata_name)
+ self.warn_on_mismatching_name()
- def prepare_pep517_metadata(self):
- # type: () -> None
- assert self.pep517_backend is not None
-
- metadata_dir = os.path.join(
- self.setup_py_dir,
- 'pip-wheel-metadata'
- )
- ensure_dir(metadata_dir)
-
- with self.build_env:
- # Note that Pep517HookCaller implements a fallback for
- # prepare_metadata_for_build_wheel, so we don't have to
- # consider the possibility that this hook doesn't exist.
- backend = self.pep517_backend
- self.spin_message = "Preparing wheel metadata"
- distinfo_dir = backend.prepare_metadata_for_build_wheel(
- metadata_dir
- )
-
- self.metadata_directory = os.path.join(metadata_dir, distinfo_dir)
-
- def run_egg_info(self):
- # type: () -> None
- if self.name:
- logger.debug(
- 'Running setup.py (path:%s) egg_info for package %s',
- self.setup_py_path, self.name,
- )
- else:
- logger.debug(
- 'Running setup.py (path:%s) egg_info for package from %s',
- self.setup_py_path, self.link,
- )
- base_cmd = make_setuptools_shim_args(self.setup_py_path)
- if self.isolated:
- base_cmd += ["--no-user-cfg"]
- egg_info_cmd = base_cmd + ['egg_info']
- # We can't put the .egg-info files at the root, because then the
- # source code will be mistaken for an installed egg, causing
- # problems
- if self.editable:
- egg_base_option = [] # type: List[str]
- else:
- egg_info_dir = os.path.join(self.setup_py_dir, 'pip-egg-info')
- ensure_dir(egg_info_dir)
- egg_base_option = ['--egg-base', 'pip-egg-info']
- with self.build_env:
- call_subprocess(
- egg_info_cmd + egg_base_option,
- cwd=self.setup_py_dir,
- command_desc='python setup.py egg_info')
-
- @property
- def egg_info_path(self):
- # type: () -> str
- if self._egg_info_path is None:
- if self.editable:
- base = self.source_dir
- else:
- base = os.path.join(self.setup_py_dir, 'pip-egg-info')
- filenames = os.listdir(base)
- if self.editable:
- filenames = []
- for root, dirs, files in os.walk(base):
- for dir in vcs.dirnames:
- if dir in dirs:
- dirs.remove(dir)
- # Iterate over a copy of ``dirs``, since mutating
- # a list while iterating over it can cause trouble.
- # (See https://github.com/pypa/pip/pull/462.)
- for dir in list(dirs):
- # Don't search in anything that looks like a virtualenv
- # environment
- if (
- os.path.lexists(
- os.path.join(root, dir, 'bin', 'python')
- ) or
- os.path.exists(
- os.path.join(
- root, dir, 'Scripts', 'Python.exe'
- )
- )):
- dirs.remove(dir)
- # Also don't search through tests
- elif dir == 'test' or dir == 'tests':
- dirs.remove(dir)
- filenames.extend([os.path.join(root, dir)
- for dir in dirs])
- filenames = [f for f in filenames if f.endswith('.egg-info')]
-
- if not filenames:
- raise InstallationError(
- "Files/directories not found in %s" % base
- )
- # if we have more than one match, we pick the toplevel one. This
- # can easily be the case if there is a dist folder which contains
- # an extracted tarball for testing purposes.
- if len(filenames) > 1:
- filenames.sort(
- key=lambda x: x.count(os.path.sep) +
- (os.path.altsep and x.count(os.path.altsep) or 0)
- )
- self._egg_info_path = os.path.join(base, filenames[0])
- return self._egg_info_path
+ self.assert_source_matches_version()
@property
def metadata(self):
@@ -690,26 +572,7 @@ class InstallRequirement(object):
def get_dist(self):
# type: () -> Distribution
- """Return a pkg_resources.Distribution for this requirement"""
- if self.metadata_directory:
- dist_dir = self.metadata_directory
- dist_cls = pkg_resources.DistInfoDistribution
- else:
- dist_dir = self.egg_info_path.rstrip(os.path.sep)
- # https://github.com/python/mypy/issues/1174
- dist_cls = pkg_resources.Distribution # type: ignore
-
- # dist_dir_name can be of the form ".dist-info" or
- # e.g. ".egg-info".
- base_dir, dist_dir_name = os.path.split(dist_dir)
- dist_name = os.path.splitext(dist_dir_name)[0]
- metadata = pkg_resources.PathMetadata(base_dir, dist_dir)
-
- return dist_cls(
- base_dir,
- project_name=dist_name,
- metadata=metadata,
- )
+ return _get_dist(self.metadata_directory)
def assert_source_matches_version(self):
# type: () -> None
@@ -730,8 +593,13 @@ class InstallRequirement(object):
)
# For both source distributions and editables
- def ensure_has_source_dir(self, parent_dir):
- # type: (str) -> str
+ def ensure_has_source_dir(
+ self,
+ parent_dir,
+ autodelete=False,
+ parallel_builds=False,
+ ):
+ # type: (str, bool, bool) -> None
"""Ensure that a source_dir is set.
This will create a temporary build dir if the name of the requirement
@@ -742,40 +610,13 @@ class InstallRequirement(object):
:return: self.source_dir
"""
if self.source_dir is None:
- self.source_dir = self.build_location(parent_dir)
- return self.source_dir
+ self.source_dir = self.ensure_build_location(
+ parent_dir,
+ autodelete=autodelete,
+ parallel_builds=parallel_builds,
+ )
# For editable installations
- def install_editable(
- self,
- install_options, # type: List[str]
- global_options=(), # type: Sequence[str]
- prefix=None # type: Optional[str]
- ):
- # type: (...) -> None
- logger.info('Running setup.py develop for %s', self.name)
-
- if self.isolated:
- global_options = list(global_options) + ["--no-user-cfg"]
-
- if prefix:
- prefix_param = ['--prefix={}'.format(prefix)]
- install_options = list(install_options) + prefix_param
-
- with indent_log():
- # FIXME: should we do --install-headers here too?
- with self.build_env:
- call_subprocess(
- make_setuptools_shim_args(self.setup_py_path) +
- list(global_options) +
- ['develop', '--no-deps'] +
- list(install_options),
-
- cwd=self.setup_py_dir,
- )
-
- self.install_succeeded = True
-
def update_editable(self, obtain=True):
# type: (bool) -> None
if not self.link:
@@ -790,26 +631,38 @@ class InstallRequirement(object):
if self.link.scheme == 'file':
# Static paths don't get updated
return
- assert '+' in self.link.url, "bad url: %r" % self.link.url
- if not self.update:
- return
+ assert '+' in self.link.url, \
+ "bad url: {self.link.url!r}".format(**locals())
vc_type, url = self.link.url.split('+', 1)
vcs_backend = vcs.get_backend(vc_type)
if vcs_backend:
- url = self.link.url
+ if not self.link.is_vcs:
+ reason = (
+ "This form of VCS requirement is being deprecated: {}."
+ ).format(
+ self.link.url
+ )
+ replacement = None
+ if self.link.url.startswith("git+git@"):
+ replacement = (
+ "git+https://git@example.com/..., "
+ "git+ssh://git@example.com/..., "
+ "or the insecure git+git://git@example.com/..."
+ )
+ deprecated(reason, replacement, gone_in="21.0", issue=7554)
+ hidden_url = hide_url(self.link.url)
if obtain:
- vcs_backend.obtain(self.source_dir, url=url)
+ vcs_backend.obtain(self.source_dir, url=hidden_url)
else:
- vcs_backend.export(self.source_dir, url=url)
+ vcs_backend.export(self.source_dir, url=hidden_url)
else:
assert 0, (
- 'Unexpected version control type (in %s): %s'
- % (self.link, vc_type))
+ 'Unexpected version control type (in {}): {}'.format(
+ self.link, vc_type))
# Top-level Actions
- def uninstall(self, auto_confirm=False, verbose=False,
- use_user_site=False):
- # type: (bool, bool, bool) -> Optional[UninstallPathSet]
+ def uninstall(self, auto_confirm=False, verbose=False):
+ # type: (bool, bool) -> Optional[UninstallPathSet]
"""
Uninstall the distribution currently satisfying this requirement.
@@ -822,42 +675,52 @@ class InstallRequirement(object):
linked to global site-packages.
"""
- if not self.check_if_exists(use_user_site):
+ assert self.req
+ dist = get_distribution(self.req.name)
+ if not dist:
logger.warning("Skipping %s as it is not installed.", self.name)
return None
- dist = self.satisfied_by or self.conflicts_with
+ logger.info('Found existing installation: %s', dist)
uninstalled_pathset = UninstallPathSet.from_dist(dist)
uninstalled_pathset.remove(auto_confirm, verbose)
return uninstalled_pathset
- def _clean_zip_name(self, name, prefix): # only used by archive.
- # type: (str, str) -> str
- assert name.startswith(prefix + os.path.sep), (
- "name %r doesn't start with prefix %r" % (name, prefix)
- )
- name = name[len(prefix) + 1:]
- name = name.replace(os.path.sep, '/')
- return name
-
def _get_archive_name(self, path, parentdir, rootdir):
# type: (str, str, str) -> str
+
+ def _clean_zip_name(name, prefix):
+ # type: (str, str) -> str
+ assert name.startswith(prefix + os.path.sep), (
+ "name {name!r} doesn't start with prefix {prefix!r}"
+ .format(**locals())
+ )
+ name = name[len(prefix) + 1:]
+ name = name.replace(os.path.sep, '/')
+ return name
+
path = os.path.join(parentdir, path)
- name = self._clean_zip_name(path, rootdir)
+ name = _clean_zip_name(path, rootdir)
return self.name + '/' + name
- # TODO: Investigate if this should be kept in InstallRequirement
- # Seems to be used only when VCS + downloads
def archive(self, build_dir):
# type: (str) -> None
+ """Saves archive to provided build_dir.
+
+ Used for saving downloaded VCS requirements as part of `pip download`.
+ """
assert self.source_dir
+
create_archive = True
- archive_name = '%s-%s.zip' % (self.name, self.metadata["version"])
+ archive_name = '{}-{}.zip'.format(self.name, self.metadata["version"])
archive_path = os.path.join(build_dir, archive_name)
+
if os.path.exists(archive_path):
response = ask_path_exists(
- 'The file %s exists. (i)gnore, (w)ipe, (b)ackup, (a)bort ' %
- display_path(archive_path), ('i', 'w', 'b', 'a'))
+ 'The file {} exists. (i)gnore, (w)ipe, '
+ '(b)ackup, (a)bort '.format(
+ display_path(archive_path)),
+ ('i', 'w', 'b', 'a'))
if response == 'i':
create_archive = False
elif response == 'w':
@@ -873,32 +736,33 @@ class InstallRequirement(object):
shutil.move(archive_path, dest_file)
elif response == 'a':
sys.exit(-1)
- if create_archive:
- zip = zipfile.ZipFile(
- archive_path, 'w', zipfile.ZIP_DEFLATED,
- allowZip64=True
+
+ if not create_archive:
+ return
+
+ zip_output = zipfile.ZipFile(
+ archive_path, 'w', zipfile.ZIP_DEFLATED, allowZip64=True,
+ )
+ with zip_output:
+ dir = os.path.normcase(
+ os.path.abspath(self.unpacked_source_directory)
)
- dir = os.path.normcase(os.path.abspath(self.setup_py_dir))
for dirpath, dirnames, filenames in os.walk(dir):
- if 'pip-egg-info' in dirnames:
- dirnames.remove('pip-egg-info')
for dirname in dirnames:
- dir_arcname = self._get_archive_name(dirname,
- parentdir=dirpath,
- rootdir=dir)
+ dir_arcname = self._get_archive_name(
+ dirname, parentdir=dirpath, rootdir=dir,
+ )
zipdir = zipfile.ZipInfo(dir_arcname + '/')
zipdir.external_attr = 0x1ED << 16 # 0o755
- zip.writestr(zipdir, '')
+ zip_output.writestr(zipdir, '')
for filename in filenames:
- if filename == PIP_DELETE_MARKER_FILENAME:
- continue
- file_arcname = self._get_archive_name(filename,
- parentdir=dirpath,
- rootdir=dir)
+ file_arcname = self._get_archive_name(
+ filename, parentdir=dirpath, rootdir=dir,
+ )
filename = os.path.join(dirpath, filename)
- zip.write(filename, file_arcname)
- zip.close()
- logger.info('Saved %s', display_path(archive_path))
+ zip_output.write(filename, file_arcname)
+
+ logger.info('Saved %s', display_path(archive_path))
def install(
self,
@@ -912,124 +776,130 @@ class InstallRequirement(object):
pycompile=True # type: bool
):
# type: (...) -> None
+ scheme = get_scheme(
+ self.name,
+ user=use_user_site,
+ home=home,
+ root=root,
+ isolated=self.isolated,
+ prefix=prefix,
+ )
+
global_options = global_options if global_options is not None else []
if self.editable:
- self.install_editable(
- install_options, global_options, prefix=prefix,
- )
- return
- if self.is_wheel:
- version = wheel.wheel_version(self.source_dir)
- wheel.check_compatibility(version, self.name)
-
- self.move_wheel_files(
- self.source_dir, root=root, prefix=prefix, home=home,
- warn_script_location=warn_script_location,
- use_user_site=use_user_site, pycompile=pycompile,
+ install_editable_legacy(
+ install_options,
+ global_options,
+ prefix=prefix,
+ home=home,
+ use_user_site=use_user_site,
+ name=self.name,
+ setup_py_path=self.setup_py_path,
+ isolated=self.isolated,
+ build_env=self.build_env,
+ unpacked_source_directory=self.unpacked_source_directory,
)
self.install_succeeded = True
return
+ if self.is_wheel:
+ assert self.local_file_path
+ direct_url = None
+ if self.original_link:
+ direct_url = direct_url_from_link(
+ self.original_link,
+ self.source_dir,
+ self.original_link_is_in_wheel_cache,
+ )
+ install_wheel(
+ self.name,
+ self.local_file_path,
+ scheme=scheme,
+ req_description=str(self.req),
+ pycompile=pycompile,
+ warn_script_location=warn_script_location,
+ direct_url=direct_url,
+ requested=self.user_supplied,
+ )
+ self.install_succeeded = True
+ return
+
+ # TODO: Why don't we do this for editable installs?
+
# Extend the list of global and install options passed on to
# the setup.py call with the ones from the requirements file.
# Options specified in requirements file override those
# specified on the command line, since the last option given
# to setup.py is the one that is used.
- global_options = list(global_options) + \
- self.options.get('global_options', [])
- install_options = list(install_options) + \
- self.options.get('install_options', [])
+ global_options = list(global_options) + self.global_options
+ install_options = list(install_options) + self.install_options
- if self.isolated:
- # https://github.com/python/mypy/issues/1174
- global_options = global_options + ["--no-user-cfg"] # type: ignore
-
- with TempDirectory(kind="record") as temp_dir:
- record_filename = os.path.join(temp_dir.path, 'install-record.txt')
- install_args = self.get_install_args(
- global_options, record_filename, root, prefix, pycompile,
+ try:
+ success = install_legacy(
+ install_options=install_options,
+ global_options=global_options,
+ root=root,
+ home=home,
+ prefix=prefix,
+ use_user_site=use_user_site,
+ pycompile=pycompile,
+ scheme=scheme,
+ setup_py_path=self.setup_py_path,
+ isolated=self.isolated,
+ req_name=self.name,
+ build_env=self.build_env,
+ unpacked_source_directory=self.unpacked_source_directory,
+ req_description=str(self.req),
)
- msg = 'Running setup.py install for %s' % (self.name,)
- with open_spinner(msg) as spinner:
- with indent_log():
- with self.build_env:
- call_subprocess(
- install_args + install_options,
- cwd=self.setup_py_dir,
- spinner=spinner,
- )
-
- if not os.path.exists(record_filename):
- logger.debug('Record file %s not found', record_filename)
- return
+ except LegacyInstallFailure as exc:
+ self.install_succeeded = False
+ six.reraise(*exc.parent)
+ except Exception:
self.install_succeeded = True
+ raise
- def prepend_root(path):
- # type: (str) -> str
- if root is None or not os.path.isabs(path):
- return path
- else:
- return change_root(root, path)
+ self.install_succeeded = success
- with open(record_filename) as f:
- for line in f:
- directory = os.path.dirname(line)
- if directory.endswith('.egg-info'):
- egg_info_dir = prepend_root(directory)
- break
- else:
- logger.warning(
- 'Could not find .egg-info directory in install record'
- ' for %s',
- self,
- )
- # FIXME: put the record somewhere
- # FIXME: should this be an error?
- return
- new_lines = []
- with open(record_filename) as f:
- for line in f:
- filename = line.strip()
- if os.path.isdir(filename):
- filename += os.path.sep
- new_lines.append(
- os.path.relpath(prepend_root(filename), egg_info_dir)
- )
- new_lines.sort()
- ensure_dir(egg_info_dir)
- inst_files_path = os.path.join(egg_info_dir, 'installed-files.txt')
- with open(inst_files_path, 'w') as f:
- f.write('\n'.join(new_lines) + '\n')
+ if success and self.legacy_install_reason == 8368:
+ deprecated(
+ reason=(
+ "{} was installed using the legacy 'setup.py install' "
+ "method, because a wheel could not be built for it.".
+ format(self.name)
+ ),
+ replacement="to fix the wheel build issue reported above",
+ gone_in="21.0",
+ issue=8368,
+ )
- def get_install_args(
- self,
- global_options, # type: Sequence[str]
- record_filename, # type: str
- root, # type: Optional[str]
- prefix, # type: Optional[str]
- pycompile # type: bool
- ):
- # type: (...) -> List[str]
- install_args = make_setuptools_shim_args(self.setup_py_path,
- unbuffered_output=True)
- install_args += list(global_options) + \
- ['install', '--record', record_filename]
- install_args += ['--single-version-externally-managed']
- if root is not None:
- install_args += ['--root', root]
- if prefix is not None:
- install_args += ['--prefix', prefix]
+def check_invalid_constraint_type(req):
+ # type: (InstallRequirement) -> str
- if pycompile:
- install_args += ["--compile"]
- else:
- install_args += ["--no-compile"]
+ # Check for unsupported forms
+ problem = ""
+ if not req.name:
+ problem = "Unnamed requirements are not allowed as constraints"
+ elif req.link:
+ problem = "Links are not allowed as constraints"
+ elif req.extras:
+ problem = "Constraints cannot have extras"
- if running_under_virtualenv():
- py_ver_str = 'python' + sysconfig.get_python_version()
- install_args += ['--install-headers',
- os.path.join(sys.prefix, 'include', 'site',
- py_ver_str, self.name)]
+ if problem:
+ deprecated(
+ reason=(
+ "Constraints are only allowed to take the form of a package "
+ "name and a version specifier. Other forms were originally "
+ "permitted as an accident of the implementation, but were "
+ "undocumented. The new implementation of the resolver no "
+ "longer supports these forms."
+ ),
+ replacement=(
+ "replacing the constraint with a requirement."
+ ),
+ # No plan yet for when the new resolver becomes default
+ gone_in=None,
+ issue=8210
+ )
- return install_args
+ return problem
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/req_set.py b/venv/lib/python3.8/site-packages/pip/_internal/req/req_set.py
index d1966a4..ab4b6f8 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/req/req_set.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/req/req_set.py
@@ -3,10 +3,12 @@ from __future__ import absolute_import
import logging
from collections import OrderedDict
+from pip._vendor.packaging.utils import canonicalize_name
+
from pip._internal.exceptions import InstallationError
-from pip._internal.utils.logging import indent_log
+from pip._internal.models.wheel import Wheel
+from pip._internal.utils import compatibility_tags
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
-from pip._internal.wheel import Wheel
if MYPY_CHECK_RUNNING:
from typing import Dict, Iterable, List, Optional, Tuple
@@ -18,35 +20,49 @@ logger = logging.getLogger(__name__)
class RequirementSet(object):
- def __init__(self, require_hashes=False, check_supported_wheels=True):
- # type: (bool, bool) -> None
+ def __init__(self, check_supported_wheels=True):
+ # type: (bool) -> None
"""Create a RequirementSet.
"""
self.requirements = OrderedDict() # type: Dict[str, InstallRequirement] # noqa: E501
- self.require_hashes = require_hashes
self.check_supported_wheels = check_supported_wheels
- # Mapping of alias: real_name
- self.requirement_aliases = {} # type: Dict[str, str]
self.unnamed_requirements = [] # type: List[InstallRequirement]
- self.successfully_downloaded = [] # type: List[InstallRequirement]
- self.reqs_to_cleanup = [] # type: List[InstallRequirement]
def __str__(self):
# type: () -> str
- reqs = [req for req in self.requirements.values()
- if not req.comes_from]
- reqs.sort(key=lambda req: req.name.lower())
- return ' '.join([str(req.req) for req in reqs])
+ requirements = sorted(
+ (req for req in self.requirements.values() if not req.comes_from),
+ key=lambda req: canonicalize_name(req.name),
+ )
+ return ' '.join(str(req.req) for req in requirements)
def __repr__(self):
# type: () -> str
- reqs = [req for req in self.requirements.values()]
- reqs.sort(key=lambda req: req.name.lower())
- reqs_str = ', '.join([str(req.req) for req in reqs])
- return ('<%s object; %d requirement(s): %s>'
- % (self.__class__.__name__, len(reqs), reqs_str))
+ requirements = sorted(
+ self.requirements.values(),
+ key=lambda req: canonicalize_name(req.name),
+ )
+
+ format_string = '<{classname} object; {count} requirement(s): {reqs}>'
+ return format_string.format(
+ classname=self.__class__.__name__,
+ count=len(requirements),
+ reqs=', '.join(str(req.req) for req in requirements),
+ )
+
+ def add_unnamed_requirement(self, install_req):
+ # type: (InstallRequirement) -> None
+ assert not install_req.name
+ self.unnamed_requirements.append(install_req)
+
+ def add_named_requirement(self, install_req):
+ # type: (InstallRequirement) -> None
+ assert install_req.name
+
+ project_name = canonicalize_name(install_req.name)
+ self.requirements[project_name] = install_req
def add_requirement(
self,
@@ -69,13 +85,11 @@ class RequirementSet(object):
the requirement is not applicable, or [install_req] if the
requirement is applicable and has just been added.
"""
- name = install_req.name
-
# If the markers do not match, ignore this requirement.
if not install_req.match_markers(extras_requested):
logger.info(
"Ignoring %s: markers '%s' don't match your environment",
- name, install_req.markers,
+ install_req.name, install_req.markers,
)
return [], None
@@ -85,27 +99,27 @@ class RequirementSet(object):
# single requirements file.
if install_req.link and install_req.link.is_wheel:
wheel = Wheel(install_req.link.filename)
- if self.check_supported_wheels and not wheel.supported():
+ tags = compatibility_tags.get_supported()
+ if (self.check_supported_wheels and not wheel.supported(tags)):
raise InstallationError(
- "%s is not a supported wheel on this platform." %
- wheel.filename
+ "{} is not a supported wheel on this platform.".format(
+ wheel.filename)
)
# This next bit is really a sanity check.
- assert install_req.is_direct == (parent_req_name is None), (
- "a direct req shouldn't have a parent and also, "
- "a non direct req should have a parent"
+ assert not install_req.user_supplied or parent_req_name is None, (
+ "a user supplied req shouldn't have a parent"
)
# Unnamed requirements are scanned again and the requirement won't be
# added as a dependency until after scanning.
- if not name:
- # url or path requirement w/o an egg fragment
- self.unnamed_requirements.append(install_req)
+ if not install_req.name:
+ self.add_unnamed_requirement(install_req)
return [install_req], None
try:
- existing_req = self.get_requirement(name)
+ existing_req = self.get_requirement(
+ install_req.name) # type: Optional[InstallRequirement]
except KeyError:
existing_req = None
@@ -118,18 +132,15 @@ class RequirementSet(object):
)
if has_conflicting_requirement:
raise InstallationError(
- "Double requirement given: %s (already in %s, name=%r)"
- % (install_req, existing_req, name)
+ "Double requirement given: {} (already in {}, name={!r})"
+ .format(install_req, existing_req, install_req.name)
)
# When no existing requirement exists, add the requirement as a
# dependency and it will be scanned again after.
if not existing_req:
- self.requirements[name] = install_req
- # FIXME: what about other normalizations? E.g., _ vs. -?
- if name.lower() != name:
- self.requirement_aliases[name.lower()] = name
- # We'd want to rescan this requirements later
+ self.add_named_requirement(install_req)
+ # We'd want to rescan this requirement later
return [install_req], install_req
# Assume there's no need to scan, and that we've already
@@ -145,15 +156,18 @@ class RequirementSet(object):
)
)
if does_not_satisfy_constraint:
- self.reqs_to_cleanup.append(install_req)
raise InstallationError(
- "Could not satisfy constraints for '%s': "
+ "Could not satisfy constraints for '{}': "
"installation from path or url cannot be "
- "constrained to a version" % name,
+ "constrained to a version".format(install_req.name)
)
# If we're now installing a constraint, mark the existing
# object for real installation.
existing_req.constraint = False
+ # If we're now installing a user supplied requirement,
+ # mark the existing object as such.
+ if install_req.user_supplied:
+ existing_req.user_supplied = True
existing_req.extras = tuple(sorted(
set(existing_req.extras) | set(install_req.extras)
))
@@ -165,29 +179,25 @@ class RequirementSet(object):
# scanning again.
return [existing_req], existing_req
- def has_requirement(self, project_name):
+ def has_requirement(self, name):
# type: (str) -> bool
- name = project_name.lower()
- if (name in self.requirements and
- not self.requirements[name].constraint or
- name in self.requirement_aliases and
- not self.requirements[self.requirement_aliases[name]].constraint):
- return True
- return False
+ project_name = canonicalize_name(name)
- def get_requirement(self, project_name):
+ return (
+ project_name in self.requirements and
+ not self.requirements[project_name].constraint
+ )
+
+ def get_requirement(self, name):
# type: (str) -> InstallRequirement
- for name in project_name, project_name.lower():
- if name in self.requirements:
- return self.requirements[name]
- if name in self.requirement_aliases:
- return self.requirements[self.requirement_aliases[name]]
- raise KeyError("No project with the name %r" % project_name)
+ project_name = canonicalize_name(name)
- def cleanup_files(self):
- # type: () -> None
- """Clean up files, remove builds."""
- logger.debug('Cleaning up...')
- with indent_log():
- for req in self.reqs_to_cleanup:
- req.remove_temporary_source()
+ if project_name in self.requirements:
+ return self.requirements[project_name]
+
+ raise KeyError("No project with the name {name!r}".format(**locals()))
+
+ @property
+ def all_requirements(self):
+ # type: () -> List[InstallRequirement]
+ return self.unnamed_requirements + list(self.requirements.values())
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/req_tracker.py b/venv/lib/python3.8/site-packages/pip/_internal/req/req_tracker.py
index e36a3f6..13fb245 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/req/req_tracker.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/req/req_tracker.py
@@ -6,35 +6,74 @@ import hashlib
import logging
import os
+from pip._vendor import contextlib2
+
from pip._internal.utils.temp_dir import TempDirectory
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
if MYPY_CHECK_RUNNING:
from types import TracebackType
- from typing import Iterator, Optional, Set, Type
+ from typing import Dict, Iterator, Optional, Set, Type, Union
from pip._internal.req.req_install import InstallRequirement
from pip._internal.models.link import Link
logger = logging.getLogger(__name__)
+@contextlib.contextmanager
+def update_env_context_manager(**changes):
+ # type: (str) -> Iterator[None]
+ target = os.environ
+
+ # Save values from the target and change them.
+ non_existent_marker = object()
+ saved_values = {} # type: Dict[str, Union[object, str]]
+ for name, new_value in changes.items():
+ try:
+ saved_values[name] = target[name]
+ except KeyError:
+ saved_values[name] = non_existent_marker
+ target[name] = new_value
+
+ try:
+ yield
+ finally:
+ # Restore original values in the target.
+ for name, original_value in saved_values.items():
+ if original_value is non_existent_marker:
+ del target[name]
+ else:
+ assert isinstance(original_value, str) # for mypy
+ target[name] = original_value
+
+
+@contextlib.contextmanager
+def get_requirement_tracker():
+ # type: () -> Iterator[RequirementTracker]
+ root = os.environ.get('PIP_REQ_TRACKER')
+ with contextlib2.ExitStack() as ctx:
+ if root is None:
+ root = ctx.enter_context(
+ TempDirectory(kind='req-tracker')
+ ).path
+ ctx.enter_context(update_env_context_manager(PIP_REQ_TRACKER=root))
+ logger.debug("Initialized build tracking at %s", root)
+
+ with RequirementTracker(root) as tracker:
+ yield tracker
+
+
class RequirementTracker(object):
- def __init__(self):
- # type: () -> None
- self._root = os.environ.get('PIP_REQ_TRACKER')
- if self._root is None:
- self._temp_dir = TempDirectory(delete=False, kind='req-tracker')
- self._temp_dir.create()
- self._root = os.environ['PIP_REQ_TRACKER'] = self._temp_dir.path
- logger.debug('Created requirements tracker %r', self._root)
- else:
- self._temp_dir = None
- logger.debug('Re-using requirements tracker %r', self._root)
+ def __init__(self, root):
+ # type: (str) -> None
+ self._root = root
self._entries = set() # type: Set[InstallRequirement]
+ logger.debug("Created build tracker: %s", self._root)
def __enter__(self):
# type: () -> RequirementTracker
+ logger.debug("Entered build tracker: %s", self._root)
return self
def __exit__(
@@ -53,40 +92,55 @@ class RequirementTracker(object):
def add(self, req):
# type: (InstallRequirement) -> None
- link = req.link
- info = str(req)
- entry_path = self._entry_path(link)
+ """Add an InstallRequirement to build tracking.
+ """
+
+ assert req.link
+ # Get the file to write information about this requirement.
+ entry_path = self._entry_path(req.link)
+
+ # Try reading from the file. If it exists and can be read from, a build
+ # is already in progress, so a LookupError is raised.
try:
with open(entry_path) as fp:
- # Error, these's already a build in progress.
- raise LookupError('%s is already being built: %s'
- % (link, fp.read()))
+ contents = fp.read()
except IOError as e:
+ # if the error is anything other than "file does not exist", raise.
if e.errno != errno.ENOENT:
raise
- assert req not in self._entries
- with open(entry_path, 'w') as fp:
- fp.write(info)
- self._entries.add(req)
- logger.debug('Added %s to build tracker %r', req, self._root)
+ else:
+ message = '{} is already being built: {}'.format(
+ req.link, contents)
+ raise LookupError(message)
+
+ # If we're here, req should really not be building already.
+ assert req not in self._entries
+
+ # Start tracking this requirement.
+ with open(entry_path, 'w') as fp:
+ fp.write(str(req))
+ self._entries.add(req)
+
+ logger.debug('Added %s to build tracker %r', req, self._root)
def remove(self, req):
# type: (InstallRequirement) -> None
- link = req.link
+ """Remove an InstallRequirement from build tracking.
+ """
+
+ assert req.link
+ # Delete the created file and the corresponding entries.
+ os.unlink(self._entry_path(req.link))
self._entries.remove(req)
- os.unlink(self._entry_path(link))
+
logger.debug('Removed %s from build tracker %r', req, self._root)
def cleanup(self):
# type: () -> None
for req in set(self._entries):
self.remove(req)
- remove = self._temp_dir is not None
- if remove:
- self._temp_dir.cleanup()
- logger.debug('%s build tracker %r',
- 'Removed' if remove else 'Cleaned',
- self._root)
+
+ logger.debug("Removed build tracker: %r", self._root)
@contextlib.contextmanager
def track(self, req):
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/req/req_uninstall.py b/venv/lib/python3.8/site-packages/pip/_internal/req/req_uninstall.py
index 733301c..69719d3 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/req/req_uninstall.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/req/req_uninstall.py
@@ -14,8 +14,15 @@ from pip._internal.locations import bin_py, bin_user
from pip._internal.utils.compat import WINDOWS, cache_from_source, uses_pycache
from pip._internal.utils.logging import indent_log
from pip._internal.utils.misc import (
- FakeFile, ask, dist_in_usersite, dist_is_local, egg_link_path, is_local,
- normalize_path, renames, rmtree,
+ FakeFile,
+ ask,
+ dist_in_usersite,
+ dist_is_local,
+ egg_link_path,
+ is_local,
+ normalize_path,
+ renames,
+ rmtree,
)
from pip._internal.utils.temp_dir import AdjacentTempDirectory, TempDirectory
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
@@ -52,7 +59,7 @@ def _script_names(dist, script_name, is_gui):
def _unique(fn):
- # type: (Callable) -> Callable[..., Iterator[Any]]
+ # type: (Callable[..., Iterator[Any]]) -> Callable[..., Iterator[Any]]
@functools.wraps(fn)
def unique(*args, **kw):
# type: (Any, Any) -> Iterator[Any]
@@ -220,10 +227,8 @@ class StashedUninstallPathSet(object):
try:
save_dir = AdjacentTempDirectory(path) # type: TempDirectory
- save_dir.create()
except OSError:
save_dir = TempDirectory(kind="uninstall")
- save_dir.create()
self._save_dirs[os.path.normcase(path)] = save_dir
return save_dir.path
@@ -249,7 +254,6 @@ class StashedUninstallPathSet(object):
# Did not find any suitable root
head = os.path.dirname(path)
save_dir = TempDirectory(kind='uninstall')
- save_dir.create()
self._save_dirs[head] = save_dir
relpath = os.path.relpath(path, head)
@@ -260,14 +264,16 @@ class StashedUninstallPathSet(object):
def stash(self, path):
# type: (str) -> str
"""Stashes the directory or file and returns its new location.
+ Handle symlinks as files to avoid modifying the symlink targets.
"""
- if os.path.isdir(path):
+ path_is_dir = os.path.isdir(path) and not os.path.islink(path)
+ if path_is_dir:
new_path = self._get_directory_stash(path)
else:
new_path = self._get_file_stash(path)
self._moves.append((path, new_path))
- if os.path.isdir(path) and os.path.isdir(new_path):
+ if (path_is_dir and os.path.isdir(new_path)):
# If we're moving a directory, we need to
# remove the destination first or else it will be
# moved to inside the existing directory.
@@ -289,12 +295,12 @@ class StashedUninstallPathSet(object):
# type: () -> None
"""Undoes the uninstall by moving stashed files back."""
for p in self._moves:
- logging.info("Moving to %s\n from %s", *p)
+ logger.info("Moving to %s\n from %s", *p)
for new_path, path in self._moves:
try:
logger.debug('Replacing %s from %s', new_path, path)
- if os.path.isfile(new_path):
+ if os.path.isfile(new_path) or os.path.islink(new_path):
os.unlink(new_path)
elif os.path.isdir(new_path):
rmtree(new_path)
@@ -534,8 +540,9 @@ class UninstallPathSet(object):
with open(develop_egg_link, 'r') as fh:
link_pointer = os.path.normcase(fh.readline().strip())
assert (link_pointer == dist.location), (
- 'Egg-link %s does not match installed location of %s '
- '(at %s)' % (link_pointer, dist.project_name, dist.location)
+ 'Egg-link {} does not match installed location of {} '
+ '(at {})'.format(
+ link_pointer, dist.project_name, dist.location)
)
paths_to_remove.add(develop_egg_link)
easy_install_pth = os.path.join(os.path.dirname(develop_egg_link),
@@ -578,10 +585,6 @@ class UninstallPathSet(object):
class UninstallPthEntries(object):
def __init__(self, pth_file):
# type: (str) -> None
- if not os.path.isfile(pth_file):
- raise UninstallationError(
- "Cannot remove entries from nonexistent file %s" % pth_file
- )
self.file = pth_file
self.entries = set() # type: Set[str]
self._saved_lines = None # type: Optional[List[bytes]]
@@ -593,6 +596,11 @@ class UninstallPthEntries(object):
# backslashes. This is correct for entries that describe absolute
# paths outside of site-packages, but all the others use forward
# slashes.
+ # os.path.splitdrive is used instead of os.path.isabs because isabs
+ # treats non-absolute paths with drive letter markings like c:foo\bar
+ # as absolute paths. It also does not recognize UNC paths if they don't
+ # have more than "\\sever\share". Valid examples: "\\server\share\" or
+ # "\\server\share\folder". Python 2.7.8+ support UNC in splitdrive.
if WINDOWS and not os.path.splitdrive(entry)[0]:
entry = entry.replace('\\', '/')
self.entries.add(entry)
@@ -600,6 +608,13 @@ class UninstallPthEntries(object):
def remove(self):
# type: () -> None
logger.debug('Removing pth entries from %s:', self.file)
+
+ # If the file doesn't exist, log a warning and return
+ if not os.path.isfile(self.file):
+ logger.warning(
+ "Cannot remove entries from nonexistent file %s", self.file
+ )
+ return
with open(self.file, 'rb') as fh:
# windows uses '\r\n' with py3k, but uses '\n' with py2.x
lines = fh.readlines()
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-38.pyc
index 93a52b2..245ef0b 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-38.pyc
index be17a48..e8f3b9e 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/compat.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/compat.cpython-38.pyc
index 41bcef2..39d4f87 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/compat.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/compat.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-38.pyc
index 20c0b14..a5c9fdf 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-38.pyc
index 3a54a36..14aea42 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-38.pyc
index be5631a..67c6f78 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-38.pyc
index 9cf3b40..1210018 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-38.pyc
index 512c48f..1f6e43e 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/logging.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/logging.cpython-38.pyc
index 5e1caa1..42a4706 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/logging.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/logging.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/marker_files.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/marker_files.cpython-38.pyc
deleted file mode 100644
index 1da829e..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/marker_files.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/misc.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/misc.cpython-38.pyc
index 077cfb9..272e1d8 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/misc.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/misc.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/models.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/models.cpython-38.pyc
index fab3506..9a02208 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/models.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/models.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/outdated.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/outdated.cpython-38.pyc
deleted file mode 100644
index 232b67f..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/outdated.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-38.pyc
index acd4670..bc7e039 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-38.pyc
index 097b560..2fa6bce 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-38.pyc
index b8e5a27..0430fb7 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/typing.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/typing.cpython-38.pyc
index e1e6102..7d49d64 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/typing.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/typing.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/ui.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/ui.cpython-38.pyc
deleted file mode 100644
index 100fce0..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/ui.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-38.pyc
index be71e69..3d32956 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/appdirs.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/appdirs.py
index fb26111..3989ed3 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/utils/appdirs.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/appdirs.py
@@ -1,15 +1,17 @@
"""
-This code was taken from https://github.com/ActiveState/appdirs and modified
-to suit our purposes.
+This code wraps the vendored appdirs module to so the return values are
+compatible for the current pip code base.
+
+The intention is to rewrite current usages gradually, keeping the tests pass,
+and eventually drop this after all usages are changed.
"""
+
from __future__ import absolute_import
import os
-import sys
-from pip._vendor.six import PY2, text_type
+from pip._vendor import appdirs as _appdirs
-from pip._internal.utils.compat import WINDOWS, expanduser
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
if MYPY_CHECK_RUNNING:
@@ -18,251 +20,25 @@ if MYPY_CHECK_RUNNING:
def user_cache_dir(appname):
# type: (str) -> str
- r"""
- Return full path to the user-specific cache dir for this application.
-
- "appname" is the name of application.
-
- Typical user cache directories are:
- macOS: ~/Library/Caches/
- Unix: ~/.cache/ (XDG default)
- Windows: C:\Users\\AppData\Local\\Cache
-
- On Windows the only suggestion in the MSDN docs is that local settings go
- in the `CSIDL_LOCAL_APPDATA` directory. This is identical to the
- non-roaming app data dir (the default returned by `user_data_dir`). Apps
- typically put cache data somewhere *under* the given dir here. Some
- examples:
- ...\Mozilla\Firefox\Profiles\\Cache
- ...\Acme\SuperApp\Cache\1.0
-
- OPINION: This function appends "Cache" to the `CSIDL_LOCAL_APPDATA` value.
- """
- if WINDOWS:
- # Get the base path
- path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA"))
-
- # When using Python 2, return paths as bytes on Windows like we do on
- # other operating systems. See helper function docs for more details.
- if PY2 and isinstance(path, text_type):
- path = _win_path_to_bytes(path)
-
- # Add our app name and Cache directory to it
- path = os.path.join(path, appname, "Cache")
- elif sys.platform == "darwin":
- # Get the base path
- path = expanduser("~/Library/Caches")
-
- # Add our app name to it
- path = os.path.join(path, appname)
- else:
- # Get the base path
- path = os.getenv("XDG_CACHE_HOME", expanduser("~/.cache"))
-
- # Add our app name to it
- path = os.path.join(path, appname)
-
- return path
-
-
-def user_data_dir(appname, roaming=False):
- # type: (str, bool) -> str
- r"""
- Return full path to the user-specific data dir for this application.
-
- "appname" is the name of application.
- If None, just the system directory is returned.
- "roaming" (boolean, default False) can be set True to use the Windows
- roaming appdata directory. That means that for users on a Windows
- network setup for roaming profiles, this user data will be
- sync'd on login. See
-
- for a discussion of issues.
-
- Typical user data directories are:
- macOS: ~/Library/Application Support/
- if it exists, else ~/.config/
- Unix: ~/.local/share/ # or in
- $XDG_DATA_HOME, if defined
- Win XP (not roaming): C:\Documents and Settings\\ ...
- ...Application Data\
- Win XP (roaming): C:\Documents and Settings\\Local ...
- ...Settings\Application Data\
- Win 7 (not roaming): C:\\Users\\AppData\Local\
- Win 7 (roaming): C:\\Users\\AppData\Roaming\
-
- For Unix, we follow the XDG spec and support $XDG_DATA_HOME.
- That means, by default "~/.local/share/".
- """
- if WINDOWS:
- const = roaming and "CSIDL_APPDATA" or "CSIDL_LOCAL_APPDATA"
- path = os.path.join(os.path.normpath(_get_win_folder(const)), appname)
- elif sys.platform == "darwin":
- path = os.path.join(
- expanduser('~/Library/Application Support/'),
- appname,
- ) if os.path.isdir(os.path.join(
- expanduser('~/Library/Application Support/'),
- appname,
- )
- ) else os.path.join(
- expanduser('~/.config/'),
- appname,
- )
- else:
- path = os.path.join(
- os.getenv('XDG_DATA_HOME', expanduser("~/.local/share")),
- appname,
- )
-
- return path
+ return _appdirs.user_cache_dir(appname, appauthor=False)
def user_config_dir(appname, roaming=True):
# type: (str, bool) -> str
- """Return full path to the user-specific config dir for this application.
-
- "appname" is the name of application.
- If None, just the system directory is returned.
- "roaming" (boolean, default True) can be set False to not use the
- Windows roaming appdata directory. That means that for users on a
- Windows network setup for roaming profiles, this user data will be
- sync'd on login. See
-
- for a discussion of issues.
-
- Typical user data directories are:
- macOS: same as user_data_dir
- Unix: ~/.config/
- Win *: same as user_data_dir
-
- For Unix, we follow the XDG spec and support $XDG_CONFIG_HOME.
- That means, by default "~/.config/".
- """
- if WINDOWS:
- path = user_data_dir(appname, roaming=roaming)
- elif sys.platform == "darwin":
- path = user_data_dir(appname)
- else:
- path = os.getenv('XDG_CONFIG_HOME', expanduser("~/.config"))
- path = os.path.join(path, appname)
-
+ path = _appdirs.user_config_dir(appname, appauthor=False, roaming=roaming)
+ if _appdirs.system == "darwin" and not os.path.isdir(path):
+ path = os.path.expanduser('~/.config/')
+ if appname:
+ path = os.path.join(path, appname)
return path
-# for the discussion regarding site_config_dirs locations
+# for the discussion regarding site_config_dir locations
# see
def site_config_dirs(appname):
# type: (str) -> List[str]
- r"""Return a list of potential user-shared config dirs for this application.
-
- "appname" is the name of application.
-
- Typical user config directories are:
- macOS: /Library/Application Support//
- Unix: /etc or $XDG_CONFIG_DIRS[i]// for each value in
- $XDG_CONFIG_DIRS
- Win XP: C:\Documents and Settings\All Users\Application ...
- ...Data\\
- Vista: (Fail! "C:\ProgramData" is a hidden *system* directory
- on Vista.)
- Win 7: Hidden, but writeable on Win 7:
- C:\ProgramData\\
- """
- if WINDOWS:
- path = os.path.normpath(_get_win_folder("CSIDL_COMMON_APPDATA"))
- pathlist = [os.path.join(path, appname)]
- elif sys.platform == 'darwin':
- pathlist = [os.path.join('/Library/Application Support', appname)]
- else:
- # try looking in $XDG_CONFIG_DIRS
- xdg_config_dirs = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg')
- if xdg_config_dirs:
- pathlist = [
- os.path.join(expanduser(x), appname)
- for x in xdg_config_dirs.split(os.pathsep)
- ]
- else:
- pathlist = []
-
+ dirval = _appdirs.site_config_dir(appname, appauthor=False, multipath=True)
+ if _appdirs.system not in ["win32", "darwin"]:
# always look in /etc directly as well
- pathlist.append('/etc')
-
- return pathlist
-
-
-# -- Windows support functions --
-
-def _get_win_folder_from_registry(csidl_name):
- # type: (str) -> str
- """
- This is a fallback technique at best. I'm not sure if using the
- registry for this guarantees us the correct answer for all CSIDL_*
- names.
- """
- import _winreg
-
- shell_folder_name = {
- "CSIDL_APPDATA": "AppData",
- "CSIDL_COMMON_APPDATA": "Common AppData",
- "CSIDL_LOCAL_APPDATA": "Local AppData",
- }[csidl_name]
-
- key = _winreg.OpenKey(
- _winreg.HKEY_CURRENT_USER,
- r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders"
- )
- directory, _type = _winreg.QueryValueEx(key, shell_folder_name)
- return directory
-
-
-def _get_win_folder_with_ctypes(csidl_name):
- # type: (str) -> str
- csidl_const = {
- "CSIDL_APPDATA": 26,
- "CSIDL_COMMON_APPDATA": 35,
- "CSIDL_LOCAL_APPDATA": 28,
- }[csidl_name]
-
- buf = ctypes.create_unicode_buffer(1024)
- ctypes.windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf)
-
- # Downgrade to short path name if have highbit chars. See
- # .
- has_high_char = False
- for c in buf:
- if ord(c) > 255:
- has_high_char = True
- break
- if has_high_char:
- buf2 = ctypes.create_unicode_buffer(1024)
- if ctypes.windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024):
- buf = buf2
-
- return buf.value
-
-
-if WINDOWS:
- try:
- import ctypes
- _get_win_folder = _get_win_folder_with_ctypes
- except ImportError:
- _get_win_folder = _get_win_folder_from_registry
-
-
-def _win_path_to_bytes(path):
- """Encode Windows paths to bytes. Only used on Python 2.
-
- Motivation is to be consistent with other operating systems where paths
- are also returned as bytes. This avoids problems mixing bytes and Unicode
- elsewhere in the codebase. For more details and discussion see
- .
-
- If encoding using ASCII and MBCS fails, return the original Unicode path.
- """
- for encoding in ('ASCII', 'MBCS'):
- try:
- return path.encode(encoding)
- except (UnicodeEncodeError, LookupError):
- pass
- return path
+ return dirval.split(os.pathsep) + ['/etc']
+ return [dirval]
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/compat.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/compat.py
index ec3995c..9a2bb78 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/utils/compat.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/compat.py
@@ -1,29 +1,33 @@
"""Stuff that differs in different Python versions and platform
distributions."""
+
+# The following comment should be removed at some point in the future.
+# mypy: disallow-untyped-defs=False
+
from __future__ import absolute_import, division
import codecs
+import functools
import locale
import logging
import os
import shutil
import sys
-from pip._vendor.six import text_type
-from pip._vendor.urllib3.util import IS_PYOPENSSL
+from pip._vendor.six import PY2, text_type
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
if MYPY_CHECK_RUNNING:
- from typing import Optional, Text, Tuple, Union
+ from typing import Callable, Optional, Protocol, Text, Tuple, TypeVar, Union
-try:
- import _ssl # noqa
-except ImportError:
- ssl = None
-else:
- # This additional assignment was needed to prevent a mypy error.
- ssl = _ssl
+ # Used in the @lru_cache polyfill.
+ F = TypeVar('F')
+
+ class LruCache(Protocol):
+ def __call__(self, maxsize=None):
+ # type: (Optional[int]) -> Callable[[F], F]
+ raise NotImplementedError
try:
import ipaddress
@@ -37,20 +41,14 @@ except ImportError:
__all__ = [
- "ipaddress", "uses_pycache", "console_to_str", "native_str",
+ "ipaddress", "uses_pycache", "console_to_str",
"get_path_uid", "stdlib_pkgs", "WINDOWS", "samefile", "get_terminal_size",
- "get_extension_suffixes",
]
logger = logging.getLogger(__name__)
-HAS_TLS = (ssl is not None) or IS_PYOPENSSL
-
-if sys.version_info >= (3, 4):
- uses_pycache = True
- from importlib.util import cache_from_source
-else:
+if PY2:
import imp
try:
@@ -60,27 +58,41 @@ else:
cache_from_source = None
uses_pycache = cache_from_source is not None
-
-
-if sys.version_info >= (3, 5):
- backslashreplace_decode = "backslashreplace"
else:
- # In version 3.4 and older, backslashreplace exists
+ uses_pycache = True
+ from importlib.util import cache_from_source
+
+
+if PY2:
+ # In Python 2.7, backslashreplace exists
# but does not support use for decoding.
# We implement our own replace handler for this
# situation, so that we can consistently use
# backslash replacement for all versions.
def backslashreplace_decode_fn(err):
raw_bytes = (err.object[i] for i in range(err.start, err.end))
- if sys.version_info[0] == 2:
- # Python 2 gave us characters - convert to numeric bytes
- raw_bytes = (ord(b) for b in raw_bytes)
- return u"".join(u"\\x%x" % c for c in raw_bytes), err.end
+ # Python 2 gave us characters - convert to numeric bytes
+ raw_bytes = (ord(b) for b in raw_bytes)
+ return u"".join(map(u"\\x{:x}".format, raw_bytes)), err.end
codecs.register_error(
"backslashreplace_decode",
backslashreplace_decode_fn,
)
backslashreplace_decode = "backslashreplace_decode"
+else:
+ backslashreplace_decode = "backslashreplace"
+
+
+def has_tls():
+ # type: () -> bool
+ try:
+ import _ssl # noqa: F401 # ignore unused
+ return True
+ except ImportError:
+ pass
+
+ from pip._vendor.urllib3.util import IS_PYOPENSSL
+ return IS_PYOPENSSL
def str_to_display(data, desc=None):
@@ -118,10 +130,11 @@ def str_to_display(data, desc=None):
try:
decoded_data = data.decode(encoding)
except UnicodeDecodeError:
- if desc is None:
- desc = 'Bytes object'
- msg_format = '{} does not appear to be encoded as %s'.format(desc)
- logger.warning(msg_format, encoding)
+ logger.warning(
+ '%s does not appear to be encoded as %s',
+ desc or 'Bytes object',
+ encoding,
+ )
decoded_data = data.decode(encoding, errors=backslashreplace_decode)
# Make sure we can print the output, by encoding it to the output
@@ -156,22 +169,6 @@ def console_to_str(data):
return str_to_display(data, desc='Subprocess output')
-if sys.version_info >= (3,):
- def native_str(s, replace=False):
- # type: (str, bool) -> str
- if isinstance(s, bytes):
- return s.decode('utf-8', 'replace' if replace else 'strict')
- return s
-
-else:
- def native_str(s, replace=False):
- # type: (str, bool) -> str
- # Replace is ignored -- unicode to UTF-8 can't fail
- if isinstance(s, text_type):
- return s.encode('utf-8')
- return s
-
-
def get_path_uid(path):
# type: (str) -> int
"""
@@ -197,23 +194,12 @@ def get_path_uid(path):
else:
# raise OSError for parity with os.O_NOFOLLOW above
raise OSError(
- "%s is a symlink; Will not return uid for symlinks" % path
+ "{} is a symlink; Will not return uid for symlinks".format(
+ path)
)
return file_uid
-if sys.version_info >= (3, 4):
- from importlib.machinery import EXTENSION_SUFFIXES
-
- def get_extension_suffixes():
- return EXTENSION_SUFFIXES
-else:
- from imp import get_suffixes
-
- def get_extension_suffixes():
- return [suffix[0] for suffix in get_suffixes()]
-
-
def expanduser(path):
# type: (str) -> str
"""
@@ -282,12 +268,26 @@ else:
return cr
cr = ioctl_GWINSZ(0) or ioctl_GWINSZ(1) or ioctl_GWINSZ(2)
if not cr:
- try:
- fd = os.open(os.ctermid(), os.O_RDONLY)
- cr = ioctl_GWINSZ(fd)
- os.close(fd)
- except Exception:
- pass
+ if sys.platform != "win32":
+ try:
+ fd = os.open(os.ctermid(), os.O_RDONLY)
+ cr = ioctl_GWINSZ(fd)
+ os.close(fd)
+ except Exception:
+ pass
if not cr:
cr = (os.environ.get('LINES', 25), os.environ.get('COLUMNS', 80))
return int(cr[1]), int(cr[0])
+
+
+# Fallback to noop_lru_cache in Python 2
+# TODO: this can be removed when python 2 support is dropped!
+def noop_lru_cache(maxsize=None):
+ # type: (Optional[int]) -> Callable[[F], F]
+ def _wrapper(f):
+ # type: (F) -> F
+ return f
+ return _wrapper
+
+
+lru_cache = getattr(functools, "lru_cache", noop_lru_cache) # type: LruCache
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/deprecation.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/deprecation.py
index b9359bd..2f20cfd 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/utils/deprecation.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/deprecation.py
@@ -1,6 +1,10 @@
"""
A module that implements tooling to enable easy warnings about deprecations.
"""
+
+# The following comment should be removed at some point in the future.
+# mypy: disallow-untyped-defs=False
+
from __future__ import absolute_import
import logging
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/encoding.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/encoding.py
index 30139f2..5b83d61 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/utils/encoding.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/encoding.py
@@ -32,7 +32,9 @@ def auto_decode(data):
# Lets check the first two lines as in PEP263
for line in data.split(b'\n')[:2]:
if line[0:1] == b'#' and ENCODING_RE.search(line):
- encoding = ENCODING_RE.search(line).groups()[0].decode('ascii')
+ result = ENCODING_RE.search(line)
+ assert result is not None
+ encoding = result.groups()[0].decode('ascii')
return data.decode(encoding)
return data.decode(
locale.getpreferredencoding(False) or sys.getdefaultencoding(),
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/filesystem.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/filesystem.py
index 1e6b033..303243f 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/utils/filesystem.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/filesystem.py
@@ -1,16 +1,42 @@
+import errno
+import fnmatch
import os
import os.path
+import random
+import shutil
+import stat
+import sys
+from contextlib import contextmanager
+from tempfile import NamedTemporaryFile
+
+# NOTE: retrying is not annotated in typeshed as on 2017-07-17, which is
+# why we ignore the type on this import.
+from pip._vendor.retrying import retry # type: ignore
+from pip._vendor.six import PY2
from pip._internal.utils.compat import get_path_uid
+from pip._internal.utils.misc import format_size
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING, cast
+
+if MYPY_CHECK_RUNNING:
+ from typing import Any, BinaryIO, Iterator, List, Union
+
+ class NamedTemporaryFileResult(BinaryIO):
+ @property
+ def file(self):
+ # type: () -> BinaryIO
+ pass
def check_path_owner(path):
# type: (str) -> bool
# If we don't have a way to check the effective uid of this process, then
# we'll just assume that we own the directory.
- if not hasattr(os, "geteuid"):
+ if sys.platform == "win32" or not hasattr(os, "geteuid"):
return True
+ assert os.path.isabs(path)
+
previous = None
while path != previous:
if os.path.lexists(path):
@@ -28,3 +54,171 @@ def check_path_owner(path):
else:
previous, path = path, os.path.dirname(path)
return False # assume we don't own the path
+
+
+def copy2_fixed(src, dest):
+ # type: (str, str) -> None
+ """Wrap shutil.copy2() but map errors copying socket files to
+ SpecialFileError as expected.
+
+ See also https://bugs.python.org/issue37700.
+ """
+ try:
+ shutil.copy2(src, dest)
+ except (OSError, IOError):
+ for f in [src, dest]:
+ try:
+ is_socket_file = is_socket(f)
+ except OSError:
+ # An error has already occurred. Another error here is not
+ # a problem and we can ignore it.
+ pass
+ else:
+ if is_socket_file:
+ raise shutil.SpecialFileError(
+ "`{f}` is a socket".format(**locals()))
+
+ raise
+
+
+def is_socket(path):
+ # type: (str) -> bool
+ return stat.S_ISSOCK(os.lstat(path).st_mode)
+
+
+@contextmanager
+def adjacent_tmp_file(path, **kwargs):
+ # type: (str, **Any) -> Iterator[NamedTemporaryFileResult]
+ """Return a file-like object pointing to a tmp file next to path.
+
+ The file is created securely and is ensured to be written to disk
+ after the context reaches its end.
+
+ kwargs will be passed to tempfile.NamedTemporaryFile to control
+ the way the temporary file will be opened.
+ """
+ with NamedTemporaryFile(
+ delete=False,
+ dir=os.path.dirname(path),
+ prefix=os.path.basename(path),
+ suffix='.tmp',
+ **kwargs
+ ) as f:
+ result = cast('NamedTemporaryFileResult', f)
+ try:
+ yield result
+ finally:
+ result.file.flush()
+ os.fsync(result.file.fileno())
+
+
+_replace_retry = retry(stop_max_delay=1000, wait_fixed=250)
+
+if PY2:
+ @_replace_retry
+ def replace(src, dest):
+ # type: (str, str) -> None
+ try:
+ os.rename(src, dest)
+ except OSError:
+ os.remove(dest)
+ os.rename(src, dest)
+
+else:
+ replace = _replace_retry(os.replace)
+
+
+# test_writable_dir and _test_writable_dir_win are copied from Flit,
+# with the author's agreement to also place them under pip's license.
+def test_writable_dir(path):
+ # type: (str) -> bool
+ """Check if a directory is writable.
+
+ Uses os.access() on POSIX, tries creating files on Windows.
+ """
+ # If the directory doesn't exist, find the closest parent that does.
+ while not os.path.isdir(path):
+ parent = os.path.dirname(path)
+ if parent == path:
+ break # Should never get here, but infinite loops are bad
+ path = parent
+
+ if os.name == 'posix':
+ return os.access(path, os.W_OK)
+
+ return _test_writable_dir_win(path)
+
+
+def _test_writable_dir_win(path):
+ # type: (str) -> bool
+ # os.access doesn't work on Windows: http://bugs.python.org/issue2528
+ # and we can't use tempfile: http://bugs.python.org/issue22107
+ basename = 'accesstest_deleteme_fishfingers_custard_'
+ alphabet = 'abcdefghijklmnopqrstuvwxyz0123456789'
+ for _ in range(10):
+ name = basename + ''.join(random.choice(alphabet) for _ in range(6))
+ file = os.path.join(path, name)
+ try:
+ fd = os.open(file, os.O_RDWR | os.O_CREAT | os.O_EXCL)
+ # Python 2 doesn't support FileExistsError and PermissionError.
+ except OSError as e:
+ # exception FileExistsError
+ if e.errno == errno.EEXIST:
+ continue
+ # exception PermissionError
+ if e.errno == errno.EPERM or e.errno == errno.EACCES:
+ # This could be because there's a directory with the same name.
+ # But it's highly unlikely there's a directory called that,
+ # so we'll assume it's because the parent dir is not writable.
+ # This could as well be because the parent dir is not readable,
+ # due to non-privileged user access.
+ return False
+ raise
+ else:
+ os.close(fd)
+ os.unlink(file)
+ return True
+
+ # This should never be reached
+ raise EnvironmentError(
+ 'Unexpected condition testing for writable directory'
+ )
+
+
+def find_files(path, pattern):
+ # type: (str, str) -> List[str]
+ """Returns a list of absolute paths of files beneath path, recursively,
+ with filenames which match the UNIX-style shell glob pattern."""
+ result = [] # type: List[str]
+ for root, _, files in os.walk(path):
+ matches = fnmatch.filter(files, pattern)
+ result.extend(os.path.join(root, f) for f in matches)
+ return result
+
+
+def file_size(path):
+ # type: (str) -> Union[int, float]
+ # If it's a symlink, return 0.
+ if os.path.islink(path):
+ return 0
+ return os.path.getsize(path)
+
+
+def format_file_size(path):
+ # type: (str) -> str
+ return format_size(file_size(path))
+
+
+def directory_size(path):
+ # type: (str) -> Union[int, float]
+ size = 0.0
+ for root, _dirs, files in os.walk(path):
+ for filename in files:
+ file_path = os.path.join(root, filename)
+ size += file_size(file_path)
+ return size
+
+
+def format_directory_size(path):
+ # type: (str) -> str
+ return format_size(directory_size(path))
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/glibc.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/glibc.py
index aa77d9b..3610424 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/utils/glibc.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/glibc.py
@@ -1,8 +1,10 @@
+# The following comment should be removed at some point in the future.
+# mypy: strict-optional=False
+
from __future__ import absolute_import
import os
-import re
-import warnings
+import sys
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
@@ -23,6 +25,8 @@ def glibc_version_string_confstr():
# to be broken or missing. This strategy is used in the standard library
# platform module:
# https://github.com/python/cpython/blob/fcf1d003bf4f0100c9d0921ff3d70e1127ca1b71/Lib/platform.py#L175-L183
+ if sys.platform == "win32":
+ return None
try:
# os.confstr("CS_GNU_LIBC_VERSION") returns a string like "glibc 2.17":
_, version = os.confstr("CS_GNU_LIBC_VERSION").split()
@@ -63,32 +67,6 @@ def glibc_version_string_ctypes():
return version_str
-# Separated out from have_compatible_glibc for easier unit testing
-def check_glibc_version(version_str, required_major, minimum_minor):
- # type: (str, int, int) -> bool
- # Parse string and check against requested version.
- #
- # We use a regexp instead of str.split because we want to discard any
- # random junk that might come after the minor version -- this might happen
- # in patched/forked versions of glibc (e.g. Linaro's version of glibc
- # uses version strings like "2.20-2014.11"). See gh-3588.
- m = re.match(r"(?P[0-9]+)\.(?P[0-9]+)", version_str)
- if not m:
- warnings.warn("Expected glibc version with 2 components major.minor,"
- " got: %s" % version_str, RuntimeWarning)
- return False
- return (int(m.group("major")) == required_major and
- int(m.group("minor")) >= minimum_minor)
-
-
-def have_compatible_glibc(required_major, minimum_minor):
- # type: (int, int) -> bool
- version_str = glibc_version_string()
- if version_str is None:
- return False
- return check_glibc_version(version_str, required_major, minimum_minor)
-
-
# platform.libc_ver regularly returns completely nonsensical glibc
# versions. E.g. on my computer, platform says:
#
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/hashes.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/hashes.py
index e8aabe1..d9f74a6 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/utils/hashes.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/hashes.py
@@ -5,7 +5,9 @@ import hashlib
from pip._vendor.six import iteritems, iterkeys, itervalues
from pip._internal.exceptions import (
- HashMismatch, HashMissing, InstallationError,
+ HashMismatch,
+ HashMissing,
+ InstallationError,
)
from pip._internal.utils.misc import read_chunks
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
@@ -44,6 +46,26 @@ class Hashes(object):
"""
self._allowed = {} if hashes is None else hashes
+ def __and__(self, other):
+ # type: (Hashes) -> Hashes
+ if not isinstance(other, Hashes):
+ return NotImplemented
+
+ # If either of the Hashes object is entirely empty (i.e. no hash
+ # specified at all), all hashes from the other object are allowed.
+ if not other:
+ return self
+ if not self:
+ return other
+
+ # Otherwise only hashes that present in both objects are allowed.
+ new = {}
+ for alg, values in iteritems(other._allowed):
+ if alg not in self._allowed:
+ continue
+ new[alg] = [v for v in values if v in self._allowed[alg]]
+ return Hashes(new)
+
@property
def digest_count(self):
# type: () -> int
@@ -54,6 +76,7 @@ class Hashes(object):
hash_name, # type: str
hex_digest, # type: str
):
+ # type: (...) -> bool
"""Return whether the given hex digest is allowed."""
return hex_digest in self._allowed.get(hash_name, [])
@@ -70,7 +93,9 @@ class Hashes(object):
try:
gots[hash_name] = hashlib.new(hash_name)
except (ValueError, TypeError):
- raise InstallationError('Unknown hash name: %s' % hash_name)
+ raise InstallationError(
+ 'Unknown hash name: {}'.format(hash_name)
+ )
for chunk in chunks:
for hash in itervalues(gots):
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/logging.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/logging.py
index 3fbec71..9a017cf 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/utils/logging.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/logging.py
@@ -1,3 +1,6 @@
+# The following comment should be removed at some point in the future.
+# mypy: disallow-untyped-defs=False
+
from __future__ import absolute_import
import contextlib
@@ -6,13 +9,13 @@ import logging
import logging.handlers
import os
import sys
-from logging import Filter
+from logging import Filter, getLogger
from pip._vendor.six import PY2
from pip._internal.utils.compat import WINDOWS
from pip._internal.utils.deprecation import DEPRECATION_MSG_PREFIX
-from pip._internal.utils.misc import ensure_dir, subprocess_logger
+from pip._internal.utils.misc import ensure_dir
try:
import threading
@@ -49,7 +52,7 @@ else:
_log_state = threading.local()
-_log_state.indentation = 0
+subprocess_logger = getLogger('pip.subprocessor')
class BrokenStdoutLoggingError(Exception):
@@ -100,6 +103,8 @@ def indent_log(num=2):
A context manager which will cause the log output to be indented for any
log messages emitted inside it.
"""
+ # For thread-safety
+ _log_state.indentation = get_indentation()
_log_state.indentation += num
try:
yield
@@ -152,7 +157,7 @@ class IndentingFormatter(logging.Formatter):
if self.add_timestamp:
# TODO: Use Formatter.default_time_format after dropping PY2.
t = self.formatTime(record, "%Y-%m-%dT%H:%M:%S")
- prefix = '%s,%03d ' % (t, record.msecs)
+ prefix = '{t},{record.msecs:03.0f} '.format(**locals())
prefix += " " * get_indentation()
formatted = "".join([
prefix + line
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/marker_files.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/marker_files.py
deleted file mode 100644
index cb0c8eb..0000000
--- a/venv/lib/python3.8/site-packages/pip/_internal/utils/marker_files.py
+++ /dev/null
@@ -1,20 +0,0 @@
-import os.path
-
-DELETE_MARKER_MESSAGE = '''\
-This file is placed here by pip to indicate the source was put
-here by pip.
-
-Once this package is successfully installed this source code will be
-deleted (unless you remove this file).
-'''
-PIP_DELETE_MARKER_FILENAME = 'pip-delete-this-directory.txt'
-
-
-def write_delete_marker_file(directory):
- # type: (str) -> None
- """
- Write the pip delete marker file into this directory.
- """
- filepath = os.path.join(directory, PIP_DELETE_MARKER_FILENAME)
- with open(filepath, 'w') as marker_fp:
- marker_fp.write(DELETE_MARKER_MESSAGE)
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/misc.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/misc.py
index 61f74dc..5629c60 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/utils/misc.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/misc.py
@@ -1,43 +1,50 @@
+# The following comment should be removed at some point in the future.
+# mypy: strict-optional=False
+# mypy: disallow-untyped-defs=False
+
from __future__ import absolute_import
import contextlib
import errno
import getpass
+import hashlib
import io
-# we have a submodule named 'logging' which would shadow this if we used the
-# regular name:
-import logging as std_logging
+import logging
import os
import posixpath
-import re
import shutil
import stat
-import subprocess
import sys
-import tarfile
-import zipfile
from collections import deque
+from itertools import tee
from pip._vendor import pkg_resources
+from pip._vendor.packaging.utils import canonicalize_name
# NOTE: retrying is not annotated in typeshed as on 2017-07-17, which is
# why we ignore the type on this import.
from pip._vendor.retrying import retry # type: ignore
from pip._vendor.six import PY2, text_type
-from pip._vendor.six.moves import input, shlex_quote
+from pip._vendor.six.moves import filter, filterfalse, input, map, zip_longest
from pip._vendor.six.moves.urllib import parse as urllib_parse
-from pip._vendor.six.moves.urllib import request as urllib_request
from pip._vendor.six.moves.urllib.parse import unquote as urllib_unquote
from pip import __version__
-from pip._internal.exceptions import CommandError, InstallationError
-from pip._internal.locations import site_packages, user_site
-from pip._internal.utils.compat import (
- WINDOWS, console_to_str, expanduser, stdlib_pkgs, str_to_display,
+from pip._internal.exceptions import CommandError
+from pip._internal.locations import (
+ get_major_minor_version,
+ site_packages,
+ user_site,
)
-from pip._internal.utils.marker_files import write_delete_marker_file
-from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+from pip._internal.utils.compat import (
+ WINDOWS,
+ expanduser,
+ stdlib_pkgs,
+ str_to_display,
+)
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING, cast
from pip._internal.utils.virtualenv import (
- running_under_virtualenv, virtualenv_no_global,
+ running_under_virtualenv,
+ virtualenv_no_global,
)
if PY2:
@@ -47,60 +54,25 @@ else:
if MYPY_CHECK_RUNNING:
from typing import (
- Any, AnyStr, Container, Iterable, List, Mapping, Match, Optional, Text,
- Tuple, Union, cast,
+ Any, AnyStr, Callable, Container, Iterable, Iterator, List, Optional,
+ Text, Tuple, TypeVar, Union,
)
from pip._vendor.pkg_resources import Distribution
- from pip._internal.models.link import Link
- from pip._internal.utils.ui import SpinnerInterface
VersionInfo = Tuple[int, int, int]
-else:
- # typing's cast() is needed at runtime, but we don't want to import typing.
- # Thus, we use a dummy no-op version, which we tell mypy to ignore.
- def cast(type_, value): # type: ignore
- return value
+ T = TypeVar("T")
__all__ = ['rmtree', 'display_path', 'backup_dir',
'ask', 'splitext',
'format_size', 'is_installable_dir',
- 'is_svn_page', 'file_contents',
- 'split_leading_dir', 'has_leading_dir',
'normalize_path',
'renames', 'get_prog',
- 'unzip_file', 'untar_file', 'unpack_file', 'call_subprocess',
'captured_stdout', 'ensure_dir',
- 'ARCHIVE_EXTENSIONS', 'SUPPORTED_EXTENSIONS', 'WHEEL_EXTENSION',
'get_installed_version', 'remove_auth_from_url']
-logger = std_logging.getLogger(__name__)
-subprocess_logger = std_logging.getLogger('pip.subprocessor')
-
-LOG_DIVIDER = '----------------------------------------'
-
-WHEEL_EXTENSION = '.whl'
-BZ2_EXTENSIONS = ('.tar.bz2', '.tbz')
-XZ_EXTENSIONS = ('.tar.xz', '.txz', '.tlz', '.tar.lz', '.tar.lzma')
-ZIP_EXTENSIONS = ('.zip', WHEEL_EXTENSION)
-TAR_EXTENSIONS = ('.tar.gz', '.tgz', '.tar')
-ARCHIVE_EXTENSIONS = (
- ZIP_EXTENSIONS + BZ2_EXTENSIONS + TAR_EXTENSIONS + XZ_EXTENSIONS)
-SUPPORTED_EXTENSIONS = ZIP_EXTENSIONS + TAR_EXTENSIONS
-
-try:
- import bz2 # noqa
- SUPPORTED_EXTENSIONS += BZ2_EXTENSIONS
-except ImportError:
- logger.debug('bz2 module is not available')
-
-try:
- # Only for Python 3.3+
- import lzma # noqa
- SUPPORTED_EXTENSIONS += XZ_EXTENSIONS
-except ImportError:
- logger.debug('lzma module is not available')
+logger = logging.getLogger(__name__)
def get_pip_version():
@@ -110,7 +82,7 @@ def get_pip_version():
return (
'pip {} from {} (python {})'.format(
- __version__, pip_pkg_dir, sys.version[:3],
+ __version__, pip_pkg_dir, get_major_minor_version(),
)
)
@@ -141,7 +113,8 @@ def ensure_dir(path):
try:
os.makedirs(path)
except OSError as e:
- if e.errno != errno.EEXIST:
+ # Windows can raise spurious ENOTEMPTY errors. See #6426.
+ if e.errno != errno.EEXIST and e.errno != errno.ENOTEMPTY:
raise
@@ -150,7 +123,7 @@ def get_prog():
try:
prog = os.path.basename(sys.argv[0])
if prog in ('__main__.py', '-c'):
- return "%s -m pip" % sys.executable
+ return "{} -m pip".format(sys.executable)
else:
return prog
except (AttributeError, TypeError, IndexError):
@@ -161,7 +134,7 @@ def get_prog():
# Retry every half second for up to 3 seconds
@retry(stop_max_delay=3000, wait_fixed=500)
def rmtree(dir, ignore_errors=False):
- # type: (str, bool) -> None
+ # type: (Text, bool) -> None
shutil.rmtree(dir, ignore_errors=ignore_errors,
onerror=rmtree_errorhandler)
@@ -170,8 +143,13 @@ def rmtree_errorhandler(func, path, exc_info):
"""On Windows, the files in .svn are read-only, so when rmtree() tries to
remove them, an exception is thrown. We catch that here, remove the
read-only attribute, and hopefully continue without problems."""
- # if file type currently read only
- if os.stat(path).st_mode & stat.S_IREAD:
+ try:
+ has_attr_readonly = not (os.stat(path).st_mode & stat.S_IWRITE)
+ except (IOError, OSError):
+ # it's equivalent to os.path.exists
+ return
+
+ if has_attr_readonly:
# convert to read/write
os.chmod(path, stat.S_IWRITE)
# use the original function to repeat the operation
@@ -253,8 +231,8 @@ def _check_no_input(message):
"""Raise an error if no input is allowed."""
if os.environ.get('PIP_NO_INPUT'):
raise Exception(
- 'No input was expected ($PIP_NO_INPUT set); question: %s' %
- message
+ 'No input was expected ($PIP_NO_INPUT set); question: {}'.format(
+ message)
)
@@ -267,8 +245,8 @@ def ask(message, options):
response = response.strip().lower()
if response not in options:
print(
- 'Your response (%r) was not one of the expected responses: '
- '%s' % (response, ', '.join(options))
+ 'Your response ({!r}) was not one of the expected responses: '
+ '{}'.format(response, ', '.join(options))
)
else:
return response
@@ -291,13 +269,28 @@ def ask_password(message):
def format_size(bytes):
# type: (float) -> str
if bytes > 1000 * 1000:
- return '%.1fMB' % (bytes / 1000.0 / 1000)
+ return '{:.1f} MB'.format(bytes / 1000.0 / 1000)
elif bytes > 10 * 1000:
- return '%ikB' % (bytes / 1000)
+ return '{} kB'.format(int(bytes / 1000))
elif bytes > 1000:
- return '%.1fkB' % (bytes / 1000.0)
+ return '{:.1f} kB'.format(bytes / 1000.0)
else:
- return '%ibytes' % bytes
+ return '{} bytes'.format(int(bytes))
+
+
+def tabulate(rows):
+ # type: (Iterable[Iterable[Any]]) -> Tuple[List[str], List[int]]
+ """Return a list of formatted rows and a list of column sizes.
+
+ For example::
+
+ >>> tabulate([['foobar', 2000], [0xdeadbeef]])
+ (['foobar 2000', '3735928559'], [10, 4])
+ """
+ rows = [tuple(map(str, row)) for row in rows]
+ sizes = [max(map(len, col)) for col in zip_longest(*rows, fillvalue='')]
+ table = [" ".join(map(str.ljust, row, sizes)).rstrip() for row in rows]
+ return table, sizes
def is_installable_dir(path):
@@ -315,21 +308,6 @@ def is_installable_dir(path):
return False
-def is_svn_page(html):
- # type: (Union[str, Text]) -> Optional[Match[Union[str, Text]]]
- """
- Returns true if the page appears to be the index page of an svn repository
- """
- return (re.search(r'[^<]*Revision \d+:', html) and
- re.search(r'Powered by (?:]*?>)?Subversion', html, re.I))
-
-
-def file_contents(filename):
- # type: (str) -> Text
- with open(filename, 'rb') as fp:
- return fp.read().decode('utf-8')
-
-
def read_chunks(file, size=io.DEFAULT_BUFFER_SIZE):
"""Yield pieces of data from a file-like object until EOF."""
while True:
@@ -339,34 +317,6 @@ def read_chunks(file, size=io.DEFAULT_BUFFER_SIZE):
yield chunk
-def split_leading_dir(path):
- # type: (Union[str, Text]) -> List[Union[str, Text]]
- path = path.lstrip('/').lstrip('\\')
- if '/' in path and (('\\' in path and path.find('/') < path.find('\\')) or
- '\\' not in path):
- return path.split('/', 1)
- elif '\\' in path:
- return path.split('\\', 1)
- else:
- return [path, '']
-
-
-def has_leading_dir(paths):
- # type: (Iterable[Union[str, Text]]) -> bool
- """Returns true if all the paths have the same leading path name
- (i.e., everything is in one subdirectory in an archive)"""
- common_prefix = None
- for path in paths:
- prefix, rest = split_leading_dir(path)
- if not prefix:
- return False
- elif common_prefix is None:
- common_prefix = prefix
- elif prefix != common_prefix:
- return False
- return True
-
-
def normalize_path(path, resolve_symlinks=True):
# type: (str, bool) -> str
"""
@@ -416,10 +366,12 @@ def is_local(path):
If we're not in a virtualenv, all paths are considered "local."
+ Caution: this function assumes the head of path has been normalized
+ with normalize_path.
"""
if not running_under_virtualenv():
return True
- return normalize_path(path).startswith(normalize_path(sys.prefix))
+ return path.startswith(normalize_path(sys.prefix))
def dist_is_local(dist):
@@ -439,8 +391,7 @@ def dist_in_usersite(dist):
"""
Return True if given Distribution is installed in user site.
"""
- norm_path = normalize_path(dist_location(dist))
- return norm_path.startswith(normalize_path(user_site))
+ return dist_location(dist).startswith(normalize_path(user_site))
def dist_in_site_packages(dist):
@@ -449,9 +400,7 @@ def dist_in_site_packages(dist):
Return True if given Distribution is installed in
sysconfig.get_python_lib().
"""
- return normalize_path(
- dist_location(dist)
- ).startswith(normalize_path(site_packages))
+ return dist_location(dist).startswith(normalize_path(site_packages))
def dist_is_editable(dist):
@@ -525,8 +474,7 @@ def get_installed_distributions(
def user_test(d):
return True
- # because of pkg_resources vendoring, mypy cannot find stub in typeshed
- return [d for d in working_set # type: ignore
+ return [d for d in working_set
if local_test(d) and
d.key not in skip and
editable_test(d) and
@@ -535,6 +483,57 @@ def get_installed_distributions(
]
+def _search_distribution(req_name):
+ # type: (str) -> Optional[Distribution]
+ """Find a distribution matching the ``req_name`` in the environment.
+
+ This searches from *all* distributions available in the environment, to
+ match the behavior of ``pkg_resources.get_distribution()``.
+ """
+ # Canonicalize the name before searching in the list of
+ # installed distributions and also while creating the package
+ # dictionary to get the Distribution object
+ req_name = canonicalize_name(req_name)
+ packages = get_installed_distributions(
+ local_only=False,
+ skip=(),
+ include_editables=True,
+ editables_only=False,
+ user_only=False,
+ paths=None,
+ )
+ pkg_dict = {canonicalize_name(p.key): p for p in packages}
+ return pkg_dict.get(req_name)
+
+
+def get_distribution(req_name):
+ # type: (str) -> Optional[Distribution]
+ """Given a requirement name, return the installed Distribution object.
+
+ This searches from *all* distributions available in the environment, to
+ match the behavior of ``pkg_resources.get_distribution()``.
+ """
+
+ # Search the distribution by looking through the working set
+ dist = _search_distribution(req_name)
+
+ # If distribution could not be found, call working_set.require
+ # to update the working set, and try to find the distribution
+ # again.
+ # This might happen for e.g. when you install a package
+ # twice, once using setup.py develop and again using setup.py install.
+ # Now when run pip uninstall twice, the package gets removed
+ # from the working set in the first uninstall, so we have to populate
+ # the working set again so that pip knows about it and the packages
+ # gets picked up and is successfully uninstalled the second time too.
+ if not dist:
+ try:
+ pkg_resources.working_set.require(req_name)
+ except pkg_resources.DistributionNotFound:
+ return None
+ return _search_distribution(req_name)
+
+
def egg_link_path(dist):
# type: (Distribution) -> Optional[str]
"""
@@ -556,12 +555,9 @@ def egg_link_path(dist):
"""
sites = []
if running_under_virtualenv():
- if virtualenv_no_global():
- sites.append(site_packages)
- else:
- sites.append(site_packages)
- if user_site:
- sites.append(user_site)
+ sites.append(site_packages)
+ if not virtualenv_no_global() and user_site:
+ sites.append(user_site)
else:
if user_site:
sites.append(user_site)
@@ -582,383 +578,28 @@ def dist_location(dist):
packages, where dist.location is the source code location, and we
want to know where the egg-link file is.
+ The returned location is normalized (in particular, with symlinks removed).
"""
egg_link = egg_link_path(dist)
if egg_link:
- return egg_link
- return dist.location
+ return normalize_path(egg_link)
+ return normalize_path(dist.location)
-def current_umask():
- """Get the current umask which involves having to set it temporarily."""
- mask = os.umask(0)
- os.umask(mask)
- return mask
-
-
-def unzip_file(filename, location, flatten=True):
- # type: (str, str, bool) -> None
- """
- Unzip the file (with path `filename`) to the destination `location`. All
- files are written based on system defaults and umask (i.e. permissions are
- not preserved), except that regular file members with any execute
- permissions (user, group, or world) have "chmod +x" applied after being
- written. Note that for windows, any execute changes using os.chmod are
- no-ops per the python docs.
- """
- ensure_dir(location)
- zipfp = open(filename, 'rb')
- try:
- zip = zipfile.ZipFile(zipfp, allowZip64=True)
- leading = has_leading_dir(zip.namelist()) and flatten
- for info in zip.infolist():
- name = info.filename
- fn = name
- if leading:
- fn = split_leading_dir(name)[1]
- fn = os.path.join(location, fn)
- dir = os.path.dirname(fn)
- if fn.endswith('/') or fn.endswith('\\'):
- # A directory
- ensure_dir(fn)
- else:
- ensure_dir(dir)
- # Don't use read() to avoid allocating an arbitrarily large
- # chunk of memory for the file's content
- fp = zip.open(name)
- try:
- with open(fn, 'wb') as destfp:
- shutil.copyfileobj(fp, destfp)
- finally:
- fp.close()
- mode = info.external_attr >> 16
- # if mode and regular file and any execute permissions for
- # user/group/world?
- if mode and stat.S_ISREG(mode) and mode & 0o111:
- # make dest file have execute for user/group/world
- # (chmod +x) no-op on windows per python docs
- os.chmod(fn, (0o777 - current_umask() | 0o111))
- finally:
- zipfp.close()
-
-
-def untar_file(filename, location):
- # type: (str, str) -> None
- """
- Untar the file (with path `filename`) to the destination `location`.
- All files are written based on system defaults and umask (i.e. permissions
- are not preserved), except that regular file members with any execute
- permissions (user, group, or world) have "chmod +x" applied after being
- written. Note that for windows, any execute changes using os.chmod are
- no-ops per the python docs.
- """
- ensure_dir(location)
- if filename.lower().endswith('.gz') or filename.lower().endswith('.tgz'):
- mode = 'r:gz'
- elif filename.lower().endswith(BZ2_EXTENSIONS):
- mode = 'r:bz2'
- elif filename.lower().endswith(XZ_EXTENSIONS):
- mode = 'r:xz'
- elif filename.lower().endswith('.tar'):
- mode = 'r'
- else:
- logger.warning(
- 'Cannot determine compression type for file %s', filename,
- )
- mode = 'r:*'
- tar = tarfile.open(filename, mode)
- try:
- leading = has_leading_dir([
- member.name for member in tar.getmembers()
- ])
- for member in tar.getmembers():
- fn = member.name
- if leading:
- # https://github.com/python/mypy/issues/1174
- fn = split_leading_dir(fn)[1] # type: ignore
- path = os.path.join(location, fn)
- if member.isdir():
- ensure_dir(path)
- elif member.issym():
- try:
- # https://github.com/python/typeshed/issues/2673
- tar._extract_member(member, path) # type: ignore
- except Exception as exc:
- # Some corrupt tar files seem to produce this
- # (specifically bad symlinks)
- logger.warning(
- 'In the tar file %s the member %s is invalid: %s',
- filename, member.name, exc,
- )
- continue
- else:
- try:
- fp = tar.extractfile(member)
- except (KeyError, AttributeError) as exc:
- # Some corrupt tar files seem to produce this
- # (specifically bad symlinks)
- logger.warning(
- 'In the tar file %s the member %s is invalid: %s',
- filename, member.name, exc,
- )
- continue
- ensure_dir(os.path.dirname(path))
- with open(path, 'wb') as destfp:
- shutil.copyfileobj(fp, destfp)
- fp.close()
- # Update the timestamp (useful for cython compiled files)
- # https://github.com/python/typeshed/issues/2673
- tar.utime(member, path) # type: ignore
- # member have any execute permissions for user/group/world?
- if member.mode & 0o111:
- # make dest file have execute for user/group/world
- # no-op on windows per python docs
- os.chmod(path, (0o777 - current_umask() | 0o111))
- finally:
- tar.close()
-
-
-def unpack_file(
- filename, # type: str
- location, # type: str
- content_type, # type: Optional[str]
- link # type: Optional[Link]
-):
- # type: (...) -> None
- filename = os.path.realpath(filename)
- if (content_type == 'application/zip' or
- filename.lower().endswith(ZIP_EXTENSIONS) or
- zipfile.is_zipfile(filename)):
- unzip_file(
- filename,
- location,
- flatten=not filename.endswith('.whl')
- )
- elif (content_type == 'application/x-gzip' or
- tarfile.is_tarfile(filename) or
- filename.lower().endswith(
- TAR_EXTENSIONS + BZ2_EXTENSIONS + XZ_EXTENSIONS)):
- untar_file(filename, location)
- elif (content_type and content_type.startswith('text/html') and
- is_svn_page(file_contents(filename))):
- # We don't really care about this
- from pip._internal.vcs.subversion import Subversion
- url = 'svn+' + link.url
- Subversion().unpack(location, url=url)
- else:
- # FIXME: handle?
- # FIXME: magic signatures?
- logger.critical(
- 'Cannot unpack file %s (downloaded from %s, content-type: %s); '
- 'cannot detect archive format',
- filename, location, content_type,
- )
- raise InstallationError(
- 'Cannot determine archive format of %s' % location
- )
-
-
-def format_command_args(args):
- # type: (List[str]) -> str
- """
- Format command arguments for display.
- """
- return ' '.join(shlex_quote(arg) for arg in args)
-
-
-def make_subprocess_output_error(
- cmd_args, # type: List[str]
- cwd, # type: Optional[str]
- lines, # type: List[Text]
- exit_status, # type: int
-):
- # type: (...) -> Text
- """
- Create and return the error message to use to log a subprocess error
- with command output.
-
- :param lines: A list of lines, each ending with a newline.
- """
- command = format_command_args(cmd_args)
- # Convert `command` and `cwd` to text (unicode in Python 2) so we can use
- # them as arguments in the unicode format string below. This avoids
- # "UnicodeDecodeError: 'ascii' codec can't decode byte ..." in Python 2
- # if either contains a non-ascii character.
- command_display = str_to_display(command, desc='command bytes')
- cwd_display = path_to_display(cwd)
-
- # We know the joined output value ends in a newline.
- output = ''.join(lines)
- msg = (
- # Use a unicode string to avoid "UnicodeEncodeError: 'ascii'
- # codec can't encode character ..." in Python 2 when a format
- # argument (e.g. `output`) has a non-ascii character.
- u'Command errored out with exit status {exit_status}:\n'
- ' command: {command_display}\n'
- ' cwd: {cwd_display}\n'
- 'Complete output ({line_count} lines):\n{output}{divider}'
- ).format(
- exit_status=exit_status,
- command_display=command_display,
- cwd_display=cwd_display,
- line_count=len(lines),
- output=output,
- divider=LOG_DIVIDER,
- )
- return msg
-
-
-def call_subprocess(
- cmd, # type: List[str]
- show_stdout=False, # type: bool
- cwd=None, # type: Optional[str]
- on_returncode='raise', # type: str
- extra_ok_returncodes=None, # type: Optional[Iterable[int]]
- command_desc=None, # type: Optional[str]
- extra_environ=None, # type: Optional[Mapping[str, Any]]
- unset_environ=None, # type: Optional[Iterable[str]]
- spinner=None # type: Optional[SpinnerInterface]
-):
- # type: (...) -> Text
- """
- Args:
- show_stdout: if true, use INFO to log the subprocess's stderr and
- stdout streams. Otherwise, use DEBUG. Defaults to False.
- extra_ok_returncodes: an iterable of integer return codes that are
- acceptable, in addition to 0. Defaults to None, which means [].
- unset_environ: an iterable of environment variable names to unset
- prior to calling subprocess.Popen().
- """
- if extra_ok_returncodes is None:
- extra_ok_returncodes = []
- if unset_environ is None:
- unset_environ = []
- # Most places in pip use show_stdout=False. What this means is--
- #
- # - We connect the child's output (combined stderr and stdout) to a
- # single pipe, which we read.
- # - We log this output to stderr at DEBUG level as it is received.
- # - If DEBUG logging isn't enabled (e.g. if --verbose logging wasn't
- # requested), then we show a spinner so the user can still see the
- # subprocess is in progress.
- # - If the subprocess exits with an error, we log the output to stderr
- # at ERROR level if it hasn't already been displayed to the console
- # (e.g. if --verbose logging wasn't enabled). This way we don't log
- # the output to the console twice.
- #
- # If show_stdout=True, then the above is still done, but with DEBUG
- # replaced by INFO.
- if show_stdout:
- # Then log the subprocess output at INFO level.
- log_subprocess = subprocess_logger.info
- used_level = std_logging.INFO
- else:
- # Then log the subprocess output using DEBUG. This also ensures
- # it will be logged to the log file (aka user_log), if enabled.
- log_subprocess = subprocess_logger.debug
- used_level = std_logging.DEBUG
-
- # Whether the subprocess will be visible in the console.
- showing_subprocess = subprocess_logger.getEffectiveLevel() <= used_level
-
- # Only use the spinner if we're not showing the subprocess output
- # and we have a spinner.
- use_spinner = not showing_subprocess and spinner is not None
-
- if command_desc is None:
- command_desc = format_command_args(cmd)
-
- log_subprocess("Running command %s", command_desc)
- env = os.environ.copy()
- if extra_environ:
- env.update(extra_environ)
- for name in unset_environ:
- env.pop(name, None)
- try:
- proc = subprocess.Popen(
- cmd, stderr=subprocess.STDOUT, stdin=subprocess.PIPE,
- stdout=subprocess.PIPE, cwd=cwd, env=env,
- )
- proc.stdin.close()
- except Exception as exc:
- subprocess_logger.critical(
- "Error %s while executing command %s", exc, command_desc,
- )
- raise
- all_output = []
- while True:
- # The "line" value is a unicode string in Python 2.
- line = console_to_str(proc.stdout.readline())
- if not line:
- break
- line = line.rstrip()
- all_output.append(line + '\n')
-
- # Show the line immediately.
- log_subprocess(line)
- # Update the spinner.
- if use_spinner:
- spinner.spin()
- try:
- proc.wait()
- finally:
- if proc.stdout:
- proc.stdout.close()
- proc_had_error = (
- proc.returncode and proc.returncode not in extra_ok_returncodes
- )
- if use_spinner:
- if proc_had_error:
- spinner.finish("error")
- else:
- spinner.finish("done")
- if proc_had_error:
- if on_returncode == 'raise':
- if not showing_subprocess:
- # Then the subprocess streams haven't been logged to the
- # console yet.
- msg = make_subprocess_output_error(
- cmd_args=cmd,
- cwd=cwd,
- lines=all_output,
- exit_status=proc.returncode,
- )
- subprocess_logger.error(msg)
- exc_msg = (
- 'Command errored out with exit status {}: {} '
- 'Check the logs for full command output.'
- ).format(proc.returncode, command_desc)
- raise InstallationError(exc_msg)
- elif on_returncode == 'warn':
- subprocess_logger.warning(
- 'Command "%s" had error code %s in %s',
- command_desc, proc.returncode, cwd,
- )
- elif on_returncode == 'ignore':
- pass
- else:
- raise ValueError('Invalid value: on_returncode=%s' %
- repr(on_returncode))
- return ''.join(all_output)
-
-
-def _make_build_dir(build_dir):
- os.makedirs(build_dir)
- write_delete_marker_file(build_dir)
+def write_output(msg, *args):
+ # type: (Any, Any) -> None
+ logger.info(msg, *args)
class FakeFile(object):
"""Wrap a list of lines in an object with readline() to make
ConfigParser happy."""
def __init__(self, lines):
- self._gen = (l for l in lines)
+ self._gen = iter(lines)
def readline(self):
try:
- try:
- return next(self._gen)
- except NameError:
- return self._gen.next()
+ return next(self._gen)
except StopIteration:
return ''
@@ -1013,26 +654,6 @@ def captured_stderr():
return captured_output('stderr')
-class cached_property(object):
- """A property that is only computed once per instance and then replaces
- itself with an ordinary attribute. Deleting the attribute resets the
- property.
-
- Source: https://github.com/bottlepy/bottle/blob/0.11.5/bottle.py#L175
- """
-
- def __init__(self, func):
- self.__doc__ = getattr(func, '__doc__')
- self.func = func
-
- def __get__(self, obj, cls):
- if obj is None:
- # We're being accessed from the class itself, not from an object
- return self
- value = obj.__dict__[self.func.__name__] = self.func(obj)
- return value
-
-
def get_installed_version(dist_name, working_set=None):
"""Get the installed version of dist_name avoiding pkg_resources cache"""
# Create a requirement that we'll look for inside of setuptools.
@@ -1064,15 +685,38 @@ def enum(*sequential, **named):
return type('Enum', (), enums)
-def path_to_url(path):
- # type: (Union[str, Text]) -> str
+def build_netloc(host, port):
+ # type: (str, Optional[int]) -> str
"""
- Convert a path to a file: URL. The path will be made absolute and have
- quoted path parts.
+ Build a netloc from a host-port pair
"""
- path = os.path.normpath(os.path.abspath(path))
- url = urllib_parse.urljoin('file:', urllib_request.pathname2url(path))
- return url
+ if port is None:
+ return host
+ if ':' in host:
+ # Only wrap host with square brackets when it is IPv6
+ host = '[{}]'.format(host)
+ return '{}:{}'.format(host, port)
+
+
+def build_url_from_netloc(netloc, scheme='https'):
+ # type: (str, str) -> str
+ """
+ Build a full URL from a netloc.
+ """
+ if netloc.count(':') >= 2 and '@' not in netloc and '[' not in netloc:
+ # It must be a bare IPv6 address, so wrap it with brackets.
+ netloc = '[{}]'.format(netloc)
+ return '{}://{}'.format(scheme, netloc)
+
+
+def parse_netloc(netloc):
+ # type: (str) -> Tuple[str, Optional[int]]
+ """
+ Return the host-port pair from a netloc.
+ """
+ url = build_url_from_netloc(netloc)
+ parsed = urllib_parse.urlparse(url)
+ return parsed.hostname, parsed.port
def split_auth_from_netloc(netloc):
@@ -1106,15 +750,22 @@ def split_auth_from_netloc(netloc):
def redact_netloc(netloc):
# type: (str) -> str
"""
- Replace the password in a netloc with "****", if it exists.
+ Replace the sensitive data in a netloc with "****", if it exists.
- For example, "user:pass@example.com" returns "user:****@example.com".
+ For example:
+ - "user:pass@example.com" returns "user:****@example.com"
+ - "accesstoken@example.com" returns "****@example.com"
"""
netloc, (user, password) = split_auth_from_netloc(netloc)
if user is None:
return netloc
- password = '' if password is None else ':****'
- return '{user}{password}@{netloc}'.format(user=urllib_parse.quote(user),
+ if password is None:
+ user = '****'
+ password = ''
+ else:
+ user = urllib_parse.quote(user)
+ password = ':****'
+ return '{user}{password}@{netloc}'.format(user=user,
password=password,
netloc=netloc)
@@ -1166,13 +817,60 @@ def remove_auth_from_url(url):
return _transform_url(url, _get_netloc)[0]
-def redact_password_from_url(url):
+def redact_auth_from_url(url):
# type: (str) -> str
"""Replace the password in a given url with ****."""
return _transform_url(url, _redact_netloc)[0]
+class HiddenText(object):
+ def __init__(
+ self,
+ secret, # type: str
+ redacted, # type: str
+ ):
+ # type: (...) -> None
+ self.secret = secret
+ self.redacted = redacted
+
+ def __repr__(self):
+ # type: (...) -> str
+ return ''.format(str(self))
+
+ def __str__(self):
+ # type: (...) -> str
+ return self.redacted
+
+ # This is useful for testing.
+ def __eq__(self, other):
+ # type: (Any) -> bool
+ if type(self) != type(other):
+ return False
+
+ # The string being used for redaction doesn't also have to match,
+ # just the raw, original string.
+ return (self.secret == other.secret)
+
+ # We need to provide an explicit __ne__ implementation for Python 2.
+ # TODO: remove this when we drop PY2 support.
+ def __ne__(self, other):
+ # type: (Any) -> bool
+ return not self == other
+
+
+def hide_value(value):
+ # type: (str) -> HiddenText
+ return HiddenText(value, redacted='****')
+
+
+def hide_url(url):
+ # type: (str) -> HiddenText
+ redacted = redact_auth_from_url(url)
+ return HiddenText(url, redacted=redacted)
+
+
def protect_pip_from_modification_on_windows(modifying_pip):
+ # type: (bool) -> None
"""Protection of pip.exe from modification on Windows
On Windows, any operation modifying pip should be run as:
@@ -1199,3 +897,63 @@ def protect_pip_from_modification_on_windows(modifying_pip):
'To modify pip, please run the following command:\n{}'
.format(" ".join(new_command))
)
+
+
+def is_console_interactive():
+ # type: () -> bool
+ """Is this console interactive?
+ """
+ return sys.stdin is not None and sys.stdin.isatty()
+
+
+def hash_file(path, blocksize=1 << 20):
+ # type: (Text, int) -> Tuple[Any, int]
+ """Return (hash, length) for path using hashlib.sha256()
+ """
+
+ h = hashlib.sha256()
+ length = 0
+ with open(path, 'rb') as f:
+ for block in read_chunks(f, size=blocksize):
+ length += len(block)
+ h.update(block)
+ return h, length
+
+
+def is_wheel_installed():
+ """
+ Return whether the wheel package is installed.
+ """
+ try:
+ import wheel # noqa: F401
+ except ImportError:
+ return False
+
+ return True
+
+
+def pairwise(iterable):
+ # type: (Iterable[Any]) -> Iterator[Tuple[Any, Any]]
+ """
+ Return paired elements.
+
+ For example:
+ s -> (s0, s1), (s2, s3), (s4, s5), ...
+ """
+ iterable = iter(iterable)
+ return zip_longest(iterable, iterable)
+
+
+def partition(
+ pred, # type: Callable[[T], bool]
+ iterable, # type: Iterable[T]
+):
+ # type: (...) -> Tuple[Iterable[T], Iterable[T]]
+ """
+ Use a predicate to partition entries into false entries and true entries,
+ like
+
+ partition(is_odd, range(10)) --> 0 2 4 6 8 and 1 3 5 7 9
+ """
+ t1, t2 = tee(iterable)
+ return filterfalse(pred, t1), filter(pred, t2)
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/models.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/models.py
index fccaf5d..d1c2f22 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/utils/models.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/models.py
@@ -1,5 +1,7 @@
"""Utilities for defining models
"""
+# The following comment should be removed at some point in the future.
+# mypy: disallow-untyped-defs=False
import operator
@@ -8,6 +10,8 @@ class KeyBasedCompareMixin(object):
"""Provides comparison capabilities that is based on a key
"""
+ __slots__ = ['_compare_key', '_defining_class']
+
def __init__(self, key, defining_class):
self._compare_key = key
self._defining_class = defining_class
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/outdated.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/outdated.py
deleted file mode 100644
index 2b10aef..0000000
--- a/venv/lib/python3.8/site-packages/pip/_internal/utils/outdated.py
+++ /dev/null
@@ -1,178 +0,0 @@
-from __future__ import absolute_import
-
-import datetime
-import json
-import logging
-import os.path
-import sys
-
-from pip._vendor import lockfile, pkg_resources
-from pip._vendor.packaging import version as packaging_version
-
-from pip._internal.cli.cmdoptions import make_search_scope
-from pip._internal.index import PackageFinder
-from pip._internal.models.selection_prefs import SelectionPreferences
-from pip._internal.utils.compat import WINDOWS
-from pip._internal.utils.filesystem import check_path_owner
-from pip._internal.utils.misc import ensure_dir, get_installed_version
-from pip._internal.utils.packaging import get_installer
-from pip._internal.utils.typing import MYPY_CHECK_RUNNING
-
-if MYPY_CHECK_RUNNING:
- import optparse
- from typing import Any, Dict
- from pip._internal.download import PipSession
-
-
-SELFCHECK_DATE_FMT = "%Y-%m-%dT%H:%M:%SZ"
-
-
-logger = logging.getLogger(__name__)
-
-
-class SelfCheckState(object):
- def __init__(self, cache_dir):
- # type: (str) -> None
- self.state = {} # type: Dict[str, Any]
- self.statefile_path = None
-
- # Try to load the existing state
- if cache_dir:
- self.statefile_path = os.path.join(cache_dir, "selfcheck.json")
- try:
- with open(self.statefile_path) as statefile:
- self.state = json.load(statefile)[sys.prefix]
- except (IOError, ValueError, KeyError):
- # Explicitly suppressing exceptions, since we don't want to
- # error out if the cache file is invalid.
- pass
-
- def save(self, pypi_version, current_time):
- # type: (str, datetime.datetime) -> None
- # If we do not have a path to cache in, don't bother saving.
- if not self.statefile_path:
- return
-
- # Check to make sure that we own the directory
- if not check_path_owner(os.path.dirname(self.statefile_path)):
- return
-
- # Now that we've ensured the directory is owned by this user, we'll go
- # ahead and make sure that all our directories are created.
- ensure_dir(os.path.dirname(self.statefile_path))
-
- # Attempt to write out our version check file
- with lockfile.LockFile(self.statefile_path):
- if os.path.exists(self.statefile_path):
- with open(self.statefile_path) as statefile:
- state = json.load(statefile)
- else:
- state = {}
-
- state[sys.prefix] = {
- "last_check": current_time.strftime(SELFCHECK_DATE_FMT),
- "pypi_version": pypi_version,
- }
-
- with open(self.statefile_path, "w") as statefile:
- json.dump(state, statefile, sort_keys=True,
- separators=(",", ":"))
-
-
-def was_installed_by_pip(pkg):
- # type: (str) -> bool
- """Checks whether pkg was installed by pip
-
- This is used not to display the upgrade message when pip is in fact
- installed by system package manager, such as dnf on Fedora.
- """
- try:
- dist = pkg_resources.get_distribution(pkg)
- return "pip" == get_installer(dist)
- except pkg_resources.DistributionNotFound:
- return False
-
-
-def pip_version_check(session, options):
- # type: (PipSession, optparse.Values) -> None
- """Check for an update for pip.
-
- Limit the frequency of checks to once per week. State is stored either in
- the active virtualenv or in the user's USER_CACHE_DIR keyed off the prefix
- of the pip script path.
- """
- installed_version = get_installed_version("pip")
- if not installed_version:
- return
-
- pip_version = packaging_version.parse(installed_version)
- pypi_version = None
-
- try:
- state = SelfCheckState(cache_dir=options.cache_dir)
-
- current_time = datetime.datetime.utcnow()
- # Determine if we need to refresh the state
- if "last_check" in state.state and "pypi_version" in state.state:
- last_check = datetime.datetime.strptime(
- state.state["last_check"],
- SELFCHECK_DATE_FMT
- )
- if (current_time - last_check).total_seconds() < 7 * 24 * 60 * 60:
- pypi_version = state.state["pypi_version"]
-
- # Refresh the version if we need to or just see if we need to warn
- if pypi_version is None:
- # Lets use PackageFinder to see what the latest pip version is
- search_scope = make_search_scope(options, suppress_no_index=True)
-
- # Pass allow_yanked=False so we don't suggest upgrading to a
- # yanked version.
- selection_prefs = SelectionPreferences(
- allow_yanked=False,
- allow_all_prereleases=False, # Explicitly set to False
- )
-
- finder = PackageFinder.create(
- search_scope=search_scope,
- selection_prefs=selection_prefs,
- trusted_hosts=options.trusted_hosts,
- session=session,
- )
- candidate = finder.find_candidates("pip").get_best()
- if candidate is None:
- return
- pypi_version = str(candidate.version)
-
- # save that we've performed a check
- state.save(pypi_version, current_time)
-
- remote_version = packaging_version.parse(pypi_version)
-
- local_version_is_older = (
- pip_version < remote_version and
- pip_version.base_version != remote_version.base_version and
- was_installed_by_pip('pip')
- )
-
- # Determine if our pypi_version is older
- if not local_version_is_older:
- return
-
- # Advise "python -m pip" on Windows to avoid issues
- # with overwriting pip.exe.
- if WINDOWS:
- pip_cmd = "python -m pip"
- else:
- pip_cmd = "pip"
- logger.warning(
- "You are using pip version %s, however version %s is "
- "available.\nYou should consider upgrading via the "
- "'%s install --upgrade pip' command.",
- pip_version, pypi_version, pip_cmd
- )
- except Exception:
- logger.debug(
- "There was an error checking the latest version of pip",
- exc_info=True,
- )
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/setuptools_build.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/setuptools_build.py
index 5895607..2a664b0 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/utils/setuptools_build.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/setuptools_build.py
@@ -3,7 +3,7 @@ import sys
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
if MYPY_CHECK_RUNNING:
- from typing import List
+ from typing import List, Optional, Sequence
# Shim to wrap setup.py invocation with setuptools
#
@@ -20,17 +20,162 @@ _SETUPTOOLS_SHIM = (
)
-def make_setuptools_shim_args(setup_py_path, unbuffered_output=False):
- # type: (str, bool) -> List[str]
+def make_setuptools_shim_args(
+ setup_py_path, # type: str
+ global_options=None, # type: Sequence[str]
+ no_user_config=False, # type: bool
+ unbuffered_output=False # type: bool
+):
+ # type: (...) -> List[str]
"""
Get setuptools command arguments with shim wrapped setup file invocation.
:param setup_py_path: The path to setup.py to be wrapped.
+ :param global_options: Additional global options.
+ :param no_user_config: If True, disables personal user configuration.
:param unbuffered_output: If True, adds the unbuffered switch to the
argument list.
"""
args = [sys.executable]
if unbuffered_output:
- args.append('-u')
- args.extend(['-c', _SETUPTOOLS_SHIM.format(setup_py_path)])
+ args += ["-u"]
+ args += ["-c", _SETUPTOOLS_SHIM.format(setup_py_path)]
+ if global_options:
+ args += global_options
+ if no_user_config:
+ args += ["--no-user-cfg"]
+ return args
+
+
+def make_setuptools_bdist_wheel_args(
+ setup_py_path, # type: str
+ global_options, # type: Sequence[str]
+ build_options, # type: Sequence[str]
+ destination_dir, # type: str
+):
+ # type: (...) -> List[str]
+ # NOTE: Eventually, we'd want to also -S to the flags here, when we're
+ # isolating. Currently, it breaks Python in virtualenvs, because it
+ # relies on site.py to find parts of the standard library outside the
+ # virtualenv.
+ args = make_setuptools_shim_args(
+ setup_py_path,
+ global_options=global_options,
+ unbuffered_output=True
+ )
+ args += ["bdist_wheel", "-d", destination_dir]
+ args += build_options
+ return args
+
+
+def make_setuptools_clean_args(
+ setup_py_path, # type: str
+ global_options, # type: Sequence[str]
+):
+ # type: (...) -> List[str]
+ args = make_setuptools_shim_args(
+ setup_py_path,
+ global_options=global_options,
+ unbuffered_output=True
+ )
+ args += ["clean", "--all"]
+ return args
+
+
+def make_setuptools_develop_args(
+ setup_py_path, # type: str
+ global_options, # type: Sequence[str]
+ install_options, # type: Sequence[str]
+ no_user_config, # type: bool
+ prefix, # type: Optional[str]
+ home, # type: Optional[str]
+ use_user_site, # type: bool
+):
+ # type: (...) -> List[str]
+ assert not (use_user_site and prefix)
+
+ args = make_setuptools_shim_args(
+ setup_py_path,
+ global_options=global_options,
+ no_user_config=no_user_config,
+ )
+
+ args += ["develop", "--no-deps"]
+
+ args += install_options
+
+ if prefix:
+ args += ["--prefix", prefix]
+ if home is not None:
+ args += ["--home", home]
+
+ if use_user_site:
+ args += ["--user", "--prefix="]
+
+ return args
+
+
+def make_setuptools_egg_info_args(
+ setup_py_path, # type: str
+ egg_info_dir, # type: Optional[str]
+ no_user_config, # type: bool
+):
+ # type: (...) -> List[str]
+ args = make_setuptools_shim_args(
+ setup_py_path, no_user_config=no_user_config
+ )
+
+ args += ["egg_info"]
+
+ if egg_info_dir:
+ args += ["--egg-base", egg_info_dir]
+
+ return args
+
+
+def make_setuptools_install_args(
+ setup_py_path, # type: str
+ global_options, # type: Sequence[str]
+ install_options, # type: Sequence[str]
+ record_filename, # type: str
+ root, # type: Optional[str]
+ prefix, # type: Optional[str]
+ header_dir, # type: Optional[str]
+ home, # type: Optional[str]
+ use_user_site, # type: bool
+ no_user_config, # type: bool
+ pycompile # type: bool
+):
+ # type: (...) -> List[str]
+ assert not (use_user_site and prefix)
+ assert not (use_user_site and root)
+
+ args = make_setuptools_shim_args(
+ setup_py_path,
+ global_options=global_options,
+ no_user_config=no_user_config,
+ unbuffered_output=True
+ )
+ args += ["install", "--record", record_filename]
+ args += ["--single-version-externally-managed"]
+
+ if root is not None:
+ args += ["--root", root]
+ if prefix is not None:
+ args += ["--prefix", prefix]
+ if home is not None:
+ args += ["--home", home]
+ if use_user_site:
+ args += ["--user", "--prefix="]
+
+ if pycompile:
+ args += ["--compile"]
+ else:
+ args += ["--no-compile"]
+
+ if header_dir:
+ args += ["--install-headers", header_dir]
+
+ args += install_options
+
return args
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/temp_dir.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/temp_dir.py
index 2c81ad5..03aa828 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/utils/temp_dir.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/temp_dir.py
@@ -5,12 +5,95 @@ import itertools
import logging
import os.path
import tempfile
+from contextlib import contextmanager
+
+from pip._vendor.contextlib2 import ExitStack
+from pip._vendor.six import ensure_text
+
+from pip._internal.utils.misc import enum, rmtree
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+
+if MYPY_CHECK_RUNNING:
+ from typing import Any, Dict, Iterator, Optional, TypeVar, Union
+
+ _T = TypeVar('_T', bound='TempDirectory')
-from pip._internal.utils.misc import rmtree
logger = logging.getLogger(__name__)
+# Kinds of temporary directories. Only needed for ones that are
+# globally-managed.
+tempdir_kinds = enum(
+ BUILD_ENV="build-env",
+ EPHEM_WHEEL_CACHE="ephem-wheel-cache",
+ REQ_BUILD="req-build",
+)
+
+
+_tempdir_manager = None # type: Optional[ExitStack]
+
+
+@contextmanager
+def global_tempdir_manager():
+ # type: () -> Iterator[None]
+ global _tempdir_manager
+ with ExitStack() as stack:
+ old_tempdir_manager, _tempdir_manager = _tempdir_manager, stack
+ try:
+ yield
+ finally:
+ _tempdir_manager = old_tempdir_manager
+
+
+class TempDirectoryTypeRegistry(object):
+ """Manages temp directory behavior
+ """
+
+ def __init__(self):
+ # type: () -> None
+ self._should_delete = {} # type: Dict[str, bool]
+
+ def set_delete(self, kind, value):
+ # type: (str, bool) -> None
+ """Indicate whether a TempDirectory of the given kind should be
+ auto-deleted.
+ """
+ self._should_delete[kind] = value
+
+ def get_delete(self, kind):
+ # type: (str) -> bool
+ """Get configured auto-delete flag for a given TempDirectory type,
+ default True.
+ """
+ return self._should_delete.get(kind, True)
+
+
+_tempdir_registry = None # type: Optional[TempDirectoryTypeRegistry]
+
+
+@contextmanager
+def tempdir_registry():
+ # type: () -> Iterator[TempDirectoryTypeRegistry]
+ """Provides a scoped global tempdir registry that can be used to dictate
+ whether directories should be deleted.
+ """
+ global _tempdir_registry
+ old_tempdir_registry = _tempdir_registry
+ _tempdir_registry = TempDirectoryTypeRegistry()
+ try:
+ yield _tempdir_registry
+ finally:
+ _tempdir_registry = old_tempdir_registry
+
+
+class _Default(object):
+ pass
+
+
+_default = _Default()
+
+
class TempDirectory(object):
"""Helper class that owns and cleans up a temporary directory.
@@ -19,69 +102,101 @@ class TempDirectory(object):
Attributes:
path
- Location to the created temporary directory or None
+ Location to the created temporary directory
delete
Whether the directory should be deleted when exiting
(when used as a contextmanager)
Methods:
- create()
- Creates a temporary directory and stores its path in the path
- attribute.
cleanup()
- Deletes the temporary directory and sets path attribute to None
+ Deletes the temporary directory
- When used as a context manager, a temporary directory is created on
- entering the context and, if the delete attribute is True, on exiting the
- context the created directory is deleted.
+ When used as a context manager, if the delete attribute is True, on
+ exiting the context the temporary directory is deleted.
"""
- def __init__(self, path=None, delete=None, kind="temp"):
+ def __init__(
+ self,
+ path=None, # type: Optional[str]
+ delete=_default, # type: Union[bool, None, _Default]
+ kind="temp", # type: str
+ globally_managed=False, # type: bool
+ ):
super(TempDirectory, self).__init__()
- if path is None and delete is None:
- # If we were not given an explicit directory, and we were not given
- # an explicit delete option, then we'll default to deleting.
- delete = True
+ if delete is _default:
+ if path is not None:
+ # If we were given an explicit directory, resolve delete option
+ # now.
+ delete = False
+ else:
+ # Otherwise, we wait until cleanup and see what
+ # tempdir_registry says.
+ delete = None
- self.path = path
+ if path is None:
+ path = self._create(kind)
+
+ self._path = path
+ self._deleted = False
self.delete = delete
self.kind = kind
+ if globally_managed:
+ assert _tempdir_manager is not None
+ _tempdir_manager.enter_context(self)
+
+ @property
+ def path(self):
+ # type: () -> str
+ assert not self._deleted, (
+ "Attempted to access deleted path: {}".format(self._path)
+ )
+ return self._path
+
def __repr__(self):
+ # type: () -> str
return "<{} {!r}>".format(self.__class__.__name__, self.path)
def __enter__(self):
- self.create()
+ # type: (_T) -> _T
return self
def __exit__(self, exc, value, tb):
- if self.delete:
+ # type: (Any, Any, Any) -> None
+ if self.delete is not None:
+ delete = self.delete
+ elif _tempdir_registry:
+ delete = _tempdir_registry.get_delete(self.kind)
+ else:
+ delete = True
+
+ if delete:
self.cleanup()
- def create(self):
+ def _create(self, kind):
+ # type: (str) -> str
"""Create a temporary directory and store its path in self.path
"""
- if self.path is not None:
- logger.debug(
- "Skipped creation of temporary directory: {}".format(self.path)
- )
- return
# We realpath here because some systems have their default tmpdir
# symlinked to another directory. This tends to confuse build
# scripts, so we canonicalize the path by traversing potential
# symlinks here.
- self.path = os.path.realpath(
- tempfile.mkdtemp(prefix="pip-{}-".format(self.kind))
+ path = os.path.realpath(
+ tempfile.mkdtemp(prefix="pip-{}-".format(kind))
)
- logger.debug("Created temporary directory: {}".format(self.path))
+ logger.debug("Created temporary directory: %s", path)
+ return path
def cleanup(self):
+ # type: () -> None
"""Remove the temporary directory created and reset state
"""
- if self.path is not None and os.path.exists(self.path):
- rmtree(self.path)
- self.path = None
+ self._deleted = True
+ if os.path.exists(self._path):
+ # Make sure to pass unicode on Python 2 to make the contents also
+ # use unicode, ensuring non-ASCII names and can be represented.
+ rmtree(ensure_text(self._path))
class AdjacentTempDirectory(TempDirectory):
@@ -106,11 +221,13 @@ class AdjacentTempDirectory(TempDirectory):
LEADING_CHARS = "-~.=%0123456789"
def __init__(self, original, delete=None):
- super(AdjacentTempDirectory, self).__init__(delete=delete)
+ # type: (str, Optional[bool]) -> None
self.original = original.rstrip('/\\')
+ super(AdjacentTempDirectory, self).__init__(delete=delete)
@classmethod
def _generate_names(cls, name):
+ # type: (str) -> Iterator[str]
"""Generates a series of temporary names.
The algorithm replaces the leading characters in the name
@@ -133,7 +250,8 @@ class AdjacentTempDirectory(TempDirectory):
if new_name != name:
yield new_name
- def create(self):
+ def _create(self, kind):
+ # type: (str) -> str
root, name = os.path.split(self.original)
for candidate in self._generate_names(name):
path = os.path.join(root, candidate)
@@ -144,12 +262,13 @@ class AdjacentTempDirectory(TempDirectory):
if ex.errno != errno.EEXIST:
raise
else:
- self.path = os.path.realpath(path)
+ path = os.path.realpath(path)
break
-
- if not self.path:
+ else:
# Final fallback on the default behavior.
- self.path = os.path.realpath(
- tempfile.mkdtemp(prefix="pip-{}-".format(self.kind))
+ path = os.path.realpath(
+ tempfile.mkdtemp(prefix="pip-{}-".format(kind))
)
- logger.debug("Created temporary directory: {}".format(self.path))
+
+ logger.debug("Created temporary directory: %s", path)
+ return path
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/typing.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/typing.py
index 10170ce..8505a29 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/utils/typing.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/typing.py
@@ -27,3 +27,12 @@ Ref: https://github.com/python/mypy/issues/3216
"""
MYPY_CHECK_RUNNING = False
+
+
+if MYPY_CHECK_RUNNING:
+ from typing import cast
+else:
+ # typing's cast() is needed at runtime, but we don't want to import typing.
+ # Thus, we use a dummy no-op version, which we tell mypy to ignore.
+ def cast(type_, value): # type: ignore
+ return value
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/ui.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/ui.py
deleted file mode 100644
index 46390f4..0000000
--- a/venv/lib/python3.8/site-packages/pip/_internal/utils/ui.py
+++ /dev/null
@@ -1,424 +0,0 @@
-from __future__ import absolute_import, division
-
-import contextlib
-import itertools
-import logging
-import sys
-import time
-from signal import SIGINT, default_int_handler, signal
-
-from pip._vendor import six
-from pip._vendor.progress import HIDE_CURSOR, SHOW_CURSOR
-from pip._vendor.progress.bar import Bar, FillingCirclesBar, IncrementalBar
-from pip._vendor.progress.spinner import Spinner
-
-from pip._internal.utils.compat import WINDOWS
-from pip._internal.utils.logging import get_indentation
-from pip._internal.utils.misc import format_size
-from pip._internal.utils.typing import MYPY_CHECK_RUNNING
-
-if MYPY_CHECK_RUNNING:
- from typing import Any, Iterator, IO
-
-try:
- from pip._vendor import colorama
-# Lots of different errors can come from this, including SystemError and
-# ImportError.
-except Exception:
- colorama = None
-
-logger = logging.getLogger(__name__)
-
-
-def _select_progress_class(preferred, fallback):
- encoding = getattr(preferred.file, "encoding", None)
-
- # If we don't know what encoding this file is in, then we'll just assume
- # that it doesn't support unicode and use the ASCII bar.
- if not encoding:
- return fallback
-
- # Collect all of the possible characters we want to use with the preferred
- # bar.
- characters = [
- getattr(preferred, "empty_fill", six.text_type()),
- getattr(preferred, "fill", six.text_type()),
- ]
- characters += list(getattr(preferred, "phases", []))
-
- # Try to decode the characters we're using for the bar using the encoding
- # of the given file, if this works then we'll assume that we can use the
- # fancier bar and if not we'll fall back to the plaintext bar.
- try:
- six.text_type().join(characters).encode(encoding)
- except UnicodeEncodeError:
- return fallback
- else:
- return preferred
-
-
-_BaseBar = _select_progress_class(IncrementalBar, Bar) # type: Any
-
-
-class InterruptibleMixin(object):
- """
- Helper to ensure that self.finish() gets called on keyboard interrupt.
-
- This allows downloads to be interrupted without leaving temporary state
- (like hidden cursors) behind.
-
- This class is similar to the progress library's existing SigIntMixin
- helper, but as of version 1.2, that helper has the following problems:
-
- 1. It calls sys.exit().
- 2. It discards the existing SIGINT handler completely.
- 3. It leaves its own handler in place even after an uninterrupted finish,
- which will have unexpected delayed effects if the user triggers an
- unrelated keyboard interrupt some time after a progress-displaying
- download has already completed, for example.
- """
-
- def __init__(self, *args, **kwargs):
- """
- Save the original SIGINT handler for later.
- """
- super(InterruptibleMixin, self).__init__(*args, **kwargs)
-
- self.original_handler = signal(SIGINT, self.handle_sigint)
-
- # If signal() returns None, the previous handler was not installed from
- # Python, and we cannot restore it. This probably should not happen,
- # but if it does, we must restore something sensible instead, at least.
- # The least bad option should be Python's default SIGINT handler, which
- # just raises KeyboardInterrupt.
- if self.original_handler is None:
- self.original_handler = default_int_handler
-
- def finish(self):
- """
- Restore the original SIGINT handler after finishing.
-
- This should happen regardless of whether the progress display finishes
- normally, or gets interrupted.
- """
- super(InterruptibleMixin, self).finish()
- signal(SIGINT, self.original_handler)
-
- def handle_sigint(self, signum, frame):
- """
- Call self.finish() before delegating to the original SIGINT handler.
-
- This handler should only be in place while the progress display is
- active.
- """
- self.finish()
- self.original_handler(signum, frame)
-
-
-class SilentBar(Bar):
-
- def update(self):
- pass
-
-
-class BlueEmojiBar(IncrementalBar):
-
- suffix = "%(percent)d%%"
- bar_prefix = " "
- bar_suffix = " "
- phases = (u"\U0001F539", u"\U0001F537", u"\U0001F535") # type: Any
-
-
-class DownloadProgressMixin(object):
-
- def __init__(self, *args, **kwargs):
- super(DownloadProgressMixin, self).__init__(*args, **kwargs)
- self.message = (" " * (get_indentation() + 2)) + self.message
-
- @property
- def downloaded(self):
- return format_size(self.index)
-
- @property
- def download_speed(self):
- # Avoid zero division errors...
- if self.avg == 0.0:
- return "..."
- return format_size(1 / self.avg) + "/s"
-
- @property
- def pretty_eta(self):
- if self.eta:
- return "eta %s" % self.eta_td
- return ""
-
- def iter(self, it, n=1):
- for x in it:
- yield x
- self.next(n)
- self.finish()
-
-
-class WindowsMixin(object):
-
- def __init__(self, *args, **kwargs):
- # The Windows terminal does not support the hide/show cursor ANSI codes
- # even with colorama. So we'll ensure that hide_cursor is False on
- # Windows.
- # This call needs to go before the super() call, so that hide_cursor
- # is set in time. The base progress bar class writes the "hide cursor"
- # code to the terminal in its init, so if we don't set this soon
- # enough, we get a "hide" with no corresponding "show"...
- if WINDOWS and self.hide_cursor:
- self.hide_cursor = False
-
- super(WindowsMixin, self).__init__(*args, **kwargs)
-
- # Check if we are running on Windows and we have the colorama module,
- # if we do then wrap our file with it.
- if WINDOWS and colorama:
- self.file = colorama.AnsiToWin32(self.file)
- # The progress code expects to be able to call self.file.isatty()
- # but the colorama.AnsiToWin32() object doesn't have that, so we'll
- # add it.
- self.file.isatty = lambda: self.file.wrapped.isatty()
- # The progress code expects to be able to call self.file.flush()
- # but the colorama.AnsiToWin32() object doesn't have that, so we'll
- # add it.
- self.file.flush = lambda: self.file.wrapped.flush()
-
-
-class BaseDownloadProgressBar(WindowsMixin, InterruptibleMixin,
- DownloadProgressMixin):
-
- file = sys.stdout
- message = "%(percent)d%%"
- suffix = "%(downloaded)s %(download_speed)s %(pretty_eta)s"
-
-# NOTE: The "type: ignore" comments on the following classes are there to
-# work around https://github.com/python/typing/issues/241
-
-
-class DefaultDownloadProgressBar(BaseDownloadProgressBar,
- _BaseBar):
- pass
-
-
-class DownloadSilentBar(BaseDownloadProgressBar, SilentBar): # type: ignore
- pass
-
-
-class DownloadBar(BaseDownloadProgressBar, # type: ignore
- Bar):
- pass
-
-
-class DownloadFillingCirclesBar(BaseDownloadProgressBar, # type: ignore
- FillingCirclesBar):
- pass
-
-
-class DownloadBlueEmojiProgressBar(BaseDownloadProgressBar, # type: ignore
- BlueEmojiBar):
- pass
-
-
-class DownloadProgressSpinner(WindowsMixin, InterruptibleMixin,
- DownloadProgressMixin, Spinner):
-
- file = sys.stdout
- suffix = "%(downloaded)s %(download_speed)s"
-
- def next_phase(self):
- if not hasattr(self, "_phaser"):
- self._phaser = itertools.cycle(self.phases)
- return next(self._phaser)
-
- def update(self):
- message = self.message % self
- phase = self.next_phase()
- suffix = self.suffix % self
- line = ''.join([
- message,
- " " if message else "",
- phase,
- " " if suffix else "",
- suffix,
- ])
-
- self.writeln(line)
-
-
-BAR_TYPES = {
- "off": (DownloadSilentBar, DownloadSilentBar),
- "on": (DefaultDownloadProgressBar, DownloadProgressSpinner),
- "ascii": (DownloadBar, DownloadProgressSpinner),
- "pretty": (DownloadFillingCirclesBar, DownloadProgressSpinner),
- "emoji": (DownloadBlueEmojiProgressBar, DownloadProgressSpinner)
-}
-
-
-def DownloadProgressProvider(progress_bar, max=None):
- if max is None or max == 0:
- return BAR_TYPES[progress_bar][1]().iter
- else:
- return BAR_TYPES[progress_bar][0](max=max).iter
-
-
-################################################################
-# Generic "something is happening" spinners
-#
-# We don't even try using progress.spinner.Spinner here because it's actually
-# simpler to reimplement from scratch than to coerce their code into doing
-# what we need.
-################################################################
-
-@contextlib.contextmanager
-def hidden_cursor(file):
- # type: (IO) -> Iterator[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)
-
-
-class RateLimiter(object):
- def __init__(self, min_update_interval_seconds):
- # type: (float) -> None
- self._min_update_interval_seconds = min_update_interval_seconds
- self._last_update = 0 # type: float
-
- def ready(self):
- # type: () -> bool
- now = time.time()
- delta = now - self._last_update
- return delta >= self._min_update_interval_seconds
-
- def reset(self):
- # type: () -> None
- self._last_update = time.time()
-
-
-class SpinnerInterface(object):
- def spin(self):
- # type: () -> None
- raise NotImplementedError()
-
- def finish(self, final_status):
- # type: (str) -> None
- raise NotImplementedError()
-
-
-class InteractiveSpinner(SpinnerInterface):
- def __init__(self, message, file=None, spin_chars="-\\|/",
- # Empirically, 8 updates/second looks nice
- min_update_interval_seconds=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):
- 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):
- # type: () -> None
- if self._finished:
- return
- if not self._rate_limiter.ready():
- return
- self._write(next(self._spin_cycle))
-
- def finish(self, final_status):
- # type: (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, min_update_interval_seconds=60):
- # type: (str, float) -> None
- self._message = message
- self._finished = False
- self._rate_limiter = RateLimiter(min_update_interval_seconds)
- self._update("started")
-
- def _update(self, status):
- assert not self._finished
- self._rate_limiter.reset()
- logger.info("%s: %s", self._message, status)
-
- def spin(self):
- # type: () -> None
- if self._finished:
- return
- if not self._rate_limiter.ready():
- return
- self._update("still running...")
-
- def finish(self, final_status):
- # type: (str) -> None
- if self._finished:
- return
- self._update("finished with status '%s'" % (final_status,))
- self._finished = True
-
-
-@contextlib.contextmanager
-def open_spinner(message):
- # type: (str) -> Iterator[SpinnerInterface]
- # 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 = InteractiveSpinner(message) # type: SpinnerInterface
- 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")
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/utils/virtualenv.py b/venv/lib/python3.8/site-packages/pip/_internal/utils/virtualenv.py
index 380db1c..4a78128 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/utils/virtualenv.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/utils/virtualenv.py
@@ -1,34 +1,119 @@
-import os.path
+from __future__ import absolute_import
+
+import io
+import logging
+import os
+import re
import site
import sys
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+
+if MYPY_CHECK_RUNNING:
+ from typing import List, Optional
+
+logger = logging.getLogger(__name__)
+_INCLUDE_SYSTEM_SITE_PACKAGES_REGEX = re.compile(
+ r"include-system-site-packages\s*=\s*(?Ptrue|false)"
+)
+
+
+def _running_under_venv():
+ # type: () -> bool
+ """Checks if sys.base_prefix and sys.prefix match.
+
+ This handles PEP 405 compliant virtual environments.
+ """
+ return sys.prefix != getattr(sys, "base_prefix", sys.prefix)
+
+
+def _running_under_regular_virtualenv():
+ # type: () -> bool
+ """Checks if sys.real_prefix is set.
+
+ This handles virtual environments created with pypa's virtualenv.
+ """
+ # pypa/virtualenv case
+ return hasattr(sys, 'real_prefix')
+
def running_under_virtualenv():
# type: () -> bool
+ """Return True if we're running inside a virtualenv, False otherwise.
"""
- Return True if we're running inside a virtualenv, False otherwise.
+ return _running_under_venv() or _running_under_regular_virtualenv()
+
+def _get_pyvenv_cfg_lines():
+ # type: () -> Optional[List[str]]
+ """Reads {sys.prefix}/pyvenv.cfg and returns its contents as list of lines
+
+ Returns None, if it could not read/access the file.
"""
- if hasattr(sys, 'real_prefix'):
- # pypa/virtualenv case
- return True
- elif sys.prefix != getattr(sys, "base_prefix", sys.prefix):
- # PEP 405 venv
+ pyvenv_cfg_file = os.path.join(sys.prefix, 'pyvenv.cfg')
+ try:
+ # Although PEP 405 does not specify, the built-in venv module always
+ # writes with UTF-8. (pypa/pip#8717)
+ with io.open(pyvenv_cfg_file, encoding='utf-8') as f:
+ return f.read().splitlines() # avoids trailing newlines
+ except IOError:
+ return None
+
+
+def _no_global_under_venv():
+ # type: () -> bool
+ """Check `{sys.prefix}/pyvenv.cfg` for system site-packages inclusion
+
+ PEP 405 specifies that when system site-packages are not supposed to be
+ visible from a virtual environment, `pyvenv.cfg` must contain the following
+ line:
+
+ include-system-site-packages = false
+
+ Additionally, log a warning if accessing the file fails.
+ """
+ cfg_lines = _get_pyvenv_cfg_lines()
+ if cfg_lines is None:
+ # We're not in a "sane" venv, so assume there is no system
+ # site-packages access (since that's PEP 405's default state).
+ logger.warning(
+ "Could not access 'pyvenv.cfg' despite a virtual environment "
+ "being active. Assuming global site-packages is not accessible "
+ "in this environment."
+ )
return True
+ for line in cfg_lines:
+ match = _INCLUDE_SYSTEM_SITE_PACKAGES_REGEX.match(line)
+ if match is not None and match.group('value') == 'false':
+ return True
return False
+def _no_global_under_regular_virtualenv():
+ # type: () -> bool
+ """Check if "no-global-site-packages.txt" exists beside site.py
+
+ This mirrors logic in pypa/virtualenv for determining whether system
+ site-packages are visible in the virtual environment.
+ """
+ site_mod_dir = os.path.dirname(os.path.abspath(site.__file__))
+ no_global_site_packages_file = os.path.join(
+ site_mod_dir, 'no-global-site-packages.txt',
+ )
+ return os.path.exists(no_global_site_packages_file)
+
+
def virtualenv_no_global():
# type: () -> bool
+ """Returns a boolean, whether running in venv with no system site-packages.
"""
- Return True if in a venv and no system site packages.
- """
- # this mirrors the logic in virtualenv.py for locating the
- # no-global-site-packages.txt file
- site_mod_dir = os.path.dirname(os.path.abspath(site.__file__))
- no_global_file = os.path.join(site_mod_dir, 'no-global-site-packages.txt')
- if running_under_virtualenv() and os.path.isfile(no_global_file):
- return True
- else:
- return False
+ # PEP 405 compliance needs to be checked first since virtualenv >=20 would
+ # return True for both checks, but is only able to use the PEP 405 config.
+ if _running_under_venv():
+ return _no_global_under_venv()
+
+ if _running_under_regular_virtualenv():
+ return _no_global_under_regular_virtualenv()
+
+ return False
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/__init__.py b/venv/lib/python3.8/site-packages/pip/_internal/vcs/__init__.py
index cb573ab..2a4eb13 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/vcs/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/vcs/__init__.py
@@ -2,11 +2,14 @@
# the vcs package don't need to import deeper than `pip._internal.vcs`.
# (The test directory and imports protected by MYPY_CHECK_RUNNING may
# still need to import from a vcs sub-package.)
-from pip._internal.vcs.versioncontrol import ( # noqa: F401
- RemoteNotFoundError, make_vcs_requirement_url, vcs,
-)
# Import all vcs modules to register each VCS in the VcsSupport object.
import pip._internal.vcs.bazaar
import pip._internal.vcs.git
import pip._internal.vcs.mercurial
import pip._internal.vcs.subversion # noqa: F401
+from pip._internal.vcs.versioncontrol import ( # noqa: F401
+ RemoteNotFoundError,
+ is_url,
+ make_vcs_requirement_url,
+ vcs,
+)
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-38.pyc
index bee208c..ec5c7e0 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-38.pyc
index 3d993d5..56630ab 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/git.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/git.cpython-38.pyc
index a5c2a85..baa50fe 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/git.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/git.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-38.pyc
index 1944fd8..bfae02d 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-38.pyc
index 43308a1..67dd212 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-38.pyc
index cb4eb56..518ff68 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/bazaar.py b/venv/lib/python3.8/site-packages/pip/_internal/vcs/bazaar.py
index 4f1e114..94408c5 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/vcs/bazaar.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/vcs/bazaar.py
@@ -1,3 +1,6 @@
+# The following comment should be removed at some point in the future.
+# mypy: disallow-untyped-defs=False
+
from __future__ import absolute_import
import logging
@@ -5,9 +8,18 @@ import os
from pip._vendor.six.moves.urllib import parse as urllib_parse
-from pip._internal.utils.misc import display_path, path_to_url, rmtree
+from pip._internal.utils.misc import display_path, rmtree
+from pip._internal.utils.subprocess import make_command
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+from pip._internal.utils.urls import path_to_url
from pip._internal.vcs.versioncontrol import VersionControl, vcs
+if MYPY_CHECK_RUNNING:
+ from typing import Optional, Tuple
+ from pip._internal.utils.misc import HiddenText
+ from pip._internal.vcs.versioncontrol import AuthInfo, RevOptions
+
+
logger = logging.getLogger(__name__)
@@ -32,6 +44,7 @@ class Bazaar(VersionControl):
return ['-r', rev]
def export(self, location, url):
+ # type: (str, HiddenText) -> None
"""
Export the Bazaar repository at the url to the destination location
"""
@@ -41,11 +54,11 @@ class Bazaar(VersionControl):
url, rev_options = self.get_url_rev_options(url)
self.run_command(
- ['export', location, url] + rev_options.to_args(),
- show_stdout=False,
+ make_command('export', location, url, rev_options.to_args())
)
def fetch_new(self, dest, url, rev_options):
+ # type: (str, HiddenText, RevOptions) -> None
rev_display = rev_options.to_display()
logger.info(
'Checking out %s%s to %s',
@@ -53,18 +66,23 @@ class Bazaar(VersionControl):
rev_display,
display_path(dest),
)
- cmd_args = ['branch', '-q'] + rev_options.to_args() + [url, dest]
+ cmd_args = (
+ make_command('branch', '-q', rev_options.to_args(), url, dest)
+ )
self.run_command(cmd_args)
def switch(self, dest, url, rev_options):
- self.run_command(['switch', url], cwd=dest)
+ # type: (str, HiddenText, RevOptions) -> None
+ self.run_command(make_command('switch', url), cwd=dest)
def update(self, dest, url, rev_options):
- cmd_args = ['pull', '-q'] + rev_options.to_args()
+ # type: (str, HiddenText, RevOptions) -> None
+ cmd_args = make_command('pull', '-q', rev_options.to_args())
self.run_command(cmd_args, cwd=dest)
@classmethod
def get_url_rev_and_auth(cls, url):
+ # type: (str) -> Tuple[str, Optional[str], AuthInfo]
# hotfix the URL scheme after removing bzr+ from bzr+ssh:// readd it
url, rev, user_pass = super(Bazaar, cls).get_url_rev_and_auth(url)
if url.startswith('ssh://'):
@@ -73,7 +91,7 @@ class Bazaar(VersionControl):
@classmethod
def get_remote_url(cls, location):
- urls = cls.run_command(['info'], show_stdout=False, cwd=location)
+ urls = cls.run_command(['info'], cwd=location)
for line in urls.splitlines():
line = line.strip()
for x in ('checkout of branch: ',
@@ -88,7 +106,7 @@ class Bazaar(VersionControl):
@classmethod
def get_revision(cls, location):
revision = cls.run_command(
- ['revno'], show_stdout=False, cwd=location,
+ ['revno'], cwd=location,
)
return revision.splitlines()[-1]
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/git.py b/venv/lib/python3.8/site-packages/pip/_internal/vcs/git.py
index 3445c1b..a9c7fb6 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/vcs/git.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/vcs/git.py
@@ -1,3 +1,6 @@
+# The following comment should be removed at some point in the future.
+# mypy: disallow-untyped-defs=False
+
from __future__ import absolute_import
import logging
@@ -8,14 +11,24 @@ from pip._vendor.packaging.version import parse as parse_version
from pip._vendor.six.moves.urllib import parse as urllib_parse
from pip._vendor.six.moves.urllib import request as urllib_request
-from pip._internal.exceptions import BadCommand
-from pip._internal.utils.compat import samefile
-from pip._internal.utils.misc import display_path, redact_password_from_url
+from pip._internal.exceptions import BadCommand, SubProcessError
+from pip._internal.utils.misc import display_path, hide_url
+from pip._internal.utils.subprocess import make_command
from pip._internal.utils.temp_dir import TempDirectory
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
from pip._internal.vcs.versioncontrol import (
- RemoteNotFoundError, VersionControl, vcs,
+ RemoteNotFoundError,
+ VersionControl,
+ find_path_to_setup_from_repo_root,
+ vcs,
)
+if MYPY_CHECK_RUNNING:
+ from typing import Optional, Tuple
+ from pip._internal.utils.misc import HiddenText
+ from pip._internal.vcs.versioncontrol import AuthInfo, RevOptions
+
+
urlsplit = urllib_parse.urlsplit
urlunsplit = urllib_parse.urlunsplit
@@ -46,9 +59,26 @@ class Git(VersionControl):
def get_base_rev_args(rev):
return [rev]
+ def is_immutable_rev_checkout(self, url, dest):
+ # type: (str, str) -> bool
+ _, rev_options = self.get_url_rev_options(hide_url(url))
+ if not rev_options.rev:
+ return False
+ if not self.is_commit_id_equal(dest, rev_options.rev):
+ # the current commit is different from rev,
+ # which means rev was something else than a commit hash
+ return False
+ # return False in the rare case rev is both a commit hash
+ # and a tag or a branch; we don't want to cache in that case
+ # because that branch/tag could point to something else in the future
+ is_tag_or_branch = bool(
+ self.get_revision_sha(dest, rev_options.rev)[0]
+ )
+ return not is_tag_or_branch
+
def get_git_version(self):
VERSION_PFX = 'git version '
- version = self.run_command(['version'], show_stdout=False)
+ version = self.run_command(['version'])
if version.startswith(VERSION_PFX):
version = version[len(VERSION_PFX):].split()[0]
else:
@@ -71,7 +101,7 @@ class Git(VersionControl):
# and to suppress the message to stderr.
args = ['symbolic-ref', '-q', 'HEAD']
output = cls.run_command(
- args, extra_ok_returncodes=(1, ), show_stdout=False, cwd=location,
+ args, extra_ok_returncodes=(1, ), cwd=location,
)
ref = output.strip()
@@ -81,6 +111,7 @@ class Git(VersionControl):
return None
def export(self, location, url):
+ # type: (str, HiddenText) -> None
"""Export the Git repository at the url to the destination location"""
if not location.endswith('/'):
location = location + '/'
@@ -89,7 +120,7 @@ class Git(VersionControl):
self.unpack(temp_dir.path, url=url)
self.run_command(
['checkout-index', '-a', '-f', '--prefix', location],
- show_stdout=False, cwd=temp_dir.path
+ cwd=temp_dir.path
)
@classmethod
@@ -103,8 +134,13 @@ class Git(VersionControl):
rev: the revision name.
"""
# Pass rev to pre-filter the list.
- output = cls.run_command(['show-ref', rev], cwd=dest,
- show_stdout=False, on_returncode='ignore')
+
+ output = ''
+ try:
+ output = cls.run_command(['show-ref', rev], cwd=dest)
+ except SubProcessError:
+ pass
+
refs = {}
for line in output.strip().splitlines():
try:
@@ -129,6 +165,7 @@ class Git(VersionControl):
@classmethod
def resolve_revision(cls, dest, url, rev_options):
+ # type: (str, HiddenText, RevOptions) -> RevOptions
"""
Resolve a revision to a new RevOptions object with the SHA1 of the
branch, tag, or ref if found.
@@ -137,6 +174,10 @@ class Git(VersionControl):
rev_options: a RevOptions object.
"""
rev = rev_options.arg_rev
+ # The arg_rev property's implementation for Git ensures that the
+ # rev return value is always non-None.
+ assert rev is not None
+
sha, is_branch = cls.get_revision_sha(dest, rev)
if sha is not None:
@@ -158,7 +199,7 @@ class Git(VersionControl):
# If it looks like a ref, we have to fetch it explicitly.
cls.run_command(
- ['fetch', '-q', url] + rev_options.to_args(),
+ make_command('fetch', '-q', url, rev_options.to_args()),
cwd=dest,
)
# Change the revision to the SHA of the ref we fetched
@@ -183,12 +224,10 @@ class Git(VersionControl):
return cls.get_revision(dest) == name
def fetch_new(self, dest, url, rev_options):
+ # type: (str, HiddenText, RevOptions) -> None
rev_display = rev_options.to_display()
- logger.info(
- 'Cloning %s%s to %s', redact_password_from_url(url),
- rev_display, display_path(dest),
- )
- self.run_command(['clone', '-q', url, dest])
+ logger.info('Cloning %s%s to %s', url, rev_display, display_path(dest))
+ self.run_command(make_command('clone', '-q', url, dest))
if rev_options.rev:
# Then a specific revision was requested.
@@ -198,7 +237,9 @@ class Git(VersionControl):
# Only do a checkout if the current commit id doesn't match
# the requested revision.
if not self.is_commit_id_equal(dest, rev_options.rev):
- cmd_args = ['checkout', '-q'] + rev_options.to_args()
+ cmd_args = make_command(
+ 'checkout', '-q', rev_options.to_args(),
+ )
self.run_command(cmd_args, cwd=dest)
elif self.get_current_branch(dest) != branch_name:
# Then a specific branch was requested, and that branch
@@ -213,13 +254,18 @@ class Git(VersionControl):
self.update_submodules(dest)
def switch(self, dest, url, rev_options):
- self.run_command(['config', 'remote.origin.url', url], cwd=dest)
- cmd_args = ['checkout', '-q'] + rev_options.to_args()
+ # type: (str, HiddenText, RevOptions) -> None
+ self.run_command(
+ make_command('config', 'remote.origin.url', url),
+ cwd=dest,
+ )
+ cmd_args = make_command('checkout', '-q', rev_options.to_args())
self.run_command(cmd_args, cwd=dest)
self.update_submodules(dest)
def update(self, dest, url, rev_options):
+ # type: (str, HiddenText, RevOptions) -> None
# First fetch changes from the default remote
if self.get_git_version() >= parse_version('1.9.0'):
# fetch tags in addition to everything else
@@ -228,7 +274,7 @@ class Git(VersionControl):
self.run_command(['fetch', '-q'], cwd=dest)
# Then reset to wanted revision (maybe even origin/master)
rev_options = self.resolve_revision(dest, url, rev_options)
- cmd_args = ['reset', '--hard', '-q'] + rev_options.to_args()
+ cmd_args = make_command('reset', '--hard', '-q', rev_options.to_args())
self.run_command(cmd_args, cwd=dest)
#: update submodules
self.update_submodules(dest)
@@ -245,7 +291,7 @@ class Git(VersionControl):
# exits with return code 1 if there are no matching lines.
stdout = cls.run_command(
['config', '--get-regexp', r'remote\..*\.url'],
- extra_ok_returncodes=(1, ), show_stdout=False, cwd=location,
+ extra_ok_returncodes=(1, ), cwd=location,
)
remotes = stdout.splitlines()
try:
@@ -265,39 +311,28 @@ class Git(VersionControl):
if rev is None:
rev = 'HEAD'
current_rev = cls.run_command(
- ['rev-parse', rev], show_stdout=False, cwd=location,
+ ['rev-parse', rev], cwd=location,
)
return current_rev.strip()
@classmethod
def get_subdirectory(cls, location):
+ """
+ Return the path to setup.py, relative to the repo root.
+ Return None if setup.py is in the repo root.
+ """
# find the repo root
- git_dir = cls.run_command(['rev-parse', '--git-dir'],
- show_stdout=False, cwd=location).strip()
+ git_dir = cls.run_command(
+ ['rev-parse', '--git-dir'],
+ cwd=location).strip()
if not os.path.isabs(git_dir):
git_dir = os.path.join(location, git_dir)
- root_dir = os.path.join(git_dir, '..')
- # find setup.py
- orig_location = location
- while not os.path.exists(os.path.join(location, 'setup.py')):
- last_location = location
- location = os.path.dirname(location)
- if location == last_location:
- # We've traversed up to the root of the filesystem without
- # finding setup.py
- logger.warning(
- "Could not find setup.py for directory %s (tried all "
- "parent directories)",
- orig_location,
- )
- return None
- # relative path of setup.py to repo root
- if samefile(root_dir, location):
- return None
- return os.path.relpath(location, root_dir)
+ repo_root = os.path.abspath(os.path.join(git_dir, '..'))
+ return find_path_to_setup_from_repo_root(location, repo_root)
@classmethod
def get_url_rev_and_auth(cls, url):
+ # type: (str) -> Tuple[str, Optional[str], AuthInfo]
"""
Prefixes stub URLs like 'user@hostname:user/repo.git' with 'ssh://'.
That's required because although they use SSH they sometimes don't
@@ -340,19 +375,23 @@ class Git(VersionControl):
)
@classmethod
- def controls_location(cls, location):
- if super(Git, cls).controls_location(location):
- return True
+ def get_repository_root(cls, location):
+ loc = super(Git, cls).get_repository_root(location)
+ if loc:
+ return loc
try:
- r = cls.run_command(['rev-parse'],
- cwd=location,
- show_stdout=False,
- on_returncode='ignore')
- return not r
+ r = cls.run_command(
+ ['rev-parse', '--show-toplevel'],
+ cwd=location,
+ log_failed_cmd=False,
+ )
except BadCommand:
logger.debug("could not determine if %s is under git control "
"because git is not available", location)
- return False
+ return None
+ except SubProcessError:
+ return None
+ return os.path.normpath(r.rstrip('\r\n'))
vcs.register(Git)
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/mercurial.py b/venv/lib/python3.8/site-packages/pip/_internal/vcs/mercurial.py
index db42783..69763fe 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/vcs/mercurial.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/vcs/mercurial.py
@@ -1,3 +1,6 @@
+# The following comment should be removed at some point in the future.
+# mypy: disallow-untyped-defs=False
+
from __future__ import absolute_import
import logging
@@ -5,9 +8,22 @@ import os
from pip._vendor.six.moves import configparser
-from pip._internal.utils.misc import display_path, path_to_url
+from pip._internal.exceptions import BadCommand, SubProcessError
+from pip._internal.utils.misc import display_path
+from pip._internal.utils.subprocess import make_command
from pip._internal.utils.temp_dir import TempDirectory
-from pip._internal.vcs.versioncontrol import VersionControl, vcs
+from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+from pip._internal.utils.urls import path_to_url
+from pip._internal.vcs.versioncontrol import (
+ VersionControl,
+ find_path_to_setup_from_repo_root,
+ vcs,
+)
+
+if MYPY_CHECK_RUNNING:
+ from pip._internal.utils.misc import HiddenText
+ from pip._internal.vcs.versioncontrol import RevOptions
+
logger = logging.getLogger(__name__)
@@ -16,22 +32,26 @@ class Mercurial(VersionControl):
name = 'hg'
dirname = '.hg'
repo_name = 'clone'
- schemes = ('hg', 'hg+http', 'hg+https', 'hg+ssh', 'hg+static-http')
+ schemes = (
+ 'hg', 'hg+file', 'hg+http', 'hg+https', 'hg+ssh', 'hg+static-http',
+ )
@staticmethod
def get_base_rev_args(rev):
return [rev]
def export(self, location, url):
+ # type: (str, HiddenText) -> None
"""Export the Hg repository at the url to the destination location"""
with TempDirectory(kind="export") as temp_dir:
self.unpack(temp_dir.path, url=url)
self.run_command(
- ['archive', location], show_stdout=False, cwd=temp_dir.path
+ ['archive', location], cwd=temp_dir.path
)
def fetch_new(self, dest, url, rev_options):
+ # type: (str, HiddenText, RevOptions) -> None
rev_display = rev_options.to_display()
logger.info(
'Cloning hg %s%s to %s',
@@ -39,16 +59,19 @@ class Mercurial(VersionControl):
rev_display,
display_path(dest),
)
- self.run_command(['clone', '--noupdate', '-q', url, dest])
- cmd_args = ['update', '-q'] + rev_options.to_args()
- self.run_command(cmd_args, cwd=dest)
+ self.run_command(make_command('clone', '--noupdate', '-q', url, dest))
+ self.run_command(
+ make_command('update', '-q', rev_options.to_args()),
+ cwd=dest,
+ )
def switch(self, dest, url, rev_options):
+ # type: (str, HiddenText, RevOptions) -> None
repo_config = os.path.join(dest, self.dirname, 'hgrc')
config = configparser.RawConfigParser()
try:
config.read(repo_config)
- config.set('paths', 'default', url)
+ config.set('paths', 'default', url.secret)
with open(repo_config, 'w') as config_file:
config.write(config_file)
except (OSError, configparser.NoSectionError) as exc:
@@ -56,19 +79,20 @@ class Mercurial(VersionControl):
'Could not switch Mercurial repository to %s: %s', url, exc,
)
else:
- cmd_args = ['update', '-q'] + rev_options.to_args()
+ cmd_args = make_command('update', '-q', rev_options.to_args())
self.run_command(cmd_args, cwd=dest)
def update(self, dest, url, rev_options):
+ # type: (str, HiddenText, RevOptions) -> None
self.run_command(['pull', '-q'], cwd=dest)
- cmd_args = ['update', '-q'] + rev_options.to_args()
+ cmd_args = make_command('update', '-q', rev_options.to_args())
self.run_command(cmd_args, cwd=dest)
@classmethod
def get_remote_url(cls, location):
url = cls.run_command(
['showconfig', 'paths.default'],
- show_stdout=False, cwd=location).strip()
+ cwd=location).strip()
if cls._is_local_repository(url):
url = path_to_url(url)
return url.strip()
@@ -79,8 +103,7 @@ class Mercurial(VersionControl):
Return the repository-local changeset revision number, as an integer.
"""
current_revision = cls.run_command(
- ['parents', '--template={rev}'],
- show_stdout=False, cwd=location).strip()
+ ['parents', '--template={rev}'], cwd=location).strip()
return current_revision
@classmethod
@@ -91,7 +114,7 @@ class Mercurial(VersionControl):
"""
current_rev_hash = cls.run_command(
['parents', '--template={node}'],
- show_stdout=False, cwd=location).strip()
+ cwd=location).strip()
return current_rev_hash
@classmethod
@@ -99,5 +122,37 @@ class Mercurial(VersionControl):
"""Always assume the versions don't match"""
return False
+ @classmethod
+ def get_subdirectory(cls, location):
+ """
+ Return the path to setup.py, relative to the repo root.
+ Return None if setup.py is in the repo root.
+ """
+ # find the repo root
+ repo_root = cls.run_command(
+ ['root'], cwd=location).strip()
+ if not os.path.isabs(repo_root):
+ repo_root = os.path.abspath(os.path.join(location, repo_root))
+ return find_path_to_setup_from_repo_root(location, repo_root)
+
+ @classmethod
+ def get_repository_root(cls, location):
+ loc = super(Mercurial, cls).get_repository_root(location)
+ if loc:
+ return loc
+ try:
+ r = cls.run_command(
+ ['root'],
+ cwd=location,
+ log_failed_cmd=False,
+ )
+ except BadCommand:
+ logger.debug("could not determine if %s is under hg control "
+ "because hg is not available", location)
+ return None
+ except SubProcessError:
+ return None
+ return os.path.normpath(r.rstrip('\r\n'))
+
vcs.register(Mercurial)
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/subversion.py b/venv/lib/python3.8/site-packages/pip/_internal/vcs/subversion.py
index 6bb4c8c..ab13497 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/vcs/subversion.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/vcs/subversion.py
@@ -1,14 +1,20 @@
+# The following comment should be removed at some point in the future.
+# mypy: disallow-untyped-defs=False
+
from __future__ import absolute_import
import logging
import os
import re
-import sys
from pip._internal.utils.logging import indent_log
from pip._internal.utils.misc import (
- display_path, rmtree, split_auth_from_netloc,
+ display_path,
+ is_console_interactive,
+ rmtree,
+ split_auth_from_netloc,
)
+from pip._internal.utils.subprocess import make_command
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
from pip._internal.vcs.versioncontrol import VersionControl, vcs
@@ -19,8 +25,11 @@ _svn_info_xml_url_re = re.compile(r'(.*) ')
if MYPY_CHECK_RUNNING:
- from typing import List, Optional, Tuple
- from pip._internal.vcs.versioncontrol import RevOptions
+ from typing import Optional, Tuple
+ from pip._internal.utils.subprocess import CommandArgs
+ from pip._internal.utils.misc import HiddenText
+ from pip._internal.vcs.versioncontrol import AuthInfo, RevOptions
+
logger = logging.getLogger(__name__)
@@ -47,7 +56,7 @@ class Subversion(VersionControl):
# Note: taken from setuptools.command.egg_info
revision = 0
- for base, dirs, files in os.walk(location):
+ for base, dirs, _ in os.walk(location):
if cls.dirname not in dirs:
dirs[:] = []
continue # no sense walking uncontrolled subdirs
@@ -82,6 +91,7 @@ class Subversion(VersionControl):
@classmethod
def get_url_rev_and_auth(cls, url):
+ # type: (str) -> Tuple[str, Optional[str], AuthInfo]
# hotfix the URL scheme after removing svn+ from svn+ssh:// readd it
url, rev, user_pass = super(Subversion, cls).get_url_rev_and_auth(url)
if url.startswith('ssh://'):
@@ -90,7 +100,8 @@ class Subversion(VersionControl):
@staticmethod
def make_rev_args(username, password):
- extra_args = []
+ # type: (Optional[str], Optional[HiddenText]) -> CommandArgs
+ extra_args = [] # type: CommandArgs
if username:
extra_args += ['--username', username]
if password:
@@ -121,7 +132,7 @@ class Subversion(VersionControl):
@classmethod
def _get_svn_url_rev(cls, location):
- from pip._internal.exceptions import InstallationError
+ from pip._internal.exceptions import SubProcessError
entries_path = os.path.join(location, cls.dirname, 'entries')
if os.path.exists(entries_path):
@@ -140,7 +151,8 @@ class Subversion(VersionControl):
elif data.startswith(' None
if use_interactive is None:
- use_interactive = sys.stdin.isatty()
+ use_interactive = is_console_interactive()
self.use_interactive = use_interactive
# This member is used to cache the fetched version of the current
@@ -202,13 +213,16 @@ class Subversion(VersionControl):
# compiled Feb 25 2019, 14:20:39 on x86_64-apple-darwin17.0.0
# svn, version 1.7.14 (r1542130)
# compiled Mar 28 2018, 08:49:13 on x86_64-pc-linux-gnu
+ # svn, version 1.12.0-SlikSvn (SlikSvn/1.12.0)
+ # compiled May 28 2019, 13:44:56 on x86_64-microsoft-windows6.2
version_prefix = 'svn, version '
- version = self.run_command(['--version'], show_stdout=False)
+ version = self.run_command(['--version'])
+
if not version.startswith(version_prefix):
return ()
version = version[len(version_prefix):].split()[0]
- version_list = version.split('.')
+ version_list = version.partition('-')[0].split('.')
try:
parsed_version = tuple(map(int, version_list))
except ValueError:
@@ -238,7 +252,7 @@ class Subversion(VersionControl):
return vcs_version
def get_remote_call_options(self):
- # type: () -> List[str]
+ # type: () -> CommandArgs
"""Return options to be used on calls to Subversion that contact the server.
These options are applicable for the following ``svn`` subcommands used
@@ -271,6 +285,7 @@ class Subversion(VersionControl):
return []
def export(self, location, url):
+ # type: (str, HiddenText) -> None
"""Export the svn repository at the url to the destination location"""
url, rev_options = self.get_url_rev_options(url)
@@ -280,12 +295,14 @@ class Subversion(VersionControl):
# Subversion doesn't like to check out over an existing
# directory --force fixes this, but was only added in svn 1.5
rmtree(location)
- cmd_args = (['export'] + self.get_remote_call_options() +
- rev_options.to_args() + [url, location])
- self.run_command(cmd_args, show_stdout=False)
+ cmd_args = make_command(
+ 'export', self.get_remote_call_options(),
+ rev_options.to_args(), url, location,
+ )
+ self.run_command(cmd_args)
def fetch_new(self, dest, url, rev_options):
- # type: (str, str, RevOptions) -> None
+ # type: (str, HiddenText, RevOptions) -> None
rev_display = rev_options.to_display()
logger.info(
'Checking out %s%s to %s',
@@ -293,21 +310,26 @@ class Subversion(VersionControl):
rev_display,
display_path(dest),
)
- cmd_args = (['checkout', '-q'] +
- self.get_remote_call_options() +
- rev_options.to_args() + [url, dest])
+ cmd_args = make_command(
+ 'checkout', '-q', self.get_remote_call_options(),
+ rev_options.to_args(), url, dest,
+ )
self.run_command(cmd_args)
def switch(self, dest, url, rev_options):
- # type: (str, str, RevOptions) -> None
- cmd_args = (['switch'] + self.get_remote_call_options() +
- rev_options.to_args() + [url, dest])
+ # type: (str, HiddenText, RevOptions) -> None
+ cmd_args = make_command(
+ 'switch', self.get_remote_call_options(), rev_options.to_args(),
+ url, dest,
+ )
self.run_command(cmd_args)
def update(self, dest, url, rev_options):
- # type: (str, str, RevOptions) -> None
- cmd_args = (['update'] + self.get_remote_call_options() +
- rev_options.to_args() + [dest])
+ # type: (str, HiddenText, RevOptions) -> None
+ cmd_args = make_command(
+ 'update', self.get_remote_call_options(), rev_options.to_args(),
+ dest,
+ )
self.run_command(cmd_args)
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/vcs/versioncontrol.py b/venv/lib/python3.8/site-packages/pip/_internal/vcs/versioncontrol.py
index 2d05fc1..96f830f 100644
--- a/venv/lib/python3.8/site-packages/pip/_internal/vcs/versioncontrol.py
+++ b/venv/lib/python3.8/site-packages/pip/_internal/vcs/versioncontrol.py
@@ -1,36 +1,71 @@
"""Handles all VCS (version control) support"""
+
from __future__ import absolute_import
import errno
import logging
import os
import shutil
+import subprocess
import sys
from pip._vendor import pkg_resources
from pip._vendor.six.moves.urllib import parse as urllib_parse
-from pip._internal.exceptions import BadCommand
+from pip._internal.exceptions import (
+ BadCommand,
+ InstallationError,
+ SubProcessError,
+)
+from pip._internal.utils.compat import console_to_str, samefile
+from pip._internal.utils.logging import subprocess_logger
from pip._internal.utils.misc import (
- ask_path_exists, backup_dir, call_subprocess, display_path, rmtree,
+ ask_path_exists,
+ backup_dir,
+ display_path,
+ hide_url,
+ hide_value,
+ rmtree,
+)
+from pip._internal.utils.subprocess import (
+ format_command_args,
+ make_command,
+ make_subprocess_output_error,
+ reveal_command_args,
)
from pip._internal.utils.typing import MYPY_CHECK_RUNNING
+from pip._internal.utils.urls import get_url_scheme
if MYPY_CHECK_RUNNING:
from typing import (
- Any, Dict, Iterable, List, Mapping, Optional, Text, Tuple, Type
+ Dict, Iterable, Iterator, List, Optional, Text, Tuple,
+ Type, Union, Mapping, Any
)
- from pip._internal.utils.ui import SpinnerInterface
+ from pip._internal.utils.misc import HiddenText
+ from pip._internal.utils.subprocess import CommandArgs
AuthInfo = Tuple[Optional[str], Optional[str]]
+
__all__ = ['vcs']
logger = logging.getLogger(__name__)
+def is_url(name):
+ # type: (Union[str, Text]) -> bool
+ """
+ Return true if the name looks like a URL.
+ """
+ scheme = get_url_scheme(name)
+ if scheme is None:
+ return False
+ return scheme in ['http', 'https', 'file', 'ftp'] + vcs.all_schemes
+
+
def make_vcs_requirement_url(repo_url, rev, project_name, subdir=None):
+ # type: (str, str, str, Optional[str]) -> str
"""
Return the URL for a VCS requirement.
@@ -46,6 +81,120 @@ def make_vcs_requirement_url(repo_url, rev, project_name, subdir=None):
return req
+def call_subprocess(
+ cmd, # type: Union[List[str], CommandArgs]
+ cwd=None, # type: Optional[str]
+ extra_environ=None, # type: Optional[Mapping[str, Any]]
+ extra_ok_returncodes=None, # type: Optional[Iterable[int]]
+ log_failed_cmd=True # type: Optional[bool]
+):
+ # type: (...) -> Text
+ """
+ Args:
+ extra_ok_returncodes: an iterable of integer return codes that are
+ acceptable, in addition to 0. Defaults to None, which means [].
+ log_failed_cmd: if false, failed commands are not logged,
+ only raised.
+ """
+ if extra_ok_returncodes is None:
+ extra_ok_returncodes = []
+
+ # log the subprocess output at DEBUG level.
+ log_subprocess = subprocess_logger.debug
+
+ env = os.environ.copy()
+ if extra_environ:
+ env.update(extra_environ)
+
+ # Whether the subprocess will be visible in the console.
+ showing_subprocess = True
+
+ command_desc = format_command_args(cmd)
+ try:
+ proc = subprocess.Popen(
+ # Convert HiddenText objects to the underlying str.
+ reveal_command_args(cmd),
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ cwd=cwd
+ )
+ if proc.stdin:
+ proc.stdin.close()
+ except Exception as exc:
+ if log_failed_cmd:
+ subprocess_logger.critical(
+ "Error %s while executing command %s", exc, command_desc,
+ )
+ raise
+ all_output = []
+ while True:
+ # The "line" value is a unicode string in Python 2.
+ line = None
+ if proc.stdout:
+ line = console_to_str(proc.stdout.readline())
+ if not line:
+ break
+ line = line.rstrip()
+ all_output.append(line + '\n')
+
+ # Show the line immediately.
+ log_subprocess(line)
+ try:
+ proc.wait()
+ finally:
+ if proc.stdout:
+ proc.stdout.close()
+
+ proc_had_error = (
+ proc.returncode and proc.returncode not in extra_ok_returncodes
+ )
+ if proc_had_error:
+ if not showing_subprocess and log_failed_cmd:
+ # Then the subprocess streams haven't been logged to the
+ # console yet.
+ msg = make_subprocess_output_error(
+ cmd_args=cmd,
+ cwd=cwd,
+ lines=all_output,
+ exit_status=proc.returncode,
+ )
+ subprocess_logger.error(msg)
+ exc_msg = (
+ 'Command errored out with exit status {}: {} '
+ 'Check the logs for full command output.'
+ ).format(proc.returncode, command_desc)
+ raise SubProcessError(exc_msg)
+ return ''.join(all_output)
+
+
+def find_path_to_setup_from_repo_root(location, repo_root):
+ # type: (str, str) -> Optional[str]
+ """
+ Find the path to `setup.py` by searching up the filesystem from `location`.
+ Return the path to `setup.py` relative to `repo_root`.
+ Return None if `setup.py` is in `repo_root` or cannot be found.
+ """
+ # find setup.py
+ orig_location = location
+ while not os.path.exists(os.path.join(location, 'setup.py')):
+ last_location = location
+ location = os.path.dirname(location)
+ if location == last_location:
+ # We've traversed up to the root of the filesystem without
+ # finding setup.py
+ logger.warning(
+ "Could not find setup.py for directory %s (tried all "
+ "parent directories)",
+ orig_location,
+ )
+ return None
+
+ if samefile(repo_root, location):
+ return None
+
+ return os.path.relpath(location, repo_root)
+
+
class RemoteNotFoundError(Exception):
pass
@@ -63,7 +212,7 @@ class RevOptions(object):
self,
vc_class, # type: Type[VersionControl]
rev=None, # type: Optional[str]
- extra_args=None, # type: Optional[List[str]]
+ extra_args=None, # type: Optional[CommandArgs]
):
# type: (...) -> None
"""
@@ -78,8 +227,10 @@ class RevOptions(object):
self.extra_args = extra_args
self.rev = rev
self.vc_class = vc_class
+ self.branch_name = None # type: Optional[str]
def __repr__(self):
+ # type: () -> str
return ''.format(self.vc_class.name, self.rev)
@property
@@ -91,11 +242,11 @@ class RevOptions(object):
return self.rev
def to_args(self):
- # type: () -> List[str]
+ # type: () -> CommandArgs
"""
Return the VCS-specific command arguments.
"""
- args = [] # type: List[str]
+ args = [] # type: CommandArgs
rev = self.arg_rev
if rev is not None:
args += self.vc_class.get_base_rev_args(rev)
@@ -136,6 +287,7 @@ class VcsSupport(object):
super(VcsSupport, self).__init__()
def __iter__(self):
+ # type: () -> Iterator[str]
return self._registry.__iter__()
@property
@@ -176,10 +328,32 @@ class VcsSupport(object):
Return a VersionControl object if a repository of that type is found
at the given directory.
"""
+ vcs_backends = {}
for vcs_backend in self._registry.values():
- if vcs_backend.controls_location(location):
- logger.debug('Determine that %s uses VCS: %s',
- location, vcs_backend.name)
+ repo_path = vcs_backend.get_repository_root(location)
+ if not repo_path:
+ continue
+ logger.debug('Determine that %s uses VCS: %s',
+ location, vcs_backend.name)
+ vcs_backends[repo_path] = vcs_backend
+
+ if not vcs_backends:
+ return None
+
+ # Choose the VCS in the inner-most directory. Since all repository
+ # roots found here would be either `location` or one of its
+ # parents, the longest path should have the most path components,
+ # i.e. the backend representing the inner-most repository.
+ inner_most_repo_path = max(vcs_backends, key=len)
+ return vcs_backends[inner_most_repo_path]
+
+ def get_backend_for_scheme(self, scheme):
+ # type: (str) -> Optional[VersionControl]
+ """
+ Return a VersionControl object or None.
+ """
+ for vcs_backend in self._registry.values():
+ if scheme in vcs_backend.schemes:
return vcs_backend
return None
@@ -207,6 +381,7 @@ class VersionControl(object):
@classmethod
def should_add_vcs_url_prefix(cls, remote_url):
+ # type: (str) -> bool
"""
Return whether the vcs prefix (e.g. "git+") should be added to a
repository's remote url when used in a requirement.
@@ -214,14 +389,17 @@ class VersionControl(object):
return not remote_url.lower().startswith('{}:'.format(cls.name))
@classmethod
- def get_subdirectory(cls, repo_dir):
+ def get_subdirectory(cls, location):
+ # type: (str) -> Optional[str]
"""
Return the path to setup.py, relative to the repo root.
+ Return None if setup.py is in the repo root.
"""
return None
@classmethod
def get_requirement_revision(cls, repo_dir):
+ # type: (str) -> str
"""
Return the revision string that should be used in a requirement.
"""
@@ -229,6 +407,7 @@ class VersionControl(object):
@classmethod
def get_src_requirement(cls, repo_dir, project_name):
+ # type: (str, str) -> Optional[str]
"""
Return the requirement string to use to redownload the files
currently at the given repository directory.
@@ -256,6 +435,7 @@ class VersionControl(object):
@staticmethod
def get_base_rev_args(rev):
+ # type: (str) -> List[str]
"""
Return the base revision arguments for a vcs command.
@@ -264,9 +444,23 @@ class VersionControl(object):
"""
raise NotImplementedError
+ def is_immutable_rev_checkout(self, url, dest):
+ # type: (str, str) -> bool
+ """
+ Return true if the commit hash checked out at dest matches
+ the revision in url.
+
+ Always return False, if the VCS does not support immutable commit
+ hashes.
+
+ This method does not check if there are local uncommitted changes
+ in dest after checkout, as pip currently has no use case for that.
+ """
+ return False
+
@classmethod
def make_rev_options(cls, rev=None, extra_args=None):
- # type: (Optional[str], Optional[List[str]]) -> RevOptions
+ # type: (Optional[str], Optional[CommandArgs]) -> RevOptions
"""
Return a RevOptions object.
@@ -287,6 +481,7 @@ class VersionControl(object):
return repo.startswith(os.path.sep) or bool(drive)
def export(self, location, url):
+ # type: (str, HiddenText) -> None
"""
Export the repository at the url to the destination location
i.e. only download the files, without vcs informations
@@ -297,6 +492,7 @@ class VersionControl(object):
@classmethod
def get_netloc_and_auth(cls, netloc, scheme):
+ # type: (str, str) -> Tuple[str, Tuple[Optional[str], Optional[str]]]
"""
Parse the repository URL's netloc, and return the new netloc to use
along with auth information.
@@ -336,28 +532,38 @@ class VersionControl(object):
rev = None
if '@' in path:
path, rev = path.rsplit('@', 1)
+ if not rev:
+ raise InstallationError(
+ "The URL {!r} has an empty revision (after @) "
+ "which is not supported. Include a revision after @ "
+ "or remove @ from the URL.".format(url)
+ )
url = urllib_parse.urlunsplit((scheme, netloc, path, query, ''))
return url, rev, user_pass
@staticmethod
def make_rev_args(username, password):
+ # type: (Optional[str], Optional[HiddenText]) -> CommandArgs
"""
Return the RevOptions "extra arguments" to use in obtain().
"""
return []
def get_url_rev_options(self, url):
- # type: (str) -> Tuple[str, RevOptions]
+ # type: (HiddenText) -> Tuple[HiddenText, RevOptions]
"""
Return the URL and RevOptions object to use in obtain() and in
some cases export(), as a tuple (url, rev_options).
"""
- url, rev, user_pass = self.get_url_rev_and_auth(url)
- username, password = user_pass
+ secret_url, rev, user_pass = self.get_url_rev_and_auth(url.secret)
+ username, secret_password = user_pass
+ password = None # type: Optional[HiddenText]
+ if secret_password is not None:
+ password = hide_value(secret_password)
extra_args = self.make_rev_args(username, password)
rev_options = self.make_rev_options(rev, extra_args=extra_args)
- return url, rev_options
+ return hide_url(secret_url), rev_options
@staticmethod
def normalize_url(url):
@@ -377,6 +583,7 @@ class VersionControl(object):
return (cls.normalize_url(url1) == cls.normalize_url(url2))
def fetch_new(self, dest, url, rev_options):
+ # type: (str, HiddenText, RevOptions) -> None
"""
Fetch a revision from a repository, in the case that this is the
first fetch from the repository.
@@ -388,6 +595,7 @@ class VersionControl(object):
raise NotImplementedError
def switch(self, dest, url, rev_options):
+ # type: (str, HiddenText, RevOptions) -> None
"""
Switch the repo at ``dest`` to point to ``URL``.
@@ -397,6 +605,7 @@ class VersionControl(object):
raise NotImplementedError
def update(self, dest, url, rev_options):
+ # type: (str, HiddenText, RevOptions) -> None
"""
Update an already-existing repo to the given ``rev_options``.
@@ -407,6 +616,7 @@ class VersionControl(object):
@classmethod
def is_commit_id_equal(cls, dest, name):
+ # type: (str, Optional[str]) -> bool
"""
Return whether the id of the current commit equals the given name.
@@ -417,7 +627,7 @@ class VersionControl(object):
raise NotImplementedError
def obtain(self, dest, url):
- # type: (str, str) -> None
+ # type: (str, HiddenText) -> None
"""
Install or update in editable mode the package represented by this
VersionControl object.
@@ -434,7 +644,7 @@ class VersionControl(object):
rev_display = rev_options.to_display()
if self.is_repository_directory(dest):
existing_url = self.get_remote_url(dest)
- if self.compare_urls(existing_url, url):
+ if self.compare_urls(existing_url, url.secret):
logger.debug(
'%s in %s exists, and has correct URL (%s)',
self.repo_name.title(),
@@ -478,7 +688,8 @@ class VersionControl(object):
self.name,
url,
)
- response = ask_path_exists('What to do? %s' % prompt[0], prompt[1])
+ response = ask_path_exists('What to do? {}'.format(
+ prompt[0]), prompt[1])
if response == 'a':
sys.exit(-1)
@@ -510,7 +721,7 @@ class VersionControl(object):
self.switch(dest, url, rev_options)
def unpack(self, location, url):
- # type: (str, str) -> None
+ # type: (str, HiddenText) -> None
"""
Clean up current location and download the url repository
(and vcs infos) into location
@@ -523,6 +734,7 @@ class VersionControl(object):
@classmethod
def get_remote_url(cls, location):
+ # type: (str) -> str
"""
Return the url used at location
@@ -533,6 +745,7 @@ class VersionControl(object):
@classmethod
def get_revision(cls, location):
+ # type: (str) -> str
"""
Return the current commit id of the files at the given location.
"""
@@ -541,14 +754,11 @@ class VersionControl(object):
@classmethod
def run_command(
cls,
- cmd, # type: List[str]
- show_stdout=True, # type: bool
+ cmd, # type: Union[List[str], CommandArgs]
cwd=None, # type: Optional[str]
- on_returncode='raise', # type: str
- extra_ok_returncodes=None, # type: Optional[Iterable[int]]
- command_desc=None, # type: Optional[str]
extra_environ=None, # type: Optional[Mapping[str, Any]]
- spinner=None # type: Optional[SpinnerInterface]
+ extra_ok_returncodes=None, # type: Optional[Iterable[int]]
+ log_failed_cmd=True # type: bool
):
# type: (...) -> Text
"""
@@ -556,23 +766,20 @@ class VersionControl(object):
This is simply a wrapper around call_subprocess that adds the VCS
command name, and checks that the VCS is available
"""
- cmd = [cls.name] + cmd
+ cmd = make_command(cls.name, *cmd)
try:
- return call_subprocess(cmd, show_stdout, cwd,
- on_returncode=on_returncode,
- extra_ok_returncodes=extra_ok_returncodes,
- command_desc=command_desc,
+ return call_subprocess(cmd, cwd,
extra_environ=extra_environ,
- unset_environ=cls.unset_environ,
- spinner=spinner)
+ extra_ok_returncodes=extra_ok_returncodes,
+ log_failed_cmd=log_failed_cmd)
except OSError as e:
# errno.ENOENT = no such file or directory
# In other words, the VCS executable isn't available
if e.errno == errno.ENOENT:
raise BadCommand(
- 'Cannot find command %r - do you have '
- '%r installed and in your '
- 'PATH?' % (cls.name, cls.name))
+ 'Cannot find command {cls.name!r} - do you have '
+ '{cls.name!r} installed and in your '
+ 'PATH?'.format(**locals()))
else:
raise # re-raise exception if a different error occurred
@@ -587,14 +794,18 @@ class VersionControl(object):
return os.path.exists(os.path.join(path, cls.dirname))
@classmethod
- def controls_location(cls, location):
- # type: (str) -> bool
+ def get_repository_root(cls, location):
+ # type: (str) -> Optional[str]
"""
- Check if a location is controlled by the vcs.
+ Return the "root" (top-level) directory controlled by the vcs,
+ or `None` if the directory is not in any.
+
It is meant to be overridden to implement smarter detection
mechanisms for specific vcs.
- This can do more than is_repository_directory() alone. For example,
- the Git override checks that Git is actually available.
+ This can do more than is_repository_directory() alone. For
+ example, the Git override checks that Git is actually available.
"""
- return cls.is_repository_directory(location)
+ if cls.is_repository_directory(location):
+ return location
+ return None
diff --git a/venv/lib/python3.8/site-packages/pip/_internal/wheel.py b/venv/lib/python3.8/site-packages/pip/_internal/wheel.py
deleted file mode 100644
index 6f034cd..0000000
--- a/venv/lib/python3.8/site-packages/pip/_internal/wheel.py
+++ /dev/null
@@ -1,1125 +0,0 @@
-"""
-Support for installing and building the "wheel" binary package format.
-"""
-from __future__ import absolute_import
-
-import collections
-import compileall
-import csv
-import hashlib
-import logging
-import os.path
-import re
-import shutil
-import stat
-import sys
-import warnings
-from base64 import urlsafe_b64encode
-from email.parser import Parser
-
-from pip._vendor import pkg_resources
-from pip._vendor.distlib.scripts import ScriptMaker
-from pip._vendor.packaging.utils import canonicalize_name
-from pip._vendor.six import StringIO
-
-from pip._internal import pep425tags
-from pip._internal.download import unpack_url
-from pip._internal.exceptions import (
- InstallationError, InvalidWheelFilename, UnsupportedWheel,
-)
-from pip._internal.locations import distutils_scheme
-from pip._internal.models.link import Link
-from pip._internal.utils.logging import indent_log
-from pip._internal.utils.marker_files import PIP_DELETE_MARKER_FILENAME
-from pip._internal.utils.misc import (
- LOG_DIVIDER, call_subprocess, captured_stdout, ensure_dir,
- format_command_args, path_to_url, read_chunks,
-)
-from pip._internal.utils.setuptools_build import make_setuptools_shim_args
-from pip._internal.utils.temp_dir import TempDirectory
-from pip._internal.utils.typing import MYPY_CHECK_RUNNING
-from pip._internal.utils.ui import open_spinner
-
-if MYPY_CHECK_RUNNING:
- from typing import (
- Dict, List, Optional, Sequence, Mapping, Tuple, IO, Text, Any, Iterable
- )
- from pip._vendor.packaging.requirements import Requirement
- from pip._internal.req.req_install import InstallRequirement
- from pip._internal.download import PipSession
- from pip._internal.index import FormatControl, PackageFinder
- from pip._internal.operations.prepare import (
- RequirementPreparer
- )
- from pip._internal.cache import WheelCache
- from pip._internal.pep425tags import Pep425Tag
-
- InstalledCSVRow = Tuple[str, ...]
-
-
-VERSION_COMPATIBLE = (1, 0)
-
-
-logger = logging.getLogger(__name__)
-
-
-def normpath(src, p):
- return os.path.relpath(src, p).replace(os.path.sep, '/')
-
-
-def hash_file(path, blocksize=1 << 20):
- # type: (str, int) -> Tuple[Any, int]
- """Return (hash, length) for path using hashlib.sha256()"""
- h = hashlib.sha256()
- length = 0
- with open(path, 'rb') as f:
- for block in read_chunks(f, size=blocksize):
- length += len(block)
- h.update(block)
- return (h, length) # type: ignore
-
-
-def rehash(path, blocksize=1 << 20):
- # type: (str, int) -> Tuple[str, str]
- """Return (encoded_digest, length) for path using hashlib.sha256()"""
- h, length = hash_file(path, blocksize)
- digest = 'sha256=' + urlsafe_b64encode(
- h.digest()
- ).decode('latin1').rstrip('=')
- # unicode/str python2 issues
- return (digest, str(length)) # type: ignore
-
-
-def open_for_csv(name, mode):
- # type: (str, Text) -> IO
- if sys.version_info[0] < 3:
- nl = {} # type: Dict[str, Any]
- bin = 'b'
- else:
- nl = {'newline': ''} # type: Dict[str, Any]
- bin = ''
- return open(name, mode + bin, **nl)
-
-
-def replace_python_tag(wheelname, new_tag):
- # type: (str, str) -> str
- """Replace the Python tag in a wheel file name with a new value.
- """
- parts = wheelname.split('-')
- parts[-3] = new_tag
- return '-'.join(parts)
-
-
-def fix_script(path):
- # type: (str) -> Optional[bool]
- """Replace #!python with #!/path/to/python
- Return True if file was changed."""
- # XXX RECORD hashes will need to be updated
- if os.path.isfile(path):
- with open(path, 'rb') as script:
- firstline = script.readline()
- if not firstline.startswith(b'#!python'):
- return False
- exename = sys.executable.encode(sys.getfilesystemencoding())
- firstline = b'#!' + exename + os.linesep.encode("ascii")
- rest = script.read()
- with open(path, 'wb') as script:
- script.write(firstline)
- script.write(rest)
- return True
- return None
-
-
-dist_info_re = re.compile(r"""^(?P(?P.+?)(-(?P.+?))?)
- \.dist-info$""", re.VERBOSE)
-
-
-def root_is_purelib(name, wheeldir):
- # type: (str, str) -> bool
- """
- Return True if the extracted wheel in wheeldir should go into purelib.
- """
- name_folded = name.replace("-", "_")
- for item in os.listdir(wheeldir):
- match = dist_info_re.match(item)
- if match and match.group('name') == name_folded:
- with open(os.path.join(wheeldir, item, 'WHEEL')) as wheel:
- for line in wheel:
- line = line.lower().rstrip()
- if line == "root-is-purelib: true":
- return True
- return False
-
-
-def get_entrypoints(filename):
- # type: (str) -> Tuple[Dict[str, str], Dict[str, str]]
- if not os.path.exists(filename):
- return {}, {}
-
- # This is done because you can pass a string to entry_points wrappers which
- # means that they may or may not be valid INI files. The attempt here is to
- # strip leading and trailing whitespace in order to make them valid INI
- # files.
- with open(filename) as fp:
- data = StringIO()
- for line in fp:
- data.write(line.strip())
- data.write("\n")
- data.seek(0)
-
- # get the entry points and then the script names
- entry_points = pkg_resources.EntryPoint.parse_map(data)
- console = entry_points.get('console_scripts', {})
- gui = entry_points.get('gui_scripts', {})
-
- def _split_ep(s):
- """get the string representation of EntryPoint, remove space and split
- on '='"""
- return str(s).replace(" ", "").split("=")
-
- # convert the EntryPoint objects into strings with module:function
- console = dict(_split_ep(v) for v in console.values())
- gui = dict(_split_ep(v) for v in gui.values())
- return console, gui
-
-
-def message_about_scripts_not_on_PATH(scripts):
- # type: (Sequence[str]) -> Optional[str]
- """Determine if any scripts are not on PATH and format a warning.
-
- Returns a warning message if one or more scripts are not on PATH,
- otherwise None.
- """
- if not scripts:
- return None
-
- # Group scripts by the path they were installed in
- grouped_by_dir = collections.defaultdict(set) # type: Dict[str, set]
- for destfile in scripts:
- parent_dir = os.path.dirname(destfile)
- script_name = os.path.basename(destfile)
- grouped_by_dir[parent_dir].add(script_name)
-
- # We don't want to warn for directories that are on PATH.
- not_warn_dirs = [
- os.path.normcase(i).rstrip(os.sep) for i in
- os.environ.get("PATH", "").split(os.pathsep)
- ]
- # If an executable sits with sys.executable, we don't warn for it.
- # This covers the case of venv invocations without activating the venv.
- not_warn_dirs.append(os.path.normcase(os.path.dirname(sys.executable)))
- warn_for = {
- parent_dir: scripts for parent_dir, scripts in grouped_by_dir.items()
- if os.path.normcase(parent_dir) not in not_warn_dirs
- }
- if not warn_for:
- return None
-
- # Format a message
- msg_lines = []
- for parent_dir, scripts in warn_for.items():
- sorted_scripts = sorted(scripts) # type: List[str]
- if len(sorted_scripts) == 1:
- start_text = "script {} is".format(sorted_scripts[0])
- else:
- start_text = "scripts {} are".format(
- ", ".join(sorted_scripts[:-1]) + " and " + sorted_scripts[-1]
- )
-
- msg_lines.append(
- "The {} installed in '{}' which is not on PATH."
- .format(start_text, parent_dir)
- )
-
- last_line_fmt = (
- "Consider adding {} to PATH or, if you prefer "
- "to suppress this warning, use --no-warn-script-location."
- )
- if len(msg_lines) == 1:
- msg_lines.append(last_line_fmt.format("this directory"))
- else:
- msg_lines.append(last_line_fmt.format("these directories"))
-
- # Returns the formatted multiline message
- return "\n".join(msg_lines)
-
-
-def sorted_outrows(outrows):
- # type: (Iterable[InstalledCSVRow]) -> List[InstalledCSVRow]
- """
- Return the given rows of a RECORD file in sorted order.
-
- Each row is a 3-tuple (path, hash, size) and corresponds to a record of
- a RECORD file (see PEP 376 and PEP 427 for details). For the rows
- passed to this function, the size can be an integer as an int or string,
- or the empty string.
- """
- # Normally, there should only be one row per path, in which case the
- # second and third elements don't come into play when sorting.
- # However, in cases in the wild where a path might happen to occur twice,
- # we don't want the sort operation to trigger an error (but still want
- # determinism). Since the third element can be an int or string, we
- # coerce each element to a string to avoid a TypeError in this case.
- # For additional background, see--
- # https://github.com/pypa/pip/issues/5868
- return sorted(outrows, key=lambda row: tuple(str(x) for x in row))
-
-
-def get_csv_rows_for_installed(
- old_csv_rows, # type: Iterable[List[str]]
- installed, # type: Dict[str, str]
- changed, # type: set
- generated, # type: List[str]
- lib_dir, # type: str
-):
- # type: (...) -> List[InstalledCSVRow]
- """
- :param installed: A map from archive RECORD path to installation RECORD
- path.
- """
- installed_rows = [] # type: List[InstalledCSVRow]
- for row in old_csv_rows:
- if len(row) > 3:
- logger.warning(
- 'RECORD line has more than three elements: {}'.format(row)
- )
- # Make a copy because we are mutating the row.
- row = list(row)
- old_path = row[0]
- new_path = installed.pop(old_path, old_path)
- row[0] = new_path
- if new_path in changed:
- digest, length = rehash(new_path)
- row[1] = digest
- row[2] = length
- installed_rows.append(tuple(row))
- for f in generated:
- digest, length = rehash(f)
- installed_rows.append((normpath(f, lib_dir), digest, str(length)))
- for f in installed:
- installed_rows.append((installed[f], '', ''))
- return installed_rows
-
-
-def move_wheel_files(
- name, # type: str
- req, # type: Requirement
- wheeldir, # type: str
- user=False, # type: bool
- home=None, # type: Optional[str]
- root=None, # type: Optional[str]
- pycompile=True, # type: bool
- scheme=None, # type: Optional[Mapping[str, str]]
- isolated=False, # type: bool
- prefix=None, # type: Optional[str]
- warn_script_location=True # type: bool
-):
- # type: (...) -> None
- """Install a wheel"""
- # TODO: Investigate and break this up.
- # TODO: Look into moving this into a dedicated class for representing an
- # installation.
-
- if not scheme:
- scheme = distutils_scheme(
- name, user=user, home=home, root=root, isolated=isolated,
- prefix=prefix,
- )
-
- if root_is_purelib(name, wheeldir):
- lib_dir = scheme['purelib']
- else:
- lib_dir = scheme['platlib']
-
- info_dir = [] # type: List[str]
- data_dirs = []
- source = wheeldir.rstrip(os.path.sep) + os.path.sep
-
- # Record details of the files moved
- # installed = files copied from the wheel to the destination
- # changed = files changed while installing (scripts #! line typically)
- # generated = files newly generated during the install (script wrappers)
- installed = {} # type: Dict[str, str]
- changed = set()
- generated = [] # type: List[str]
-
- # Compile all of the pyc files that we're going to be installing
- if pycompile:
- with captured_stdout() as stdout:
- with warnings.catch_warnings():
- warnings.filterwarnings('ignore')
- compileall.compile_dir(source, force=True, quiet=True)
- logger.debug(stdout.getvalue())
-
- def record_installed(srcfile, destfile, modified=False):
- """Map archive RECORD paths to installation RECORD paths."""
- oldpath = normpath(srcfile, wheeldir)
- newpath = normpath(destfile, lib_dir)
- installed[oldpath] = newpath
- if modified:
- changed.add(destfile)
-
- def clobber(source, dest, is_base, fixer=None, filter=None):
- ensure_dir(dest) # common for the 'include' path
-
- for dir, subdirs, files in os.walk(source):
- basedir = dir[len(source):].lstrip(os.path.sep)
- destdir = os.path.join(dest, basedir)
- if is_base and basedir.split(os.path.sep, 1)[0].endswith('.data'):
- continue
- for s in subdirs:
- destsubdir = os.path.join(dest, basedir, s)
- if is_base and basedir == '' and destsubdir.endswith('.data'):
- data_dirs.append(s)
- continue
- elif (is_base and
- s.endswith('.dist-info') and
- canonicalize_name(s).startswith(
- canonicalize_name(req.name))):
- assert not info_dir, ('Multiple .dist-info directories: ' +
- destsubdir + ', ' +
- ', '.join(info_dir))
- info_dir.append(destsubdir)
- for f in files:
- # Skip unwanted files
- if filter and filter(f):
- continue
- srcfile = os.path.join(dir, f)
- destfile = os.path.join(dest, basedir, f)
- # directory creation is lazy and after the file filtering above
- # to ensure we don't install empty dirs; empty dirs can't be
- # uninstalled.
- ensure_dir(destdir)
-
- # copyfile (called below) truncates the destination if it
- # exists and then writes the new contents. This is fine in most
- # cases, but can cause a segfault if pip has loaded a shared
- # object (e.g. from pyopenssl through its vendored urllib3)
- # Since the shared object is mmap'd an attempt to call a
- # symbol in it will then cause a segfault. Unlinking the file
- # allows writing of new contents while allowing the process to
- # continue to use the old copy.
- if os.path.exists(destfile):
- os.unlink(destfile)
-
- # We use copyfile (not move, copy, or copy2) to be extra sure
- # that we are not moving directories over (copyfile fails for
- # directories) as well as to ensure that we are not copying
- # over any metadata because we want more control over what
- # metadata we actually copy over.
- shutil.copyfile(srcfile, destfile)
-
- # Copy over the metadata for the file, currently this only
- # includes the atime and mtime.
- st = os.stat(srcfile)
- if hasattr(os, "utime"):
- os.utime(destfile, (st.st_atime, st.st_mtime))
-
- # If our file is executable, then make our destination file
- # executable.
- if os.access(srcfile, os.X_OK):
- st = os.stat(srcfile)
- permissions = (
- st.st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
- )
- os.chmod(destfile, permissions)
-
- changed = False
- if fixer:
- changed = fixer(destfile)
- record_installed(srcfile, destfile, changed)
-
- clobber(source, lib_dir, True)
-
- assert info_dir, "%s .dist-info directory not found" % req
-
- # Get the defined entry points
- ep_file = os.path.join(info_dir[0], 'entry_points.txt')
- console, gui = get_entrypoints(ep_file)
-
- def is_entrypoint_wrapper(name):
- # EP, EP.exe and EP-script.py are scripts generated for
- # entry point EP by setuptools
- if name.lower().endswith('.exe'):
- matchname = name[:-4]
- elif name.lower().endswith('-script.py'):
- matchname = name[:-10]
- elif name.lower().endswith(".pya"):
- matchname = name[:-4]
- else:
- matchname = name
- # Ignore setuptools-generated scripts
- return (matchname in console or matchname in gui)
-
- for datadir in data_dirs:
- fixer = None
- filter = None
- for subdir in os.listdir(os.path.join(wheeldir, datadir)):
- fixer = None
- if subdir == 'scripts':
- fixer = fix_script
- filter = is_entrypoint_wrapper
- source = os.path.join(wheeldir, datadir, subdir)
- dest = scheme[subdir]
- clobber(source, dest, False, fixer=fixer, filter=filter)
-
- maker = ScriptMaker(None, scheme['scripts'])
-
- # Ensure old scripts are overwritten.
- # See https://github.com/pypa/pip/issues/1800
- maker.clobber = True
-
- # Ensure we don't generate any variants for scripts because this is almost
- # never what somebody wants.
- # See https://bitbucket.org/pypa/distlib/issue/35/
- maker.variants = {''}
-
- # This is required because otherwise distlib creates scripts that are not
- # executable.
- # See https://bitbucket.org/pypa/distlib/issue/32/
- maker.set_mode = True
-
- # Simplify the script and fix the fact that the default script swallows
- # every single stack trace.
- # See https://bitbucket.org/pypa/distlib/issue/34/
- # See https://bitbucket.org/pypa/distlib/issue/33/
- def _get_script_text(entry):
- if entry.suffix is None:
- raise InstallationError(
- "Invalid script entry point: %s for req: %s - A callable "
- "suffix is required. Cf https://packaging.python.org/en/"
- "latest/distributing.html#console-scripts for more "
- "information." % (entry, req)
- )
- return maker.script_template % {
- "module": entry.prefix,
- "import_name": entry.suffix.split(".")[0],
- "func": entry.suffix,
- }
- # ignore type, because mypy disallows assigning to a method,
- # see https://github.com/python/mypy/issues/2427
- maker._get_script_text = _get_script_text # type: ignore
- maker.script_template = r"""# -*- coding: utf-8 -*-
-import re
-import sys
-
-from %(module)s import %(import_name)s
-
-if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
- sys.exit(%(func)s())
-"""
-
- # Special case pip and setuptools to generate versioned wrappers
- #
- # The issue is that some projects (specifically, pip and setuptools) use
- # code in setup.py to create "versioned" entry points - pip2.7 on Python
- # 2.7, pip3.3 on Python 3.3, etc. But these entry points are baked into
- # the wheel metadata at build time, and so if the wheel is installed with
- # a *different* version of Python the entry points will be wrong. The
- # correct fix for this is to enhance the metadata to be able to describe
- # such versioned entry points, but that won't happen till Metadata 2.0 is
- # available.
- # In the meantime, projects using versioned entry points will either have
- # incorrect versioned entry points, or they will not be able to distribute
- # "universal" wheels (i.e., they will need a wheel per Python version).
- #
- # Because setuptools and pip are bundled with _ensurepip and virtualenv,
- # we need to use universal wheels. So, as a stopgap until Metadata 2.0, we
- # override the versioned entry points in the wheel and generate the
- # correct ones. This code is purely a short-term measure until Metadata 2.0
- # is available.
- #
- # To add the level of hack in this section of code, in order to support
- # ensurepip this code will look for an ``ENSUREPIP_OPTIONS`` environment
- # variable which will control which version scripts get installed.
- #
- # ENSUREPIP_OPTIONS=altinstall
- # - Only pipX.Y and easy_install-X.Y will be generated and installed
- # ENSUREPIP_OPTIONS=install
- # - pipX.Y, pipX, easy_install-X.Y will be generated and installed. Note
- # that this option is technically if ENSUREPIP_OPTIONS is set and is
- # not altinstall
- # DEFAULT
- # - The default behavior is to install pip, pipX, pipX.Y, easy_install
- # and easy_install-X.Y.
- pip_script = console.pop('pip', None)
- if pip_script:
- if "ENSUREPIP_OPTIONS" not in os.environ:
- spec = 'pip = ' + pip_script
- generated.extend(maker.make(spec))
-
- if os.environ.get("ENSUREPIP_OPTIONS", "") != "altinstall":
- spec = 'pip%s = %s' % (sys.version[:1], pip_script)
- generated.extend(maker.make(spec))
-
- spec = 'pip%s = %s' % (sys.version[:3], pip_script)
- generated.extend(maker.make(spec))
- # Delete any other versioned pip entry points
- pip_ep = [k for k in console if re.match(r'pip(\d(\.\d)?)?$', k)]
- for k in pip_ep:
- del console[k]
- easy_install_script = console.pop('easy_install', None)
- if easy_install_script:
- if "ENSUREPIP_OPTIONS" not in os.environ:
- spec = 'easy_install = ' + easy_install_script
- generated.extend(maker.make(spec))
-
- spec = 'easy_install-%s = %s' % (sys.version[:3], easy_install_script)
- generated.extend(maker.make(spec))
- # Delete any other versioned easy_install entry points
- easy_install_ep = [
- k for k in console if re.match(r'easy_install(-\d\.\d)?$', k)
- ]
- for k in easy_install_ep:
- del console[k]
-
- # Generate the console and GUI entry points specified in the wheel
- if len(console) > 0:
- generated_console_scripts = maker.make_multiple(
- ['%s = %s' % kv for kv in console.items()]
- )
- generated.extend(generated_console_scripts)
-
- if warn_script_location:
- msg = message_about_scripts_not_on_PATH(generated_console_scripts)
- if msg is not None:
- logger.warning(msg)
-
- if len(gui) > 0:
- generated.extend(
- maker.make_multiple(
- ['%s = %s' % kv for kv in gui.items()],
- {'gui': True}
- )
- )
-
- # Record pip as the installer
- installer = os.path.join(info_dir[0], 'INSTALLER')
- temp_installer = os.path.join(info_dir[0], 'INSTALLER.pip')
- with open(temp_installer, 'wb') as installer_file:
- installer_file.write(b'pip\n')
- shutil.move(temp_installer, installer)
- generated.append(installer)
-
- # Record details of all files installed
- record = os.path.join(info_dir[0], 'RECORD')
- temp_record = os.path.join(info_dir[0], 'RECORD.pip')
- with open_for_csv(record, 'r') as record_in:
- with open_for_csv(temp_record, 'w+') as record_out:
- reader = csv.reader(record_in)
- outrows = get_csv_rows_for_installed(
- reader, installed=installed, changed=changed,
- generated=generated, lib_dir=lib_dir,
- )
- writer = csv.writer(record_out)
- # Sort to simplify testing.
- for row in sorted_outrows(outrows):
- writer.writerow(row)
- shutil.move(temp_record, record)
-
-
-def wheel_version(source_dir):
- # type: (Optional[str]) -> Optional[Tuple[int, ...]]
- """
- Return the Wheel-Version of an extracted wheel, if possible.
-
- Otherwise, return None if we couldn't parse / extract it.
- """
- try:
- dist = [d for d in pkg_resources.find_on_path(None, source_dir)][0]
-
- wheel_data = dist.get_metadata('WHEEL')
- wheel_data = Parser().parsestr(wheel_data)
-
- version = wheel_data['Wheel-Version'].strip()
- version = tuple(map(int, version.split('.')))
- return version
- except Exception:
- return None
-
-
-def check_compatibility(version, name):
- # type: (Optional[Tuple[int, ...]], str) -> None
- """
- Raises errors or warns if called with an incompatible Wheel-Version.
-
- Pip should refuse to install a Wheel-Version that's a major series
- ahead of what it's compatible with (e.g 2.0 > 1.1); and warn when
- installing a version only minor version ahead (e.g 1.2 > 1.1).
-
- version: a 2-tuple representing a Wheel-Version (Major, Minor)
- name: name of wheel or package to raise exception about
-
- :raises UnsupportedWheel: when an incompatible Wheel-Version is given
- """
- if not version:
- raise UnsupportedWheel(
- "%s is in an unsupported or invalid wheel" % name
- )
- if version[0] > VERSION_COMPATIBLE[0]:
- raise UnsupportedWheel(
- "%s's Wheel-Version (%s) is not compatible with this version "
- "of pip" % (name, '.'.join(map(str, version)))
- )
- elif version > VERSION_COMPATIBLE:
- logger.warning(
- 'Installing from a newer Wheel-Version (%s)',
- '.'.join(map(str, version)),
- )
-
-
-def format_tag(file_tag):
- # type: (Tuple[str, ...]) -> str
- """
- Format three tags in the form "--".
-
- :param file_tag: A 3-tuple of tags (python_tag, abi_tag, platform_tag).
- """
- return '-'.join(file_tag)
-
-
-class Wheel(object):
- """A wheel file"""
-
- # TODO: Maybe move the class into the models sub-package
- # TODO: Maybe move the install code into this class
-
- wheel_file_re = re.compile(
- r"""^(?P(?P.+?)-(?P.*?))
- ((-(?P\d[^-]*?))?-(?P.+?)-(?P.+?)-(?P.+?)
- \.whl|\.dist-info)$""",
- re.VERBOSE
- )
-
- def __init__(self, filename):
- # type: (str) -> None
- """
- :raises InvalidWheelFilename: when the filename is invalid for a wheel
- """
- wheel_info = self.wheel_file_re.match(filename)
- if not wheel_info:
- raise InvalidWheelFilename(
- "%s is not a valid wheel filename." % filename
- )
- self.filename = filename
- self.name = wheel_info.group('name').replace('_', '-')
- # we'll assume "_" means "-" due to wheel naming scheme
- # (https://github.com/pypa/pip/issues/1150)
- self.version = wheel_info.group('ver').replace('_', '-')
- self.build_tag = wheel_info.group('build')
- self.pyversions = wheel_info.group('pyver').split('.')
- self.abis = wheel_info.group('abi').split('.')
- self.plats = wheel_info.group('plat').split('.')
-
- # All the tag combinations from this file
- self.file_tags = {
- (x, y, z) for x in self.pyversions
- for y in self.abis for z in self.plats
- }
-
- def get_formatted_file_tags(self):
- # type: () -> List[str]
- """
- Return the wheel's tags as a sorted list of strings.
- """
- return sorted(format_tag(tag) for tag in self.file_tags)
-
- def support_index_min(self, tags=None):
- # type: (Optional[List[Pep425Tag]]) -> Optional[int]
- """
- Return the lowest index that one of the wheel's file_tag combinations
- achieves in the supported_tags list e.g. if there are 8 supported tags,
- and one of the file tags is first in the list, then return 0. Returns
- None is the wheel is not supported.
- """
- if tags is None: # for mock
- tags = pep425tags.get_supported()
- indexes = [tags.index(c) for c in self.file_tags if c in tags]
- return min(indexes) if indexes else None
-
- def supported(self, tags=None):
- # type: (Optional[List[Pep425Tag]]) -> bool
- """Is this wheel supported on this system?"""
- if tags is None: # for mock
- tags = pep425tags.get_supported()
- return bool(set(tags).intersection(self.file_tags))
-
-
-def _contains_egg_info(
- s, _egg_info_re=re.compile(r'([a-z0-9_.]+)-([a-z0-9_.!+-]+)', re.I)):
- """Determine whether the string looks like an egg_info.
-
- :param s: The string to parse. E.g. foo-2.1
- """
- return bool(_egg_info_re.search(s))
-
-
-def should_use_ephemeral_cache(
- req, # type: InstallRequirement
- format_control, # type: FormatControl
- autobuilding, # type: bool
- cache_available # type: bool
-):
- # type: (...) -> Optional[bool]
- """
- Return whether to build an InstallRequirement object using the
- ephemeral cache.
-
- :param cache_available: whether a cache directory is available for the
- autobuilding=True case.
-
- :return: True or False to build the requirement with ephem_cache=True
- or False, respectively; or None not to build the requirement.
- """
- if req.constraint:
- return None
- if req.is_wheel:
- if not autobuilding:
- logger.info(
- 'Skipping %s, due to already being wheel.', req.name,
- )
- return None
- if not autobuilding:
- return False
-
- if req.editable or not req.source_dir:
- return None
-
- if "binary" not in format_control.get_allowed_formats(
- canonicalize_name(req.name)):
- logger.info(
- "Skipping bdist_wheel for %s, due to binaries "
- "being disabled for it.", req.name,
- )
- return None
-
- if req.link and not req.link.is_artifact:
- # VCS checkout. Build wheel just for this run.
- return True
-
- link = req.link
- base, ext = link.splitext()
- if cache_available and _contains_egg_info(base):
- return False
-
- # Otherwise, build the wheel just for this run using the ephemeral
- # cache since we are either in the case of e.g. a local directory, or
- # no cache directory is available to use.
- return True
-
-
-def format_command_result(
- command_args, # type: List[str]
- command_output, # type: str
-):
- # type: (...) -> str
- """
- Format command information for logging.
- """
- command_desc = format_command_args(command_args)
- text = 'Command arguments: {}\n'.format(command_desc)
-
- if not command_output:
- text += 'Command output: None'
- elif logger.getEffectiveLevel() > logging.DEBUG:
- text += 'Command output: [use --verbose to show]'
- else:
- if not command_output.endswith('\n'):
- command_output += '\n'
- text += 'Command output:\n{}{}'.format(command_output, LOG_DIVIDER)
-
- return text
-
-
-def get_legacy_build_wheel_path(
- names, # type: List[str]
- temp_dir, # type: str
- req, # type: InstallRequirement
- command_args, # type: List[str]
- command_output, # type: str
-):
- # type: (...) -> Optional[str]
- """
- Return the path to the wheel in the temporary build directory.
- """
- # Sort for determinism.
- names = sorted(names)
- if not names:
- msg = (
- 'Legacy build of wheel for {!r} created no files.\n'
- ).format(req.name)
- msg += format_command_result(command_args, command_output)
- logger.warning(msg)
- return None
-
- if len(names) > 1:
- msg = (
- 'Legacy build of wheel for {!r} created more than one file.\n'
- 'Filenames (choosing first): {}\n'
- ).format(req.name, names)
- msg += format_command_result(command_args, command_output)
- logger.warning(msg)
-
- return os.path.join(temp_dir, names[0])
-
-
-class WheelBuilder(object):
- """Build wheels from a RequirementSet."""
-
- def __init__(
- self,
- finder, # type: PackageFinder
- preparer, # type: RequirementPreparer
- wheel_cache, # type: WheelCache
- build_options=None, # type: Optional[List[str]]
- global_options=None, # type: Optional[List[str]]
- no_clean=False # type: bool
- ):
- # type: (...) -> None
- self.finder = finder
- self.preparer = preparer
- self.wheel_cache = wheel_cache
-
- self._wheel_dir = preparer.wheel_download_dir
-
- self.build_options = build_options or []
- self.global_options = global_options or []
- self.no_clean = no_clean
-
- def _build_one(self, req, output_dir, python_tag=None):
- """Build one wheel.
-
- :return: The filename of the built wheel, or None if the build failed.
- """
- # Install build deps into temporary directory (PEP 518)
- with req.build_env:
- return self._build_one_inside_env(req, output_dir,
- python_tag=python_tag)
-
- def _build_one_inside_env(self, req, output_dir, python_tag=None):
- with TempDirectory(kind="wheel") as temp_dir:
- if req.use_pep517:
- builder = self._build_one_pep517
- else:
- builder = self._build_one_legacy
- wheel_path = builder(req, temp_dir.path, python_tag=python_tag)
- if wheel_path is not None:
- wheel_name = os.path.basename(wheel_path)
- dest_path = os.path.join(output_dir, wheel_name)
- try:
- wheel_hash, length = hash_file(wheel_path)
- shutil.move(wheel_path, dest_path)
- logger.info('Created wheel for %s: '
- 'filename=%s size=%d sha256=%s',
- req.name, wheel_name, length,
- wheel_hash.hexdigest())
- logger.info('Stored in directory: %s', output_dir)
- return dest_path
- except Exception:
- pass
- # Ignore return, we can't do anything else useful.
- self._clean_one(req)
- return None
-
- def _base_setup_args(self, req):
- # NOTE: Eventually, we'd want to also -S to the flags here, when we're
- # isolating. Currently, it breaks Python in virtualenvs, because it
- # relies on site.py to find parts of the standard library outside the
- # virtualenv.
- base_cmd = make_setuptools_shim_args(req.setup_py_path,
- unbuffered_output=True)
- return base_cmd + list(self.global_options)
-
- def _build_one_pep517(self, req, tempd, python_tag=None):
- """Build one InstallRequirement using the PEP 517 build process.
-
- Returns path to wheel if successfully built. Otherwise, returns None.
- """
- assert req.metadata_directory is not None
- if self.build_options:
- # PEP 517 does not support --build-options
- logger.error('Cannot build wheel for %s using PEP 517 when '
- '--build-options is present' % (req.name,))
- return None
- try:
- req.spin_message = 'Building wheel for %s (PEP 517)' % (req.name,)
- logger.debug('Destination directory: %s', tempd)
- wheel_name = req.pep517_backend.build_wheel(
- tempd,
- metadata_directory=req.metadata_directory
- )
- if python_tag:
- # General PEP 517 backends don't necessarily support
- # a "--python-tag" option, so we rename the wheel
- # file directly.
- new_name = replace_python_tag(wheel_name, python_tag)
- os.rename(
- os.path.join(tempd, wheel_name),
- os.path.join(tempd, new_name)
- )
- # Reassign to simplify the return at the end of function
- wheel_name = new_name
- except Exception:
- logger.error('Failed building wheel for %s', req.name)
- return None
- return os.path.join(tempd, wheel_name)
-
- def _build_one_legacy(self, req, tempd, python_tag=None):
- """Build one InstallRequirement using the "legacy" build process.
-
- Returns path to wheel if successfully built. Otherwise, returns None.
- """
- base_args = self._base_setup_args(req)
-
- spin_message = 'Building wheel for %s (setup.py)' % (req.name,)
- with open_spinner(spin_message) as spinner:
- logger.debug('Destination directory: %s', tempd)
- wheel_args = base_args + ['bdist_wheel', '-d', tempd] \
- + self.build_options
-
- if python_tag is not None:
- wheel_args += ["--python-tag", python_tag]
-
- try:
- output = call_subprocess(wheel_args, cwd=req.setup_py_dir,
- spinner=spinner)
- except Exception:
- spinner.finish("error")
- logger.error('Failed building wheel for %s', req.name)
- return None
- names = os.listdir(tempd)
- wheel_path = get_legacy_build_wheel_path(
- names=names,
- temp_dir=tempd,
- req=req,
- command_args=wheel_args,
- command_output=output,
- )
- return wheel_path
-
- def _clean_one(self, req):
- base_args = self._base_setup_args(req)
-
- logger.info('Running setup.py clean for %s', req.name)
- clean_args = base_args + ['clean', '--all']
- try:
- call_subprocess(clean_args, cwd=req.source_dir)
- return True
- except Exception:
- logger.error('Failed cleaning build dir for %s', req.name)
- return False
-
- def build(
- self,
- requirements, # type: Iterable[InstallRequirement]
- session, # type: PipSession
- autobuilding=False # type: bool
- ):
- # type: (...) -> List[InstallRequirement]
- """Build wheels.
-
- :param unpack: If True, replace the sdist we built from with the
- newly built wheel, in preparation for installation.
- :return: True if all the wheels built correctly.
- """
- buildset = []
- format_control = self.finder.format_control
- # Whether a cache directory is available for autobuilding=True.
- cache_available = bool(self._wheel_dir or self.wheel_cache.cache_dir)
-
- for req in requirements:
- ephem_cache = should_use_ephemeral_cache(
- req, format_control=format_control, autobuilding=autobuilding,
- cache_available=cache_available,
- )
- if ephem_cache is None:
- continue
-
- buildset.append((req, ephem_cache))
-
- if not buildset:
- return []
-
- # Is any wheel build not using the ephemeral cache?
- if any(not ephem_cache for _, ephem_cache in buildset):
- have_directory_for_build = self._wheel_dir or (
- autobuilding and self.wheel_cache.cache_dir
- )
- assert have_directory_for_build
-
- # TODO by @pradyunsg
- # Should break up this method into 2 separate methods.
-
- # Build the wheels.
- logger.info(
- 'Building wheels for collected packages: %s',
- ', '.join([req.name for (req, _) in buildset]),
- )
- _cache = self.wheel_cache # shorter name
- with indent_log():
- build_success, build_failure = [], []
- for req, ephem in buildset:
- python_tag = None
- if autobuilding:
- python_tag = pep425tags.implementation_tag
- if ephem:
- output_dir = _cache.get_ephem_path_for_link(req.link)
- else:
- output_dir = _cache.get_path_for_link(req.link)
- try:
- ensure_dir(output_dir)
- except OSError as e:
- logger.warning("Building wheel for %s failed: %s",
- req.name, e)
- build_failure.append(req)
- continue
- else:
- output_dir = self._wheel_dir
- wheel_file = self._build_one(
- req, output_dir,
- python_tag=python_tag,
- )
- if wheel_file:
- build_success.append(req)
- if autobuilding:
- # XXX: This is mildly duplicative with prepare_files,
- # but not close enough to pull out to a single common
- # method.
- # The code below assumes temporary source dirs -
- # prevent it doing bad things.
- if req.source_dir and not os.path.exists(os.path.join(
- req.source_dir, PIP_DELETE_MARKER_FILENAME)):
- raise AssertionError(
- "bad source dir - missing marker")
- # Delete the source we built the wheel from
- req.remove_temporary_source()
- # set the build directory again - name is known from
- # the work prepare_files did.
- req.source_dir = req.build_location(
- self.preparer.build_dir
- )
- # Update the link for this.
- req.link = Link(path_to_url(wheel_file))
- assert req.link.is_wheel
- # extract the wheel into the dir
- unpack_url(
- req.link, req.source_dir, None, False,
- session=session,
- )
- else:
- build_failure.append(req)
-
- # notify success/failure
- if build_success:
- logger.info(
- 'Successfully built %s',
- ' '.join([req.name for req in build_success]),
- )
- if build_failure:
- logger.info(
- 'Failed to build %s',
- ' '.join([req.name for req in build_failure]),
- )
- # Return a list of requirements that failed to build
- return build_failure
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/__init__.py
index c1d9508..581db54 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/__init__.py
@@ -32,15 +32,11 @@ def vendored(modulename):
try:
__import__(modulename, globals(), locals(), level=0)
except ImportError:
- # We can just silently allow import failures to pass here. If we
- # got to this point it means that ``import pip._vendor.whatever``
- # failed and so did ``import whatever``. Since we're importing this
- # upfront in an attempt to alias imports, not erroring here will
- # just mean we get a regular import error whenever pip *actually*
- # tries to import one of these modules to use it, which actually
- # gives us a better error message than we would have otherwise
- # gotten.
- pass
+ # This error used to be silenced in earlier variants of this file, to instead
+ # raise the error when pip actually tries to use the missing module.
+ # Based on inputs in #5354, this was changed to explicitly raise the error.
+ # Re-raising the exception without modifying it is an intentional choice.
+ raise
else:
sys.modules[vendored_name] = sys.modules[modulename]
base, head = vendored_name.rsplit(".", 1)
@@ -58,12 +54,14 @@ if DEBUNDLED:
sys.path[:] = glob.glob(os.path.join(WHEEL_DIR, "*.whl")) + sys.path
# Actually alias all of our vendored dependencies.
+ vendored("appdirs")
vendored("cachecontrol")
+ vendored("certifi")
vendored("colorama")
+ vendored("contextlib2")
vendored("distlib")
vendored("distro")
vendored("html5lib")
- vendored("lockfile")
vendored("six")
vendored("six.moves")
vendored("six.moves.urllib")
@@ -74,7 +72,6 @@ if DEBUNDLED:
vendored("pep517")
vendored("pkg_resources")
vendored("progress")
- vendored("pytoml")
vendored("retrying")
vendored("requests")
vendored("requests.exceptions")
@@ -106,4 +103,8 @@ if DEBUNDLED:
vendored("requests.packages.urllib3.util.ssl_")
vendored("requests.packages.urllib3.util.timeout")
vendored("requests.packages.urllib3.util.url")
+ vendored("resolvelib")
+ vendored("toml")
+ vendored("toml.encoder")
+ vendored("toml.decoder")
vendored("urllib3")
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/__init__.cpython-38.pyc
index 4c1bee4..e637411 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/appdirs.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/appdirs.cpython-38.pyc
index fde8231..00ddaff 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/appdirs.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/appdirs.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/distro.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/distro.cpython-38.pyc
index 8313b27..cc7402b 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/distro.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/distro.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/ipaddress.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/ipaddress.cpython-38.pyc
index dce6895..6ceac1d 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/ipaddress.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/ipaddress.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/pyparsing.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/pyparsing.cpython-38.pyc
index 2f464de..3a680d5 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/pyparsing.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/pyparsing.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/retrying.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/retrying.cpython-38.pyc
index 83cfa7b..8795633 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/retrying.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/retrying.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/six.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/six.cpython-38.pyc
index b4424e1..4b3d4f0 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/six.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/__pycache__/six.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/appdirs.py b/venv/lib/python3.8/site-packages/pip/_vendor/appdirs.py
index 2bd3911..33a3b77 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/appdirs.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/appdirs.py
@@ -13,8 +13,8 @@ See for details and usage.
# - Mac OS X: http://developer.apple.com/documentation/MacOSX/Conceptual/BPFileSystem/index.html
# - XDG spec for Un*x: http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html
-__version_info__ = (1, 4, 3)
-__version__ = '.'.join(map(str, __version_info__))
+__version__ = "1.4.4"
+__version_info__ = tuple(int(segment) for segment in __version__.split("."))
import sys
@@ -37,6 +37,10 @@ if sys.platform.startswith('java'):
# are actually checked for and the rest of the module expects
# *sys.platform* style strings.
system = 'linux2'
+elif sys.platform == 'cli' and os.name == 'nt':
+ # Detect Windows in IronPython to match pip._internal.utils.compat.WINDOWS
+ # Discussion:
+ system = 'win32'
else:
system = sys.platform
@@ -64,7 +68,7 @@ def user_data_dir(appname=None, appauthor=None, version=None, roaming=False):
for a discussion of issues.
Typical user data directories are:
- Mac OS X: ~/Library/Application Support/
+ Mac OS X: ~/Library/Application Support/ # or ~/.config/, if the other does not exist
Unix: ~/.local/share/ # or in $XDG_DATA_HOME, if defined
Win XP (not roaming): C:\Documents and Settings\\Application Data\\
Win XP (roaming): C:\Documents and Settings\\Local Settings\Application Data\\
@@ -150,7 +154,7 @@ def site_data_dir(appname=None, appauthor=None, version=None, multipath=False):
if appname:
if version:
appname = os.path.join(appname, version)
- pathlist = [os.sep.join([x, appname]) for x in pathlist]
+ pathlist = [os.path.join(x, appname) for x in pathlist]
if multipath:
path = os.pathsep.join(pathlist)
@@ -203,6 +207,8 @@ def user_config_dir(appname=None, appauthor=None, version=None, roaming=False):
return path
+# for the discussion regarding site_config_dir locations
+# see
def site_config_dir(appname=None, appauthor=None, version=None, multipath=False):
r"""Return full path to the user-shared data dir for this application.
@@ -238,14 +244,15 @@ def site_config_dir(appname=None, appauthor=None, version=None, multipath=False)
if appname and version:
path = os.path.join(path, version)
else:
- # XDG default for $XDG_CONFIG_DIRS
+ # XDG default for $XDG_CONFIG_DIRS (missing or empty)
+ # see
# only first, if multipath is False
- path = os.getenv('XDG_CONFIG_DIRS', '/etc/xdg')
- pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep)]
+ path = os.getenv('XDG_CONFIG_DIRS') or '/etc/xdg'
+ pathlist = [os.path.expanduser(x.rstrip(os.sep)) for x in path.split(os.pathsep) if x]
if appname:
if version:
appname = os.path.join(appname, version)
- pathlist = [os.sep.join([x, appname]) for x in pathlist]
+ pathlist = [os.path.join(x, appname) for x in pathlist]
if multipath:
path = os.pathsep.join(pathlist)
@@ -291,6 +298,10 @@ def user_cache_dir(appname=None, appauthor=None, version=None, opinion=True):
if appauthor is None:
appauthor = appname
path = os.path.normpath(_get_win_folder("CSIDL_LOCAL_APPDATA"))
+ # When using Python 2, return paths as bytes on Windows like we do on
+ # other operating systems. See helper function docs for more details.
+ if not PY3 and isinstance(path, unicode):
+ path = _win_path_to_bytes(path)
if appname:
if appauthor is not False:
path = os.path.join(path, appauthor, appname)
@@ -567,6 +578,24 @@ if system == "win32":
_get_win_folder = _get_win_folder_from_registry
+def _win_path_to_bytes(path):
+ """Encode Windows paths to bytes. Only used on Python 2.
+
+ Motivation is to be consistent with other operating systems where paths
+ are also returned as bytes. This avoids problems mixing bytes and Unicode
+ elsewhere in the codebase. For more details and discussion see
+ .
+
+ If encoding using ASCII and MBCS fails, return the original Unicode path.
+ """
+ for encoding in ('ASCII', 'MBCS'):
+ try:
+ return path.encode(encoding)
+ except (UnicodeEncodeError, LookupError):
+ pass
+ return path
+
+
#---- self test code
if __name__ == "__main__":
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__init__.py
index 8fdee66..a1bbbbe 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__init__.py
@@ -4,7 +4,7 @@ Make it easy to import from cachecontrol without long namespaces.
"""
__author__ = "Eric Larson"
__email__ = "eric@ionrock.org"
-__version__ = "0.12.5"
+__version__ = "0.12.6"
from .wrapper import CacheControl
from .adapter import CacheControlAdapter
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-38.pyc
index a2198cd..c1e4675 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-38.pyc
index 9a8ae56..c42b9d4 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-38.pyc
index a2aa8c5..1f58384 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-38.pyc
index 6d2055c..6c4b385 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/compat.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/compat.cpython-38.pyc
index 0a7d40c..6eebb9e 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/compat.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/compat.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-38.pyc
index 9590f54..f6d7703 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-38.pyc
index 0d9d3c4..d0d0979 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-38.pyc
index 0ff4dd1..f8f230b 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-38.pyc
index f66bc59..deadc4e 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-38.pyc
index a04a09c..41c64ba 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/adapter.py b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/adapter.py
index 780eb28..815650e 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/adapter.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/adapter.py
@@ -24,7 +24,7 @@ class CacheControlAdapter(HTTPAdapter):
**kw
):
super(CacheControlAdapter, self).__init__(*args, **kw)
- self.cache = cache or DictCache()
+ self.cache = DictCache() if cache is None else cache
self.heuristic = heuristic
self.cacheable_methods = cacheable_methods or ("GET",)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-38.pyc
index 11f0627..fd9a088 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-38.pyc
index de16a74..3e28834 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-38.pyc
index aaba3ec..e564a4f 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py
index 1ba0080..607b945 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py
@@ -69,8 +69,8 @@ class FileCache(BaseCache):
raise ValueError("Cannot use use_dir_lock and lock_class together")
try:
- from pip._vendor.lockfile import LockFile
- from pip._vendor.lockfile.mkdirlockfile import MkdirLockFile
+ from lockfile import LockFile
+ from lockfile.mkdirlockfile import MkdirLockFile
except ImportError:
notice = dedent(
"""
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/controller.py b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/controller.py
index 1b2b943..dafe55c 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/controller.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/controller.py
@@ -34,7 +34,7 @@ class CacheController(object):
def __init__(
self, cache=None, cache_etags=True, serializer=None, status_codes=None
):
- self.cache = cache or DictCache()
+ self.cache = DictCache() if cache is None else cache
self.cache_etags = cache_etags
self.serializer = serializer or Serializer()
self.cacheable_status_codes = status_codes or (200, 203, 300, 301)
@@ -293,6 +293,15 @@ class CacheController(object):
if no_store:
return
+ # https://tools.ietf.org/html/rfc7234#section-4.1:
+ # A Vary header field-value of "*" always fails to match.
+ # Storing such a response leads to a deserialization warning
+ # during cache lookup and is not allowed to ever be served,
+ # so storing it can be avoided.
+ if "*" in response_headers.get("vary", ""):
+ logger.debug('Response header has "Vary: *"')
+ return
+
# If we've been given an etag, then keep the response
if self.cache_etags and "etag" in response_headers:
logger.debug("Caching due to etag")
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/serialize.py b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/serialize.py
index ec43ff2..3b6ec2d 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/serialize.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/serialize.py
@@ -107,6 +107,8 @@ class Serializer(object):
"""
# Special case the '*' Vary value as it means we cannot actually
# determine if the cached response is suitable for this request.
+ # This case is also handled in the controller code when creating
+ # a cache entry, but is left here for backwards compatibility.
if "*" in cached.get("vary", {}):
return
@@ -179,7 +181,7 @@ class Serializer(object):
def _loads_v4(self, request, data):
try:
- cached = msgpack.loads(data, encoding="utf-8")
+ cached = msgpack.loads(data, raw=False)
except ValueError:
return
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/wrapper.py b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/wrapper.py
index 265bfc8..d8e6fc6 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/wrapper.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/cachecontrol/wrapper.py
@@ -13,7 +13,7 @@ def CacheControl(
cacheable_methods=None,
):
- cache = cache or DictCache()
+ cache = DictCache() if cache is None else cache
adapter_class = adapter_class or CacheControlAdapter
adapter = adapter_class(
cache,
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__init__.py
index 8ccb14e..5d52a62 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__init__.py
@@ -1,3 +1,3 @@
-from .core import where
+from .core import contents, where
-__version__ = "2019.06.16"
+__version__ = "2020.06.20"
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__main__.py b/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__main__.py
index ae2aff5..0037634 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__main__.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__main__.py
@@ -1,2 +1,12 @@
-from pip._vendor.certifi import where
-print(where())
+import argparse
+
+from pip._vendor.certifi import contents, where
+
+parser = argparse.ArgumentParser()
+parser.add_argument("-c", "--contents", action="store_true")
+args = parser.parse_args()
+
+if args.contents:
+ print(contents())
+else:
+ print(where())
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-38.pyc
index 7b8bf12..90625c8 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-38.pyc
index f630e9e..1ad86ff 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-38.pyc
index aea1b4e..0815dc0 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/certifi/cacert.pem b/venv/lib/python3.8/site-packages/pip/_vendor/certifi/cacert.pem
index 9ca290f..0fd855f 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/certifi/cacert.pem
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/certifi/cacert.pem
@@ -58,38 +58,6 @@ AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
-----END CERTIFICATE-----
-# Issuer: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
-# Subject: CN=VeriSign Class 3 Public Primary Certification Authority - G3 O=VeriSign, Inc. OU=VeriSign Trust Network/(c) 1999 VeriSign, Inc. - For authorized use only
-# Label: "Verisign Class 3 Public Primary Certification Authority - G3"
-# Serial: 206684696279472310254277870180966723415
-# MD5 Fingerprint: cd:68:b6:a7:c7:c4:ce:75:e0:1d:4f:57:44:61:92:09
-# SHA1 Fingerprint: 13:2d:0d:45:53:4b:69:97:cd:b2:d5:c3:39:e2:55:76:60:9b:5c:c6
-# SHA256 Fingerprint: eb:04:cf:5e:b1:f3:9a:fa:76:2f:2b:b1:20:f2:96:cb:a5:20:c1:b9:7d:b1:58:95:65:b8:1c:b9:a1:7b:72:44
------BEGIN CERTIFICATE-----
-MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
-CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
-cmlTaWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWdu
-LCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlT
-aWduIENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3Jp
-dHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQswCQYD
-VQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlT
-aWduIFRydXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJ
-bmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWdu
-IENsYXNzIDMgUHVibGljIFByaW1hcnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkg
-LSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMu6nFL8eB8aHm8b
-N3O9+MlrlBIwT/A2R/XQkQr1F8ilYcEWQE37imGQ5XYgwREGfassbqb1EUGO+i2t
-KmFZpGcmTNDovFJbcCAEWNF6yaRpvIMXZK0Fi7zQWM6NjPXr8EJJC52XJ2cybuGu
-kxUccLwgTS8Y3pKI6GyFVxEa6X7jJhFUokWWVYPKMIno3Nij7SqAP395ZVc+FSBm
-CC+Vk7+qRy+oRpfwEuL+wgorUeZ25rdGt+INpsyow0xZVYnm6FNcHOqd8GIWC6fJ
-Xwzw3sJ2zq/3avL6QaaiMxTJ5Xpj055iN9WFZZ4O5lMkdBteHRJTW8cs54NJOxWu
-imi5V5cCAwEAATANBgkqhkiG9w0BAQUFAAOCAQEAERSWwauSCPc/L8my/uRan2Te
-2yFPhpk0djZX3dAVL8WtfxUfN2JzPtTnX84XA9s1+ivbrmAJXx5fj267Cz3qWhMe
-DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
-/Y4wjylGsB49Ndo4YhYYSq3mtlFs3q9i6wHQHiT+eo8SGhJouPtmmRQURVyu565p
-F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt
-TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
------END CERTIFICATE-----
-
# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
# Label: "Entrust.net Premium 2048 Secure Server CA"
@@ -152,39 +120,6 @@ ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
-----END CERTIFICATE-----
-# Issuer: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network
-# Subject: CN=AddTrust External CA Root O=AddTrust AB OU=AddTrust External TTP Network
-# Label: "AddTrust External Root"
-# Serial: 1
-# MD5 Fingerprint: 1d:35:54:04:85:78:b0:3f:42:42:4d:bf:20:73:0a:3f
-# SHA1 Fingerprint: 02:fa:f3:e2:91:43:54:68:60:78:57:69:4d:f5:e4:5b:68:85:18:68
-# SHA256 Fingerprint: 68:7f:a4:51:38:22:78:ff:f0:c8:b1:1f:8d:43:d5:76:67:1c:6e:b2:bc:ea:b4:13:fb:83:d9:65:d0:6d:2f:f2
------BEGIN CERTIFICATE-----
-MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
-MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
-IFRUUCBOZXR3b3JrMSIwIAYDVQQDExlBZGRUcnVzdCBFeHRlcm5hbCBDQSBSb290
-MB4XDTAwMDUzMDEwNDgzOFoXDTIwMDUzMDEwNDgzOFowbzELMAkGA1UEBhMCU0Ux
-FDASBgNVBAoTC0FkZFRydXN0IEFCMSYwJAYDVQQLEx1BZGRUcnVzdCBFeHRlcm5h
-bCBUVFAgTmV0d29yazEiMCAGA1UEAxMZQWRkVHJ1c3QgRXh0ZXJuYWwgQ0EgUm9v
-dDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALf3GjPm8gAELTngTlvt
-H7xsD821+iO2zt6bETOXpClMfZOfvUq8k+0DGuOPz+VtUFrWlymUWoCwSXrbLpX9
-uMq/NzgtHj6RQa1wVsfwTz/oMp50ysiQVOnGXw94nZpAPA6sYapeFI+eh6FqUNzX
-mk6vBbOmcZSccbNQYArHE504B4YCqOmoaSYYkKtMsE8jqzpPhNjfzp/haW+710LX
-a0Tkx63ubUFfclpxCDezeWWkWaCUN/cALw3CknLa0Dhy2xSoRcRdKn23tNbE7qzN
-E0S3ySvdQwAl+mG5aWpYIxG3pzOPVnVZ9c0p10a3CitlttNCbxWyuHv77+ldU9U0
-WicCAwEAAaOB3DCB2TAdBgNVHQ4EFgQUrb2YejS0Jvf6xCZU7wO94CTLVBowCwYD
-VR0PBAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wgZkGA1UdIwSBkTCBjoAUrb2YejS0
-Jvf6xCZU7wO94CTLVBqhc6RxMG8xCzAJBgNVBAYTAlNFMRQwEgYDVQQKEwtBZGRU
-cnVzdCBBQjEmMCQGA1UECxMdQWRkVHJ1c3QgRXh0ZXJuYWwgVFRQIE5ldHdvcmsx
-IjAgBgNVBAMTGUFkZFRydXN0IEV4dGVybmFsIENBIFJvb3SCAQEwDQYJKoZIhvcN
-AQEFBQADggEBALCb4IUlwtYj4g+WBpKdQZic2YR5gdkeWxQHIzZlj7DYd7usQWxH
-YINRsPkyPef89iYTx4AWpb9a/IfPeHmJIZriTAcKhjW88t5RxNKWt9x+Tu5w/Rw5
-6wwCURQtjr0W4MHfRnXnJK3s9EK0hZNwEGe6nQY1ShjTK3rMUUKhemPR5ruhxSvC
-Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
-c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
-mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
------END CERTIFICATE-----
-
# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc.
# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc.
# Label: "Entrust Root Certification Authority"
@@ -771,36 +706,6 @@ vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
+OkuE6N36B9K
-----END CERTIFICATE-----
-# Issuer: CN=Class 2 Primary CA O=Certplus
-# Subject: CN=Class 2 Primary CA O=Certplus
-# Label: "Certplus Class 2 Primary CA"
-# Serial: 177770208045934040241468760488327595043
-# MD5 Fingerprint: 88:2c:8c:52:b8:a2:3c:f3:f7:bb:03:ea:ae:ac:42:0b
-# SHA1 Fingerprint: 74:20:74:41:72:9c:dd:92:ec:79:31:d8:23:10:8d:c2:81:92:e2:bb
-# SHA256 Fingerprint: 0f:99:3c:8a:ef:97:ba:af:56:87:14:0e:d5:9a:d1:82:1b:b4:af:ac:f0:aa:9a:58:b5:d5:7a:33:8a:3a:fb:cb
------BEGIN CERTIFICATE-----
-MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw
-PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz
-cyAyIFByaW1hcnkgQ0EwHhcNOTkwNzA3MTcwNTAwWhcNMTkwNzA2MjM1OTU5WjA9
-MQswCQYDVQQGEwJGUjERMA8GA1UEChMIQ2VydHBsdXMxGzAZBgNVBAMTEkNsYXNz
-IDIgUHJpbWFyeSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANxQ
-ltAS+DXSCHh6tlJw/W/uz7kRy1134ezpfgSN1sxvc0NXYKwzCkTsA18cgCSR5aiR
-VhKC9+Ar9NuuYS6JEI1rbLqzAr3VNsVINyPi8Fo3UjMXEuLRYE2+L0ER4/YXJQyL
-kcAbmXuZVg2v7tK8R1fjeUl7NIknJITesezpWE7+Tt9avkGtrAjFGA7v0lPubNCd
-EgETjdyAYveVqUSISnFOYFWe2yMZeVYHDD9jC1yw4r5+FfyUM1hBOHTE4Y+L3yas
-H7WLO7dDWWuwJKZtkIvEcupdM5i3y95ee++U8Rs+yskhwcWYAqqi9lt3m/V+llU0
-HGdpwPFC40es/CgcZlUCAwEAAaOBjDCBiTAPBgNVHRMECDAGAQH/AgEKMAsGA1Ud
-DwQEAwIBBjAdBgNVHQ4EFgQU43Mt38sOKAze3bOkynm4jrvoMIkwEQYJYIZIAYb4
-QgEBBAQDAgEGMDcGA1UdHwQwMC4wLKAqoCiGJmh0dHA6Ly93d3cuY2VydHBsdXMu
-Y29tL0NSTC9jbGFzczIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQCnVM+IRBnL39R/
-AN9WM2K191EBkOvDP9GIROkkXe/nFL0gt5o8AP5tn9uQ3Nf0YtaLcF3n5QRIqWh8
-yfFC82x/xXp8HVGIutIKPidd3i1RTtMTZGnkLuPT55sJmabglZvOGtd/vjzOUrMR
-FcEPF80Du5wlFbqidon8BvEY0JNLDnyCt6X09l/+7UCmnYR0ObncHoUW2ikbhiMA
-ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB
-kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7
-l7+ijrRU
------END CERTIFICATE-----
-
# Issuer: CN=DST Root CA X3 O=Digital Signature Trust Co.
# Subject: CN=DST Root CA X3 O=Digital Signature Trust Co.
# Label: "DST Root CA X3"
@@ -1219,36 +1124,6 @@ t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw
WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
-----END CERTIFICATE-----
-# Issuer: CN=Deutsche Telekom Root CA 2 O=Deutsche Telekom AG OU=T-TeleSec Trust Center
-# Subject: CN=Deutsche Telekom Root CA 2 O=Deutsche Telekom AG OU=T-TeleSec Trust Center
-# Label: "Deutsche Telekom Root CA 2"
-# Serial: 38
-# MD5 Fingerprint: 74:01:4a:91:b1:08:c4:58:ce:47:cd:f0:dd:11:53:08
-# SHA1 Fingerprint: 85:a4:08:c0:9c:19:3e:5d:51:58:7d:cd:d6:13:30:fd:8c:de:37:bf
-# SHA256 Fingerprint: b6:19:1a:50:d0:c3:97:7f:7d:a9:9b:cd:aa:c8:6a:22:7d:ae:b9:67:9e:c7:0b:a3:b0:c9:d9:22:71:c1:70:d3
------BEGIN CERTIFICATE-----
-MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc
-MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj
-IFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290IENB
-IDIwHhcNOTkwNzA5MTIxMTAwWhcNMTkwNzA5MjM1OTAwWjBxMQswCQYDVQQGEwJE
-RTEcMBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxl
-U2VjIFRydXN0IENlbnRlcjEjMCEGA1UEAxMaRGV1dHNjaGUgVGVsZWtvbSBSb290
-IENBIDIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCrC6M14IspFLEU
-ha88EOQ5bzVdSq7d6mGNlUn0b2SjGmBmpKlAIoTZ1KXleJMOaAGtuU1cOs7TuKhC
-QN/Po7qCWWqSG6wcmtoIKyUn+WkjR/Hg6yx6m/UTAtB+NHzCnjwAWav12gz1Mjwr
-rFDa1sPeg5TKqAyZMg4ISFZbavva4VhYAUlfckE8FQYBjl2tqriTtM2e66foai1S
-NNs671x1Udrb8zH57nGYMsRUFUQM+ZtV7a3fGAigo4aKSe5TBY8ZTNXeWHmb0moc
-QqvF1afPaA+W5OFhmHZhyJF81j4A4pFQh+GdCuatl9Idxjp9y7zaAzTVjlsB9WoH
-txa2bkp/AgMBAAGjQjBAMB0GA1UdDgQWBBQxw3kbuvVT1xfgiXotF2wKsyudMzAP
-BgNVHRMECDAGAQH/AgEFMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQUFAAOC
-AQEAlGRZrTlk5ynrE/5aw4sTV8gEJPB0d8Bg42f76Ymmg7+Wgnxu1MM9756Abrsp
-tJh6sTtU6zkXR34ajgv8HzFZMQSyzhfzLMdiNlXiItiJVbSYSKpk+tYcNthEeFpa
-IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl
-6iFhkOQxIY40sfcvNUqFENrnijchvllj4PKFiDFT1FQUhXB59C4Gdyd1Lx+4ivn+
-xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU
-Cm26OWMohpLzGITY+9HPBVZkVw==
------END CERTIFICATE-----
-
# Issuer: CN=Cybertrust Global Root O=Cybertrust, Inc
# Subject: CN=Cybertrust Global Root O=Cybertrust, Inc
# Label: "Cybertrust Global Root"
@@ -1559,47 +1434,6 @@ uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2
XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
-----END CERTIFICATE-----
-# Issuer: CN=Staat der Nederlanden Root CA - G2 O=Staat der Nederlanden
-# Subject: CN=Staat der Nederlanden Root CA - G2 O=Staat der Nederlanden
-# Label: "Staat der Nederlanden Root CA - G2"
-# Serial: 10000012
-# MD5 Fingerprint: 7c:a5:0f:f8:5b:9a:7d:6d:30:ae:54:5a:e3:42:a2:8a
-# SHA1 Fingerprint: 59:af:82:79:91:86:c7:b4:75:07:cb:cf:03:57:46:eb:04:dd:b7:16
-# SHA256 Fingerprint: 66:8c:83:94:7d:a6:3b:72:4b:ec:e1:74:3c:31:a0:e6:ae:d0:db:8e:c5:b3:1b:e3:77:bb:78:4f:91:b6:71:6f
------BEGIN CERTIFICATE-----
-MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO
-TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh
-dCBkZXIgTmVkZXJsYW5kZW4gUm9vdCBDQSAtIEcyMB4XDTA4MDMyNjExMTgxN1oX
-DTIwMDMyNTExMDMxMFowWjELMAkGA1UEBhMCTkwxHjAcBgNVBAoMFVN0YWF0IGRl
-ciBOZWRlcmxhbmRlbjErMCkGA1UEAwwiU3RhYXQgZGVyIE5lZGVybGFuZGVuIFJv
-b3QgQ0EgLSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMVZ5291
-qj5LnLW4rJ4L5PnZyqtdj7U5EILXr1HgO+EASGrP2uEGQxGZqhQlEq0i6ABtQ8Sp
-uOUfiUtnvWFI7/3S4GCI5bkYYCjDdyutsDeqN95kWSpGV+RLufg3fNU254DBtvPU
-Z5uW6M7XxgpT0GtJlvOjCwV3SPcl5XCsMBQgJeN/dVrlSPhOewMHBPqCYYdu8DvE
-pMfQ9XQ+pV0aCPKbJdL2rAQmPlU6Yiile7Iwr/g3wtG61jj99O9JMDeZJiFIhQGp
-5Rbn3JBV3w/oOM2ZNyFPXfUib2rFEhZgF1XyZWampzCROME4HYYEhLoaJXhena/M
-UGDWE4dS7WMfbWV9whUYdMrhfmQpjHLYFhN9C0lK8SgbIHRrxT3dsKpICT0ugpTN
-GmXZK4iambwYfp/ufWZ8Pr2UuIHOzZgweMFvZ9C+X+Bo7d7iscksWXiSqt8rYGPy
-5V6548r6f1CGPqI0GAwJaCgRHOThuVw+R7oyPxjMW4T182t0xHJ04eOLoEq9jWYv
-6q012iDTiIJh8BIitrzQ1aTsr1SIJSQ8p22xcik/Plemf1WvbibG/ufMQFxRRIEK
-eN5KzlW/HdXZt1bv8Hb/C3m1r737qWmRRpdogBQ2HbN/uymYNqUg+oJgYjOk7Na6
-B6duxc8UpufWkjTYgfX8HV2qXB72o007uPc5AgMBAAGjgZcwgZQwDwYDVR0TAQH/
-BAUwAwEB/zBSBgNVHSAESzBJMEcGBFUdIAAwPzA9BggrBgEFBQcCARYxaHR0cDov
-L3d3dy5wa2lvdmVyaGVpZC5ubC9wb2xpY2llcy9yb290LXBvbGljeS1HMjAOBgNV
-HQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJFoMocVHYnitfGsNig0jQt8YojrMA0GCSqG
-SIb3DQEBCwUAA4ICAQCoQUpnKpKBglBu4dfYszk78wIVCVBR7y29JHuIhjv5tLyS
-CZa59sCrI2AGeYwRTlHSeYAz+51IvuxBQ4EffkdAHOV6CMqqi3WtFMTC6GY8ggen
-5ieCWxjmD27ZUD6KQhgpxrRW/FYQoAUXvQwjf/ST7ZwaUb7dRUG/kSS0H4zpX897
-IZmflZ85OkYcbPnNe5yQzSipx6lVu6xiNGI1E0sUOlWDuYaNkqbG9AclVMwWVxJK
-gnjIFNkXgiYtXSAfea7+1HAWFpWD2DU5/1JddRwWxRNVz0fMdWVSSt7wsKfkCpYL
-+63C4iWEst3kvX5ZbJvw8NjnyvLplzh+ib7M+zkXYT9y2zqR2GUBGR2tUKRXCnxL
-vJxxcypFURmFzI79R6d0lR2o0a9OF7FpJsKqeFdbxU2n5Z4FF5TKsl+gSRiNNOkm
-bEgeqmiSBeGCc1qb3AdbCG19ndeNIdn8FCCqwkXfP+cAslHkwvgFuXkajDTznlvk
-N1trSt8sV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FC
-Y7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Z
-ywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ==
------END CERTIFICATE-----
-
# Issuer: CN=Hongkong Post Root CA 1 O=Hongkong Post
# Subject: CN=Hongkong Post Root CA 1 O=Hongkong Post
# Label: "Hongkong Post Root CA 1"
@@ -2200,6 +2034,45 @@ t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy
SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
-----END CERTIFICATE-----
+# Issuer: CN=EC-ACC O=Agencia Catalana de Certificacio (NIF Q-0801176-I) OU=Serveis Publics de Certificacio/Vegeu https://www.catcert.net/verarrel (c)03/Jerarquia Entitats de Certificacio Catalanes
+# Subject: CN=EC-ACC O=Agencia Catalana de Certificacio (NIF Q-0801176-I) OU=Serveis Publics de Certificacio/Vegeu https://www.catcert.net/verarrel (c)03/Jerarquia Entitats de Certificacio Catalanes
+# Label: "EC-ACC"
+# Serial: -23701579247955709139626555126524820479
+# MD5 Fingerprint: eb:f5:9d:29:0d:61:f9:42:1f:7c:c2:ba:6d:e3:15:09
+# SHA1 Fingerprint: 28:90:3a:63:5b:52:80:fa:e6:77:4c:0b:6d:a7:d6:ba:a6:4a:f2:e8
+# SHA256 Fingerprint: 88:49:7f:01:60:2f:31:54:24:6a:e2:8c:4d:5a:ef:10:f1:d8:7e:bb:76:62:6f:4a:e0:b7:f9:5b:a7:96:87:99
+-----BEGIN CERTIFICATE-----
+MIIFVjCCBD6gAwIBAgIQ7is969Qh3hSoYqwE893EATANBgkqhkiG9w0BAQUFADCB
+8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy
+dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1
+YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3
+dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh
+IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD
+LUFDQzAeFw0wMzAxMDcyMzAwMDBaFw0zMTAxMDcyMjU5NTlaMIHzMQswCQYDVQQG
+EwJFUzE7MDkGA1UEChMyQWdlbmNpYSBDYXRhbGFuYSBkZSBDZXJ0aWZpY2FjaW8g
+KE5JRiBRLTA4MDExNzYtSSkxKDAmBgNVBAsTH1NlcnZlaXMgUHVibGljcyBkZSBD
+ZXJ0aWZpY2FjaW8xNTAzBgNVBAsTLFZlZ2V1IGh0dHBzOi8vd3d3LmNhdGNlcnQu
+bmV0L3ZlcmFycmVsIChjKTAzMTUwMwYDVQQLEyxKZXJhcnF1aWEgRW50aXRhdHMg
+ZGUgQ2VydGlmaWNhY2lvIENhdGFsYW5lczEPMA0GA1UEAxMGRUMtQUNDMIIBIjAN
+BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAsyLHT+KXQpWIR4NA9h0X84NzJB5R
+85iKw5K4/0CQBXCHYMkAqbWUZRkiFRfCQ2xmRJoNBD45b6VLeqpjt4pEndljkYRm
+4CgPukLjbo73FCeTae6RDqNfDrHrZqJyTxIThmV6PttPB/SnCWDaOkKZx7J/sxaV
+HMf5NLWUhdWZXqBIoH7nF2W4onW4HvPlQn2v7fOKSGRdghST2MDk/7NQcvJ29rNd
+QlB50JQ+awwAvthrDk4q7D7SzIKiGGUzE3eeml0aE9jD2z3Il3rucO2n5nzbcc8t
+lGLfbdb1OL4/pYUKGbio2Al1QnDE6u/LDsg0qBIimAy4E5S2S+zw0JDnJwIDAQAB
+o4HjMIHgMB0GA1UdEQQWMBSBEmVjX2FjY0BjYXRjZXJ0Lm5ldDAPBgNVHRMBAf8E
+BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUoMOLRKo3pUW/l4Ba0fF4
+opvpXY0wfwYDVR0gBHgwdjB0BgsrBgEEAfV4AQMBCjBlMCwGCCsGAQUFBwIBFiBo
+dHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbDA1BggrBgEFBQcCAjApGidW
+ZWdldSBodHRwczovL3d3dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAwDQYJKoZIhvcN
+AQEFBQADggEBAKBIW4IB9k1IuDlVNZyAelOZ1Vr/sXE7zDkJlF7W2u++AVtd0x7Y
+/X1PzaBB4DSTv8vihpw3kpBWHNzrKQXlxJ7HNd+KDM3FIUPpqojlNcAZQmNaAl6k
+SBg6hW/cnbw/nZzBh7h6YQjpdwt/cKt63dmXLGQehb+8dJahw3oS7AwaboMMPOhy
+Rp/7SNVel+axofjk70YllJyJ22k4vuxcDlbHZVHlUIiIv0LVKz3l+bqeLrPK9HOS
+Agu+TGbrIP65y7WZf+a2E/rKS03Z7lNGBjvGTq2TWoF+bCpLagVFjPIhpDGQh2xl
+nJ2lYJU6Un/10asIbvPuW/mIPX64b24D5EI=
+-----END CERTIFICATE-----
+
# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority
# Subject: CN=Hellenic Academic and Research Institutions RootCA 2011 O=Hellenic Academic and Research Institutions Cert. Authority
# Label: "Hellenic Academic and Research Institutions RootCA 2011"
@@ -3809,47 +3682,6 @@ CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW
1KyLa2tJElMzrdfkviT8tQp21KW8EA==
-----END CERTIFICATE-----
-# Issuer: CN=LuxTrust Global Root 2 O=LuxTrust S.A.
-# Subject: CN=LuxTrust Global Root 2 O=LuxTrust S.A.
-# Label: "LuxTrust Global Root 2"
-# Serial: 59914338225734147123941058376788110305822489521
-# MD5 Fingerprint: b2:e1:09:00:61:af:f7:f1:91:6f:c4:ad:8d:5e:3b:7c
-# SHA1 Fingerprint: 1e:0e:56:19:0a:d1:8b:25:98:b2:04:44:ff:66:8a:04:17:99:5f:3f
-# SHA256 Fingerprint: 54:45:5f:71:29:c2:0b:14:47:c4:18:f9:97:16:8f:24:c5:8f:c5:02:3b:f5:da:5b:e2:eb:6e:1d:d8:90:2e:d5
------BEGIN CERTIFICATE-----
-MIIFwzCCA6ugAwIBAgIUCn6m30tEntpqJIWe5rgV0xZ/u7EwDQYJKoZIhvcNAQEL
-BQAwRjELMAkGA1UEBhMCTFUxFjAUBgNVBAoMDUx1eFRydXN0IFMuQS4xHzAdBgNV
-BAMMFkx1eFRydXN0IEdsb2JhbCBSb290IDIwHhcNMTUwMzA1MTMyMTU3WhcNMzUw
-MzA1MTMyMTU3WjBGMQswCQYDVQQGEwJMVTEWMBQGA1UECgwNTHV4VHJ1c3QgUy5B
-LjEfMB0GA1UEAwwWTHV4VHJ1c3QgR2xvYmFsIFJvb3QgMjCCAiIwDQYJKoZIhvcN
-AQEBBQADggIPADCCAgoCggIBANeFl78RmOnwYoNMPIf5U2o3C/IPPIfOb9wmKb3F
-ibrJgz337spbxm1Jc7TJRqMbNBM/wYlFV/TZsfs2ZUv7COJIcRHIbjuend+JZTem
-hfY7RBi2xjcwYkSSl2l9QjAk5A0MiWtj3sXh306pFGxT4GHO9hcvHTy95iJMHZP1
-EMShduxq3sVs35a0VkBCwGKSMKEtFZSg0iAGCW5qbeXrt77U8PEVfIvmTroTzEsn
-Xpk8F12PgX8zPU/TPxvsXD/wPEx1bvKm1Z3aLQdjAsZy6ZS8TEmVT4hSyNvoaYL4
-zDRbIvCGp4m9SAptZoFtyMhk+wHh9OHe2Z7d21vUKpkmFRseTJIpgp7VkoGSQXAZ
-96Tlk0u8d2cx3Rz9MXANF5kM+Qw5GSoXtTBxVdUPrljhPS80m8+f9niFwpN6cj5m
-j5wWEWCPnolvZ77gR1o7DJpni89Gxq44o/KnvObWhWszJHAiS8sIm7vI+AIpHb4g
-DEa/a4ebsypmQjVGbKq6rfmYe+lQVRQxv7HaLe2ArWgk+2mr2HETMOZns4dA/Yl+
-8kPREd8vZS9kzl8UubG/Mb2HeFpZZYiq/FkySIbWTLkpS5XTdvN3JW1CHDiDTf2j
-X5t/Lax5Gw5CMZdjpPuKadUiDTSQMC6otOBttpSsvItO13D8xTiOZCXhTTmQzsmH
-hFhxAgMBAAGjgagwgaUwDwYDVR0TAQH/BAUwAwEB/zBCBgNVHSAEOzA5MDcGByuB
-KwEBAQowLDAqBggrBgEFBQcCARYeaHR0cHM6Ly9yZXBvc2l0b3J5Lmx1eHRydXN0
-Lmx1MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBT/GCh2+UgFLKGu8SsbK7JT
-+Et8szAdBgNVHQ4EFgQU/xgodvlIBSyhrvErGyuyU/hLfLMwDQYJKoZIhvcNAQEL
-BQADggIBAGoZFO1uecEsh9QNcH7X9njJCwROxLHOk3D+sFTAMs2ZMGQXvw/l4jP9
-BzZAcg4atmpZ1gDlaCDdLnINH2pkMSCEfUmmWjfrRcmF9dTHF5kH5ptV5AzoqbTO
-jFu1EVzPig4N1qx3gf4ynCSecs5U89BvolbW7MM3LGVYvlcAGvI1+ut7MV3CwRI9
-loGIlonBWVx65n9wNOeD4rHh4bhY79SV5GCc8JaXcozrhAIuZY+kt9J/Z93I055c
-qqmkoCUUBpvsT34tC38ddfEz2O3OuHVtPlu5mB0xDVbYQw8wkbIEa91WvpWAVWe+
-2M2D2RjuLg+GLZKecBPs3lHJQ3gCpU3I+V/EkVhGFndadKpAvAefMLmx9xIX3eP/
-JEAdemrRTxgKqpAd60Ae36EeRJIQmvKN4dFLRp7oRUKX6kWZ8+xm1QL68qZKJKre
-zrnK+T+Tb/mjuuqlPpmt/f97mfVl7vBZKGfXkJWkE4SphMHozs51k2MavDzq1WQf
-LSoSOcbDWjLtR5EWDrw4wVDej8oqkDQc7kGUnF4ZLvhFSZl0kbAEb+MEWrGrKqv+
-x9CWttrhSmQGbmBNvUJO/3jaJMobtNeWOWyu8Q6qp31IiyBMz2TWuJdGsE7RKlY6
-oJO9r4Ak4Ap+58rVyuiFVdw2KuGUaJPHZnJED4AhMmwlxyOAgwrr
------END CERTIFICATE-----
-
# Issuer: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM
# Subject: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM
# Label: "TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1"
@@ -4616,3 +4448,173 @@ L5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB60PZ2Pierc+xYw5F9KBa
LJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fqdBb9HxEG
mpv0
-----END CERTIFICATE-----
+
+# Issuer: CN=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only
+# Subject: CN=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only
+# Label: "Entrust Root Certification Authority - G4"
+# Serial: 289383649854506086828220374796556676440
+# MD5 Fingerprint: 89:53:f1:83:23:b7:7c:8e:05:f1:8c:71:38:4e:1f:88
+# SHA1 Fingerprint: 14:88:4e:86:26:37:b0:26:af:59:62:5c:40:77:ec:35:29:ba:96:01
+# SHA256 Fingerprint: db:35:17:d1:f6:73:2a:2d:5a:b9:7c:53:3e:c7:07:79:ee:32:70:a6:2f:b4:ac:42:38:37:24:60:e6:f0:1e:88
+-----BEGIN CERTIFICATE-----
+MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw
+gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL
+Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg
+MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw
+BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0
+MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1
+c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ
+bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg
+Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B
+AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ
+2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E
+T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j
+5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM
+C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T
+DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX
+wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A
+2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm
+nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8
+dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl
+N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj
+c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
+VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS
+5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS
+Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr
+hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/
+B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI
+AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw
+H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+
+b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk
+2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol
+IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk
+5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY
+n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw==
+-----END CERTIFICATE-----
+
+# Issuer: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation
+# Subject: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation
+# Label: "Microsoft ECC Root Certificate Authority 2017"
+# Serial: 136839042543790627607696632466672567020
+# MD5 Fingerprint: dd:a1:03:e6:4a:93:10:d1:bf:f0:19:42:cb:fe:ed:67
+# SHA1 Fingerprint: 99:9a:64:c3:7f:f4:7d:9f:ab:95:f1:47:69:89:14:60:ee:c4:c3:c5
+# SHA256 Fingerprint: 35:8d:f3:9d:76:4a:f9:e1:b7:66:e9:c9:72:df:35:2e:e1:5c:fa:c2:27:af:6a:d1:d7:0e:8e:4a:6e:dc:ba:02
+-----BEGIN CERTIFICATE-----
+MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw
+CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD
+VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw
+MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV
+UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy
+b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq
+hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR
+ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb
+hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E
+BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3
+FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV
+L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB
+iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M=
+-----END CERTIFICATE-----
+
+# Issuer: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation
+# Subject: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation
+# Label: "Microsoft RSA Root Certificate Authority 2017"
+# Serial: 40975477897264996090493496164228220339
+# MD5 Fingerprint: 10:ff:00:ff:cf:c9:f8:c7:7a:c0:ee:35:8e:c9:0f:47
+# SHA1 Fingerprint: 73:a5:e6:4a:3b:ff:83:16:ff:0e:dc:cc:61:8a:90:6e:4e:ae:4d:74
+# SHA256 Fingerprint: c7:41:f7:0f:4b:2a:8d:88:bf:2e:71:c1:41:22:ef:53:ef:10:eb:a0:cf:a5:e6:4c:fa:20:f4:18:85:30:73:e0
+-----BEGIN CERTIFICATE-----
+MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl
+MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw
+NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
+IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG
+EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N
+aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi
+MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ
+Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0
+ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1
+HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm
+gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ
+jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc
+aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG
+YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6
+W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K
+UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH
++FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q
+W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/
+BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC
+NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC
+LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC
+gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6
+tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh
+SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2
+TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3
+pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR
+xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp
+GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9
+dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN
+AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB
+RA+GsCyRxj3qrg+E
+-----END CERTIFICATE-----
+
+# Issuer: CN=e-Szigno Root CA 2017 O=Microsec Ltd.
+# Subject: CN=e-Szigno Root CA 2017 O=Microsec Ltd.
+# Label: "e-Szigno Root CA 2017"
+# Serial: 411379200276854331539784714
+# MD5 Fingerprint: de:1f:f6:9e:84:ae:a7:b4:21:ce:1e:58:7d:d1:84:98
+# SHA1 Fingerprint: 89:d4:83:03:4f:9e:9a:48:80:5f:72:37:d4:a9:a6:ef:cb:7c:1f:d1
+# SHA256 Fingerprint: be:b0:0b:30:83:9b:9b:c3:2c:32:e4:44:79:05:95:06:41:f2:64:21:b1:5e:d0:89:19:8b:51:8a:e2:ea:1b:99
+-----BEGIN CERTIFICATE-----
+MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV
+BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk
+LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv
+b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ
+BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg
+THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v
+IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv
+xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H
+Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
+A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB
+eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo
+jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ
++efcMQ==
+-----END CERTIFICATE-----
+
+# Issuer: O=CERTSIGN SA OU=certSIGN ROOT CA G2
+# Subject: O=CERTSIGN SA OU=certSIGN ROOT CA G2
+# Label: "certSIGN Root CA G2"
+# Serial: 313609486401300475190
+# MD5 Fingerprint: 8c:f1:75:8a:c6:19:cf:94:b7:f7:65:20:87:c3:97:c7
+# SHA1 Fingerprint: 26:f9:93:b4:ed:3d:28:27:b0:b9:4b:a7:e9:15:1d:a3:8d:92:e5:32
+# SHA256 Fingerprint: 65:7c:fe:2f:a7:3f:aa:38:46:25:71:f3:32:a2:36:3a:46:fc:e7:02:09:51:71:07:02:cd:fb:b6:ee:da:33:05
+-----BEGIN CERTIFICATE-----
+MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV
+BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g
+Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ
+BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ
+R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF
+dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw
+vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ
+uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp
+n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs
+cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW
+xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P
+rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF
+DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx
+DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy
+LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C
+eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ
+d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq
+kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC
+b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl
+qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0
+OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c
+NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk
+ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO
+pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj
+03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk
+PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE
+1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX
+QRBdJ3NghVdJIgc=
+-----END CERTIFICATE-----
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/certifi/core.py b/venv/lib/python3.8/site-packages/pip/_vendor/certifi/core.py
index 7271acf..8987449 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/certifi/core.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/certifi/core.py
@@ -4,12 +4,57 @@
certifi.py
~~~~~~~~~~
-This module returns the installation location of cacert.pem.
+This module returns the installation location of cacert.pem or its contents.
"""
import os
+try:
+ from importlib.resources import path as get_path, read_text
-def where():
- f = os.path.dirname(__file__)
+ _CACERT_CTX = None
+ _CACERT_PATH = None
- return os.path.join(f, 'cacert.pem')
+ def where():
+ # This is slightly terrible, but we want to delay extracting the file
+ # in cases where we're inside of a zipimport situation until someone
+ # actually calls where(), but we don't want to re-extract the file
+ # on every call of where(), so we'll do it once then store it in a
+ # global variable.
+ global _CACERT_CTX
+ global _CACERT_PATH
+ if _CACERT_PATH is None:
+ # This is slightly janky, the importlib.resources API wants you to
+ # manage the cleanup of this file, so it doesn't actually return a
+ # path, it returns a context manager that will give you the path
+ # when you enter it and will do any cleanup when you leave it. In
+ # the common case of not needing a temporary file, it will just
+ # return the file system location and the __exit__() is a no-op.
+ #
+ # We also have to hold onto the actual context manager, because
+ # it will do the cleanup whenever it gets garbage collected, so
+ # we will also store that at the global level as well.
+ _CACERT_CTX = get_path("pip._vendor.certifi", "cacert.pem")
+ _CACERT_PATH = str(_CACERT_CTX.__enter__())
+
+ return _CACERT_PATH
+
+
+except ImportError:
+ # This fallback will work for Python versions prior to 3.7 that lack the
+ # importlib.resources module but relies on the existing `where` function
+ # so won't address issues with environments like PyOxidizer that don't set
+ # __file__ on modules.
+ def read_text(_module, _path, encoding="ascii"):
+ with open(where(), "r", encoding=encoding) as data:
+ return data.read()
+
+ # If we don't have importlib.resources, then we will just do the old logic
+ # of assuming we're on the filesystem and munge the path directly.
+ def where():
+ f = os.path.dirname(__file__)
+
+ return os.path.join(f, "cacert.pem")
+
+
+def contents():
+ return read_text("certifi", "cacert.pem", encoding="ascii")
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/__init__.cpython-38.pyc
index 01375ee..ea262e3 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/big5freq.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/big5freq.cpython-38.pyc
index fc30105..3c66a22 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/big5freq.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/big5freq.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/big5prober.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/big5prober.cpython-38.pyc
index fa4ccca..e71ec28 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/big5prober.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/big5prober.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/chardistribution.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/chardistribution.cpython-38.pyc
index ded55b9..8c15c30 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/chardistribution.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/chardistribution.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/charsetgroupprober.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/charsetgroupprober.cpython-38.pyc
index e71d10b..c89ffac 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/charsetgroupprober.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/charsetgroupprober.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/charsetprober.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/charsetprober.cpython-38.pyc
index 9efd051..f204cbc 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/charsetprober.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/charsetprober.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachine.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachine.cpython-38.pyc
index a427742..d7a44b5 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachine.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachine.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/compat.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/compat.cpython-38.pyc
index fd57777..53e4c4f 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/compat.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/compat.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/cp949prober.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/cp949prober.cpython-38.pyc
index c3c7656..385500e 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/cp949prober.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/cp949prober.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/enums.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/enums.cpython-38.pyc
index ade15ee..829c213 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/enums.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/enums.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/escprober.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/escprober.cpython-38.pyc
index 5b58c0a..494c97e 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/escprober.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/escprober.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/escsm.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/escsm.cpython-38.pyc
index 5b5748c..0eee0c3 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/escsm.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/escsm.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/eucjpprober.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/eucjpprober.cpython-38.pyc
index 8a89ff8..30a3c33 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/eucjpprober.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/eucjpprober.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/euckrfreq.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/euckrfreq.cpython-38.pyc
index a3f1509..4380bae 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/euckrfreq.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/euckrfreq.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/euckrprober.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/euckrprober.cpython-38.pyc
index 81ee6d8..c495c53 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/euckrprober.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/euckrprober.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/euctwfreq.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/euctwfreq.cpython-38.pyc
index 10d48d0..ff38a78 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/euctwfreq.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/euctwfreq.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/euctwprober.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/euctwprober.cpython-38.pyc
index bf87674..6a21f6c 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/euctwprober.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/euctwprober.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/gb2312freq.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/gb2312freq.cpython-38.pyc
index f742a8c..2d1e270 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/gb2312freq.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/gb2312freq.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/gb2312prober.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/gb2312prober.cpython-38.pyc
index f9187e6..a4fe00d 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/gb2312prober.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/gb2312prober.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/hebrewprober.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/hebrewprober.cpython-38.pyc
index 69b57d7..7fd5f8d 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/hebrewprober.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/hebrewprober.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/jisfreq.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/jisfreq.cpython-38.pyc
index bfb5121..65edc6b 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/jisfreq.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/jisfreq.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/jpcntx.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/jpcntx.cpython-38.pyc
index 5733dae..bc529b0 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/jpcntx.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/jpcntx.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langbulgarianmodel.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langbulgarianmodel.cpython-38.pyc
index ffe4bfb..0837bad 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langbulgarianmodel.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langbulgarianmodel.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langcyrillicmodel.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langcyrillicmodel.cpython-38.pyc
index 12796e9..1f6ddbf 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langcyrillicmodel.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langcyrillicmodel.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langgreekmodel.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langgreekmodel.cpython-38.pyc
index fd7eb0f..effb46d 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langgreekmodel.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langgreekmodel.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langhebrewmodel.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langhebrewmodel.cpython-38.pyc
index 65037fa..9f77434 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langhebrewmodel.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langhebrewmodel.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langhungarianmodel.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langhungarianmodel.cpython-38.pyc
index ce11a8a..4864d4b 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langhungarianmodel.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langhungarianmodel.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langthaimodel.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langthaimodel.cpython-38.pyc
index 3cf85fd..1ab86d3 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langthaimodel.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langthaimodel.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langturkishmodel.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langturkishmodel.cpython-38.pyc
index 1ff1acb..3f41239 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langturkishmodel.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/langturkishmodel.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/latin1prober.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/latin1prober.cpython-38.pyc
index f61d25e..5041a34 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/latin1prober.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/latin1prober.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/mbcharsetprober.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/mbcharsetprober.cpython-38.pyc
index b2031b9..70f4ad2 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/mbcharsetprober.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/mbcharsetprober.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/mbcsgroupprober.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/mbcsgroupprober.cpython-38.pyc
index e2d88b8..6f38ffa 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/mbcsgroupprober.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/mbcsgroupprober.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/mbcssm.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/mbcssm.cpython-38.pyc
index 5810f53..bc70100 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/mbcssm.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/mbcssm.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/sbcharsetprober.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/sbcharsetprober.cpython-38.pyc
index ff84b92..3b69145 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/sbcharsetprober.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/sbcharsetprober.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/sbcsgroupprober.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/sbcsgroupprober.cpython-38.pyc
index e7ed467..cadf341 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/sbcsgroupprober.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/sbcsgroupprober.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/sjisprober.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/sjisprober.cpython-38.pyc
index 089fcfb..d8cf0c8 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/sjisprober.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/sjisprober.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/universaldetector.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/universaldetector.cpython-38.pyc
index 89dc24d..181d9c3 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/universaldetector.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/universaldetector.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/utf8prober.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/utf8prober.cpython-38.pyc
index 1c2e2e9..ffb7b4c 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/utf8prober.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/utf8prober.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/version.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/version.cpython-38.pyc
index 5c5de7d..b7319fd 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/version.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/__pycache__/version.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/cli/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/cli/__pycache__/__init__.cpython-38.pyc
index 671cb8e..cbb12d0 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/cli/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/cli/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/cli/__pycache__/chardetect.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/cli/__pycache__/chardetect.cpython-38.pyc
index 320a702..24a4adc 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/chardet/cli/__pycache__/chardetect.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/chardet/cli/__pycache__/chardetect.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__init__.py
index 2a3bf47..34c263c 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__init__.py
@@ -3,4 +3,4 @@ from .initialise import init, deinit, reinit, colorama_text
from .ansi import Fore, Back, Style, Cursor
from .ansitowin32 import AnsiToWin32
-__version__ = '0.4.1'
+__version__ = '0.4.3'
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/__init__.cpython-38.pyc
index efa7702..cf0e06e 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/ansi.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/ansi.cpython-38.pyc
index 469e689..0db81f9 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/ansi.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/ansi.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/ansitowin32.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/ansitowin32.cpython-38.pyc
index 00b902a..0f35ee1 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/ansitowin32.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/ansitowin32.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/initialise.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/initialise.cpython-38.pyc
index b631a8d..3bef049 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/initialise.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/initialise.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/win32.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/win32.cpython-38.pyc
index 0cfea77..7325904 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/win32.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/win32.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/winterm.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/winterm.cpython-38.pyc
index ca849fb..d9fb8ab 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/winterm.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/colorama/__pycache__/winterm.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__init__.py
index a2d70d4..63d916e 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__init__.py
@@ -6,7 +6,7 @@
#
import logging
-__version__ = '0.2.9.post0'
+__version__ = '0.3.1'
class DistlibException(Exception):
pass
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-38.pyc
index 3fde1c8..a38142a 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-38.pyc
index 3c77652..a448043 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-38.pyc
index bf5044d..771e0d7 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-38.pyc
index ae7743e..57341a5 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-38.pyc
index 8f4af00..50a4b87 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-38.pyc
index 06b0962..9e7a13b 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-38.pyc
index ff7b6b1..cb9aa7e 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-38.pyc
index 3b865da..920af04 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-38.pyc
index 1888ccf..28cb4a1 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-38.pyc
index 9c94175..67fe402 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-38.pyc
index 18d44b5..34e1b46 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-38.pyc
index 788e5eb..8040e0a 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-38.pyc
index a64c7d2..b7743fa 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/__init__.cpython-38.pyc
index 228d895..1833c68 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/misc.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/misc.cpython-38.pyc
index 86472ba..6cd1781 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/misc.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/misc.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/shutil.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/shutil.cpython-38.pyc
index d03c527..f6000a7 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/shutil.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/shutil.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/sysconfig.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/sysconfig.cpython-38.pyc
index 5e17752..6829852 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/sysconfig.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/sysconfig.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/tarfile.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/tarfile.cpython-38.pyc
index bd828f3..fb881fb 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/tarfile.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/__pycache__/tarfile.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/shutil.py b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/shutil.py
index 159e49e..10ed362 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/shutil.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/shutil.py
@@ -14,7 +14,10 @@ import sys
import stat
from os.path import abspath
import fnmatch
-import collections
+try:
+ from collections.abc import Callable
+except ImportError:
+ from collections import Callable
import errno
from . import tarfile
@@ -528,7 +531,7 @@ def register_archive_format(name, function, extra_args=None, description=''):
"""
if extra_args is None:
extra_args = []
- if not isinstance(function, collections.Callable):
+ if not isinstance(function, Callable):
raise TypeError('The %s object is not callable' % function)
if not isinstance(extra_args, (tuple, list)):
raise TypeError('extra_args needs to be a sequence')
@@ -621,7 +624,7 @@ def _check_unpack_options(extensions, function, extra_args):
raise RegistryError(msg % (extension,
existing_extensions[extension]))
- if not isinstance(function, collections.Callable):
+ if not isinstance(function, Callable):
raise TypeError('The registered function must be a callable')
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/sysconfig.py b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/sysconfig.py
index 1df3aba..b470a37 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/sysconfig.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/_backport/sysconfig.py
@@ -119,11 +119,9 @@ def _expand_globals(config):
#_expand_globals(_SCHEMES)
- # FIXME don't rely on sys.version here, its format is an implementation detail
- # of CPython, use sys.version_info or sys.hexversion
-_PY_VERSION = sys.version.split()[0]
-_PY_VERSION_SHORT = sys.version[:3]
-_PY_VERSION_SHORT_NO_DOT = _PY_VERSION[0] + _PY_VERSION[2]
+_PY_VERSION = '%s.%s.%s' % sys.version_info[:3]
+_PY_VERSION_SHORT = '%s.%s' % sys.version_info[:2]
+_PY_VERSION_SHORT_NO_DOT = '%s%s' % sys.version_info[:2]
_PREFIX = os.path.normpath(sys.prefix)
_EXEC_PREFIX = os.path.normpath(sys.exec_prefix)
_CONFIG_VARS = None
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/compat.py b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/compat.py
index ff328c8..c316fd9 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/compat.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/compat.py
@@ -319,7 +319,7 @@ except ImportError: # pragma: no cover
try:
callable = callable
except NameError: # pragma: no cover
- from collections import Callable
+ from collections.abc import Callable
def callable(obj):
return isinstance(obj, Callable)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/database.py b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/database.py
index b13cdac..0a90c30 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/database.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/database.py
@@ -550,7 +550,7 @@ class InstalledDistribution(BaseInstalledDistribution):
r = finder.find(WHEEL_METADATA_FILENAME)
# Temporary - for legacy support
if r is None:
- r = finder.find('METADATA')
+ r = finder.find(LEGACY_METADATA_FILENAME)
if r is None:
raise ValueError('no %s found in %s' % (METADATA_FILENAME,
path))
@@ -567,7 +567,7 @@ class InstalledDistribution(BaseInstalledDistribution):
p = os.path.join(path, 'top_level.txt')
if os.path.exists(p):
with open(p, 'rb') as f:
- data = f.read()
+ data = f.read().decode('utf-8')
self.modules = data.splitlines()
def __repr__(self):
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/locators.py b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/locators.py
index a7ed946..12a1d06 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/locators.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/locators.py
@@ -304,18 +304,25 @@ class Locator(object):
def _get_digest(self, info):
"""
- Get a digest from a dictionary by looking at keys of the form
- 'algo_digest'.
+ Get a digest from a dictionary by looking at a "digests" dictionary
+ or keys of the form 'algo_digest'.
Returns a 2-tuple (algo, digest) if found, else None. Currently
looks only for SHA256, then MD5.
"""
result = None
- for algo in ('sha256', 'md5'):
- key = '%s_digest' % algo
- if key in info:
- result = (algo, info[key])
- break
+ if 'digests' in info:
+ digests = info['digests']
+ for algo in ('sha256', 'md5'):
+ if algo in digests:
+ result = (algo, digests[algo])
+ break
+ if not result:
+ for algo in ('sha256', 'md5'):
+ key = '%s_digest' % algo
+ if key in info:
+ result = (algo, info[key])
+ break
return result
def _update_version_data(self, result, info):
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/metadata.py b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/metadata.py
index 2d61378..6d5e236 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/metadata.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/metadata.py
@@ -5,7 +5,7 @@
#
"""Implementation of the Metadata for Python packages PEPs.
-Supports all metadata formats (1.0, 1.1, 1.2, and 2.0 experimental).
+Supports all metadata formats (1.0, 1.1, 1.2, 1.3/2.1 and withdrawn 2.0).
"""
from __future__ import unicode_literals
@@ -194,38 +194,12 @@ def _best_version(fields):
return '2.0'
+# This follows the rules about transforming keys as described in
+# https://www.python.org/dev/peps/pep-0566/#id17
_ATTR2FIELD = {
- 'metadata_version': 'Metadata-Version',
- 'name': 'Name',
- 'version': 'Version',
- 'platform': 'Platform',
- 'supported_platform': 'Supported-Platform',
- 'summary': 'Summary',
- 'description': 'Description',
- 'keywords': 'Keywords',
- 'home_page': 'Home-page',
- 'author': 'Author',
- 'author_email': 'Author-email',
- 'maintainer': 'Maintainer',
- 'maintainer_email': 'Maintainer-email',
- 'license': 'License',
- 'classifier': 'Classifier',
- 'download_url': 'Download-URL',
- 'obsoletes_dist': 'Obsoletes-Dist',
- 'provides_dist': 'Provides-Dist',
- 'requires_dist': 'Requires-Dist',
- 'setup_requires_dist': 'Setup-Requires-Dist',
- 'requires_python': 'Requires-Python',
- 'requires_external': 'Requires-External',
- 'requires': 'Requires',
- 'provides': 'Provides',
- 'obsoletes': 'Obsoletes',
- 'project_url': 'Project-URL',
- 'private_version': 'Private-Version',
- 'obsoleted_by': 'Obsoleted-By',
- 'extension': 'Extension',
- 'provides_extra': 'Provides-Extra',
+ name.lower().replace("-", "_"): name for name in _ALL_FIELDS
}
+_FIELD2ATTR = {field: attr for attr, field in _ATTR2FIELD.items()}
_PREDICATE_FIELDS = ('Requires-Dist', 'Obsoletes-Dist', 'Provides-Dist')
_VERSIONS_FIELDS = ('Requires-Python',)
@@ -262,7 +236,7 @@ def _get_name_and_version(name, version, for_filename=False):
class LegacyMetadata(object):
"""The legacy metadata of a release.
- Supports versions 1.0, 1.1 and 1.2 (auto-detected). You can
+ Supports versions 1.0, 1.1, 1.2, 2.0 and 1.3/2.1 (auto-detected). You can
instantiate the class with one of these arguments (or none):
- *path*, the path to a metadata file
- *fileobj* give a file-like object with metadata as content
@@ -381,6 +355,11 @@ class LegacyMetadata(object):
value = msg[field]
if value is not None and value != 'UNKNOWN':
self.set(field, value)
+
+ # PEP 566 specifies that the body be used for the description, if
+ # available
+ body = msg.get_payload()
+ self["Description"] = body if body else self["Description"]
# logger.debug('Attempting to set metadata for %s', self)
# self.set_metadata_version()
@@ -567,57 +546,21 @@ class LegacyMetadata(object):
Field names will be converted to use the underscore-lowercase style
instead of hyphen-mixed case (i.e. home_page instead of Home-page).
+ This is as per https://www.python.org/dev/peps/pep-0566/#id17.
"""
self.set_metadata_version()
- mapping_1_0 = (
- ('metadata_version', 'Metadata-Version'),
- ('name', 'Name'),
- ('version', 'Version'),
- ('summary', 'Summary'),
- ('home_page', 'Home-page'),
- ('author', 'Author'),
- ('author_email', 'Author-email'),
- ('license', 'License'),
- ('description', 'Description'),
- ('keywords', 'Keywords'),
- ('platform', 'Platform'),
- ('classifiers', 'Classifier'),
- ('download_url', 'Download-URL'),
- )
+ fields = _version2fieldlist(self['Metadata-Version'])
data = {}
- for key, field_name in mapping_1_0:
+
+ for field_name in fields:
if not skip_missing or field_name in self._fields:
- data[key] = self[field_name]
-
- if self['Metadata-Version'] == '1.2':
- mapping_1_2 = (
- ('requires_dist', 'Requires-Dist'),
- ('requires_python', 'Requires-Python'),
- ('requires_external', 'Requires-External'),
- ('provides_dist', 'Provides-Dist'),
- ('obsoletes_dist', 'Obsoletes-Dist'),
- ('project_url', 'Project-URL'),
- ('maintainer', 'Maintainer'),
- ('maintainer_email', 'Maintainer-email'),
- )
- for key, field_name in mapping_1_2:
- if not skip_missing or field_name in self._fields:
- if key != 'project_url':
- data[key] = self[field_name]
- else:
- data[key] = [','.join(u) for u in self[field_name]]
-
- elif self['Metadata-Version'] == '1.1':
- mapping_1_1 = (
- ('provides', 'Provides'),
- ('requires', 'Requires'),
- ('obsoletes', 'Obsoletes'),
- )
- for key, field_name in mapping_1_1:
- if not skip_missing or field_name in self._fields:
+ key = _FIELD2ATTR[field_name]
+ if key != 'project_url':
data[key] = self[field_name]
+ else:
+ data[key] = [','.join(u) for u in self[field_name]]
return data
@@ -1003,10 +946,14 @@ class Metadata(object):
LEGACY_MAPPING = {
'name': 'Name',
'version': 'Version',
- 'license': 'License',
+ ('extensions', 'python.details', 'license'): 'License',
'summary': 'Summary',
'description': 'Description',
- 'classifiers': 'Classifier',
+ ('extensions', 'python.project', 'project_urls', 'Home'): 'Home-page',
+ ('extensions', 'python.project', 'contacts', 0, 'name'): 'Author',
+ ('extensions', 'python.project', 'contacts', 0, 'email'): 'Author-email',
+ 'source_url': 'Download-URL',
+ ('extensions', 'python.details', 'classifiers'): 'Classifier',
}
def _to_legacy(self):
@@ -1034,16 +981,29 @@ class Metadata(object):
assert self._data and not self._legacy
result = LegacyMetadata()
nmd = self._data
+ # import pdb; pdb.set_trace()
for nk, ok in self.LEGACY_MAPPING.items():
- if nk in nmd:
- result[ok] = nmd[nk]
+ if not isinstance(nk, tuple):
+ if nk in nmd:
+ result[ok] = nmd[nk]
+ else:
+ d = nmd
+ found = True
+ for k in nk:
+ try:
+ d = d[k]
+ except (KeyError, IndexError):
+ found = False
+ break
+ if found:
+ result[ok] = d
r1 = process_entries(self.run_requires + self.meta_requires)
r2 = process_entries(self.build_requires + self.dev_requires)
if self.extras:
result['Provides-Extra'] = sorted(self.extras)
result['Requires-Dist'] = sorted(r1)
result['Setup-Requires-Dist'] = sorted(r2)
- # TODO: other fields such as contacts
+ # TODO: any other fields wanted
return result
def write(self, path=None, fileobj=None, legacy=False, skip_unknown=True):
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/scripts.py b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/scripts.py
index 5965e24..03f8f21 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/scripts.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/scripts.py
@@ -48,7 +48,7 @@ if __name__ == '__main__':
'''
-def _enquote_executable(executable):
+def enquote_executable(executable):
if ' ' in executable:
# make sure we quote only the executable in case of env
# for example /usr/bin/env "/dir with spaces/bin/jython"
@@ -63,6 +63,8 @@ def _enquote_executable(executable):
executable = '"%s"' % executable
return executable
+# Keep the old name around (for now), as there is at least one project using it!
+_enquote_executable = enquote_executable
class ScriptMaker(object):
"""
@@ -88,6 +90,7 @@ class ScriptMaker(object):
self._is_nt = os.name == 'nt' or (
os.name == 'java' and os._name == 'nt')
+ self.version_info = sys.version_info
def _get_alternate_executable(self, executable, options):
if options.get('gui', False) and self._is_nt: # pragma: no cover
@@ -172,12 +175,20 @@ class ScriptMaker(object):
if sys.platform.startswith('java'): # pragma: no cover
executable = self._fix_jython_executable(executable)
- # Normalise case for Windows
- executable = os.path.normcase(executable)
+
+ # Normalise case for Windows - COMMENTED OUT
+ # executable = os.path.normcase(executable)
+ # N.B. The normalising operation above has been commented out: See
+ # issue #124. Although paths in Windows are generally case-insensitive,
+ # they aren't always. For example, a path containing a ẞ (which is a
+ # LATIN CAPITAL LETTER SHARP S - U+1E9E) is normcased to ß (which is a
+ # LATIN SMALL LETTER SHARP S' - U+00DF). The two are not considered by
+ # Windows as equivalent in path names.
+
# If the user didn't specify an executable, it may be necessary to
# cater for executable paths with spaces (not uncommon on Windows)
if enquote:
- executable = _enquote_executable(executable)
+ executable = enquote_executable(executable)
# Issue #51: don't use fsencode, since we later try to
# check that the shebang is decodable using utf-8.
executable = executable.encode('utf-8')
@@ -285,9 +296,10 @@ class ScriptMaker(object):
if '' in self.variants:
scriptnames.add(name)
if 'X' in self.variants:
- scriptnames.add('%s%s' % (name, sys.version[0]))
+ scriptnames.add('%s%s' % (name, self.version_info[0]))
if 'X.Y' in self.variants:
- scriptnames.add('%s-%s' % (name, sys.version[:3]))
+ scriptnames.add('%s-%s.%s' % (name, self.version_info[0],
+ self.version_info[1]))
if options and options.get('gui', False):
ext = 'pyw'
else:
@@ -367,8 +379,12 @@ class ScriptMaker(object):
# Issue 31: don't hardcode an absolute package name, but
# determine it relative to the current package
distlib_package = __name__.rsplit('.', 1)[0]
- result = finder(distlib_package).find(name).bytes
- return result
+ resource = finder(distlib_package).find(name)
+ if not resource:
+ msg = ('Unable to find resource %s in package %s' % (name,
+ distlib_package))
+ raise ValueError(msg)
+ return resource.bytes
# Public API follows
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/t32.exe b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/t32.exe
index 5d5bce1..8932a18 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/t32.exe and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/t32.exe differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/t64.exe b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/t64.exe
index 039ce44..325b805 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/t64.exe and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/t64.exe differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/util.py b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/util.py
index e851146..01324ea 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/util.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/util.py
@@ -703,7 +703,7 @@ class ExportEntry(object):
ENTRY_RE = re.compile(r'''(?P(\w|[-.+])+)
\s*=\s*(?P(\w+)([:\.]\w+)*)
- \s*(\[\s*(?P\w+(=\w+)?(,\s*\w+(=\w+)?)*)\s*\])?
+ \s*(\[\s*(?P[\w-]+(=\w+)?(,\s*\w+(=\w+)?)*)\s*\])?
''', re.VERBOSE)
def get_export_entry(specification):
@@ -1438,7 +1438,8 @@ if ssl:
ca_certs=self.ca_certs)
else: # pragma: no cover
context = ssl.SSLContext(ssl.PROTOCOL_SSLv23)
- context.options |= ssl.OP_NO_SSLv2
+ if hasattr(ssl, 'OP_NO_SSLv2'):
+ context.options |= ssl.OP_NO_SSLv2
if self.cert_file:
context.load_cert_chain(self.cert_file, self.key_file)
kwargs = {}
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/w32.exe b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/w32.exe
index 4df7700..e6439e9 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/w32.exe and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/w32.exe differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/w64.exe b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/w64.exe
index 63ce483..46139db 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/w64.exe and b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/w64.exe differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/wheel.py b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/wheel.py
index 0c8efad..1e2c7a0 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/distlib/wheel.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/distlib/wheel.py
@@ -26,7 +26,8 @@ import zipfile
from . import __version__, DistlibException
from .compat import sysconfig, ZipFile, fsdecode, text_type, filter
from .database import InstalledDistribution
-from .metadata import Metadata, METADATA_FILENAME, WHEEL_METADATA_FILENAME
+from .metadata import (Metadata, METADATA_FILENAME, WHEEL_METADATA_FILENAME,
+ LEGACY_METADATA_FILENAME)
from .util import (FileOperator, convert_path, CSVReader, CSVWriter, Cache,
cached_property, get_cache_base, read_exports, tempdir)
from .version import NormalizedVersion, UnsupportedVersionError
@@ -221,10 +222,12 @@ class Wheel(object):
wheel_metadata = self.get_wheel_metadata(zf)
wv = wheel_metadata['Wheel-Version'].split('.', 1)
file_version = tuple([int(i) for i in wv])
- if file_version < (1, 1):
- fns = [WHEEL_METADATA_FILENAME, METADATA_FILENAME, 'METADATA']
- else:
- fns = [WHEEL_METADATA_FILENAME, METADATA_FILENAME]
+ # if file_version < (1, 1):
+ # fns = [WHEEL_METADATA_FILENAME, METADATA_FILENAME,
+ # LEGACY_METADATA_FILENAME]
+ # else:
+ # fns = [WHEEL_METADATA_FILENAME, METADATA_FILENAME]
+ fns = [WHEEL_METADATA_FILENAME, LEGACY_METADATA_FILENAME]
result = None
for fn in fns:
try:
@@ -299,10 +302,9 @@ class Wheel(object):
return hash_kind, result
def write_record(self, records, record_path, base):
- records = list(records) # make a copy for sorting
+ records = list(records) # make a copy, as mutated
p = to_posix(os.path.relpath(record_path, base))
records.append((p, '', ''))
- records.sort()
with CSVWriter(record_path) as writer:
for row in records:
writer.writerow(row)
@@ -425,6 +427,18 @@ class Wheel(object):
ap = to_posix(os.path.join(info_dir, 'WHEEL'))
archive_paths.append((ap, p))
+ # sort the entries by archive path. Not needed by any spec, but it
+ # keeps the archive listing and RECORD tidier than they would otherwise
+ # be. Use the number of path segments to keep directory entries together,
+ # and keep the dist-info stuff at the end.
+ def sorter(t):
+ ap = t[0]
+ n = ap.count('/')
+ if '.dist-info' in ap:
+ n += 10000
+ return (n, ap)
+ archive_paths = sorted(archive_paths, key=sorter)
+
# Now, at last, RECORD.
# Paths in here are archive paths - nothing else makes sense.
self.write_records((distinfo, info_dir), libdir, archive_paths)
@@ -476,7 +490,7 @@ class Wheel(object):
data_dir = '%s.data' % name_ver
info_dir = '%s.dist-info' % name_ver
- metadata_name = posixpath.join(info_dir, METADATA_FILENAME)
+ metadata_name = posixpath.join(info_dir, LEGACY_METADATA_FILENAME)
wheel_metadata_name = posixpath.join(info_dir, 'WHEEL')
record_name = posixpath.join(info_dir, 'RECORD')
@@ -619,7 +633,7 @@ class Wheel(object):
for v in epdata[k].values():
s = '%s:%s' % (v.prefix, v.suffix)
if v.flags:
- s += ' %s' % v.flags
+ s += ' [%s]' % ','.join(v.flags)
d[v.name] = s
except Exception:
logger.warning('Unable to read legacy script '
@@ -684,7 +698,7 @@ class Wheel(object):
if cache is None:
# Use native string to avoid issues on 2.x: see Python #20140.
base = os.path.join(get_cache_base(), str('dylib-cache'),
- sys.version[:3])
+ '%s.%s' % sys.version_info[:2])
cache = Cache(base)
return cache
@@ -773,7 +787,7 @@ class Wheel(object):
data_dir = '%s.data' % name_ver
info_dir = '%s.dist-info' % name_ver
- metadata_name = posixpath.join(info_dir, METADATA_FILENAME)
+ metadata_name = posixpath.join(info_dir, LEGACY_METADATA_FILENAME)
wheel_metadata_name = posixpath.join(info_dir, 'WHEEL')
record_name = posixpath.join(info_dir, 'RECORD')
@@ -842,7 +856,7 @@ class Wheel(object):
def get_version(path_map, info_dir):
version = path = None
- key = '%s/%s' % (info_dir, METADATA_FILENAME)
+ key = '%s/%s' % (info_dir, LEGACY_METADATA_FILENAME)
if key not in path_map:
key = '%s/PKG-INFO' % info_dir
if key in path_map:
@@ -868,7 +882,7 @@ class Wheel(object):
if updated:
md = Metadata(path=path)
md.version = updated
- legacy = not path.endswith(METADATA_FILENAME)
+ legacy = path.endswith(LEGACY_METADATA_FILENAME)
md.write(path=path, legacy=legacy)
logger.debug('Version updated from %r to %r', version,
updated)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/distro.py b/venv/lib/python3.8/site-packages/pip/_vendor/distro.py
index 3306163..0611b62 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/distro.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/distro.py
@@ -49,7 +49,7 @@ _OS_RELEASE_BASENAME = 'os-release'
#:
#: * Value: Normalized value.
NORMALIZED_OS_ID = {
- 'ol': 'oracle', # Oracle Enterprise Linux
+ 'ol': 'oracle', # Oracle Linux
}
#: Translation table for normalizing the "Distributor ID" attribute returned by
@@ -60,9 +60,11 @@ NORMALIZED_OS_ID = {
#:
#: * Value: Normalized value.
NORMALIZED_LSB_ID = {
- 'enterpriseenterprise': 'oracle', # Oracle Enterprise Linux
+ 'enterpriseenterpriseas': 'oracle', # Oracle Enterprise Linux 4
+ 'enterpriseenterpriseserver': 'oracle', # Oracle Linux 5
'redhatenterpriseworkstation': 'rhel', # RHEL 6, 7 Workstation
'redhatenterpriseserver': 'rhel', # RHEL 6, 7 Server
+ 'redhatenterprisecomputenode': 'rhel', # RHEL 6 ComputeNode
}
#: Translation table for normalizing the distro ID derived from the file name
@@ -90,7 +92,8 @@ _DISTRO_RELEASE_IGNORE_BASENAMES = (
'lsb-release',
'oem-release',
_OS_RELEASE_BASENAME,
- 'system-release'
+ 'system-release',
+ 'plesk-release',
)
@@ -163,6 +166,7 @@ def id():
"openbsd" OpenBSD
"netbsd" NetBSD
"freebsd" FreeBSD
+ "midnightbsd" MidnightBSD
============== =========================================
If you have a need to get distros for reliable IDs added into this set,
@@ -609,7 +613,7 @@ class LinuxDistribution(object):
distro release file can be found, the data source for the distro
release file will be empty.
- * ``include_name`` (bool): Controls whether uname command output is
+ * ``include_uname`` (bool): Controls whether uname command output is
included as a data source. If the uname command is not available in
the program execution path the data source for the uname command will
be empty.
@@ -757,7 +761,7 @@ class LinuxDistribution(object):
version = v
break
if pretty and version and self.codename():
- version = u'{0} ({1})'.format(version, self.codename())
+ version = '{0} ({1})'.format(version, self.codename())
return version
def version_parts(self, best=False):
@@ -967,8 +971,6 @@ class LinuxDistribution(object):
# * commands or their arguments (not allowed in os-release)
if '=' in token:
k, v = token.split('=', 1)
- if isinstance(v, bytes):
- v = v.decode('utf-8')
props[k.lower()] = v
else:
# Ignore any tokens that are not variable assignments
@@ -1012,7 +1014,7 @@ class LinuxDistribution(object):
stdout = subprocess.check_output(cmd, stderr=devnull)
except OSError: # Command not found
return {}
- content = stdout.decode(sys.getfilesystemencoding()).splitlines()
+ content = self._to_str(stdout).splitlines()
return self._parse_lsb_release_content(content)
@staticmethod
@@ -1047,7 +1049,7 @@ class LinuxDistribution(object):
stdout = subprocess.check_output(cmd, stderr=devnull)
except OSError:
return {}
- content = stdout.decode(sys.getfilesystemencoding()).splitlines()
+ content = self._to_str(stdout).splitlines()
return self._parse_uname_content(content)
@staticmethod
@@ -1067,6 +1069,20 @@ class LinuxDistribution(object):
props['release'] = version
return props
+ @staticmethod
+ def _to_str(text):
+ encoding = sys.getfilesystemencoding()
+ encoding = 'utf-8' if encoding == 'ascii' else encoding
+
+ if sys.version_info[0] >= 3:
+ if isinstance(text, bytes):
+ return text.decode(encoding)
+ else:
+ if isinstance(text, unicode): # noqa
+ return text.encode(encoding)
+
+ return text
+
@cached_property
def _distro_release_info(self):
"""
@@ -1169,8 +1185,6 @@ class LinuxDistribution(object):
Returns:
A dictionary containing all information items.
"""
- if isinstance(line, bytes):
- line = line.decode('utf-8')
matches = _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN.match(
line.strip()[::-1])
distro_info = {}
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__init__.py
index 0491234..d1d82f1 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__init__.py
@@ -32,4 +32,4 @@ __all__ = ["HTMLParser", "parse", "parseFragment", "getTreeBuilder",
# this has to be at the top level, see how setup.py parses this
#: Distribution version number.
-__version__ = "1.0.1"
+__version__ = "1.1"
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/__init__.cpython-38.pyc
index 630827e..16192b6 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/_ihatexml.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/_ihatexml.cpython-38.pyc
index 48015d2..064c992 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/_ihatexml.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/_ihatexml.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/_inputstream.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/_inputstream.cpython-38.pyc
index 36570fc..fbfcfb7 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/_inputstream.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/_inputstream.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/_tokenizer.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/_tokenizer.cpython-38.pyc
index 748619e..221325e 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/_tokenizer.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/_tokenizer.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/_utils.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/_utils.cpython-38.pyc
index 99f227b..24a22f3 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/_utils.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/_utils.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/constants.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/constants.cpython-38.pyc
index aa9cdfb..77cd32c 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/constants.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/constants.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/html5parser.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/html5parser.cpython-38.pyc
index fe60056..2782f90 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/html5parser.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/html5parser.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/serializer.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/serializer.cpython-38.pyc
index 5278980..bf5d56f 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/serializer.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/__pycache__/serializer.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_ihatexml.py b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_ihatexml.py
index 4c77717..3ff803c 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_ihatexml.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_ihatexml.py
@@ -136,6 +136,7 @@ def normaliseCharList(charList):
i += j
return rv
+
# We don't really support characters above the BMP :(
max_unicode = int("FFFF", 16)
@@ -254,7 +255,7 @@ class InfosetFilter(object):
nameRest = name[1:]
m = nonXmlNameFirstBMPRegexp.match(nameFirst)
if m:
- warnings.warn("Coercing non-XML name", DataLossWarning)
+ warnings.warn("Coercing non-XML name: %s" % name, DataLossWarning)
nameFirstOutput = self.getReplacementCharacter(nameFirst)
else:
nameFirstOutput = nameFirst
@@ -262,7 +263,7 @@ class InfosetFilter(object):
nameRestOutput = nameRest
replaceChars = set(nonXmlNameBMPRegexp.findall(nameRest))
for char in replaceChars:
- warnings.warn("Coercing non-XML name", DataLossWarning)
+ warnings.warn("Coercing non-XML name: %s" % name, DataLossWarning)
replacement = self.getReplacementCharacter(char)
nameRestOutput = nameRestOutput.replace(char, replacement)
return nameFirstOutput + nameRestOutput
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_inputstream.py b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_inputstream.py
index a65e55f..e0bb376 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_inputstream.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_inputstream.py
@@ -1,10 +1,11 @@
from __future__ import absolute_import, division, unicode_literals
-from pip._vendor.six import text_type, binary_type
+from pip._vendor.six import text_type
from pip._vendor.six.moves import http_client, urllib
import codecs
import re
+from io import BytesIO, StringIO
from pip._vendor import webencodings
@@ -12,13 +13,6 @@ from .constants import EOF, spaceCharacters, asciiLetters, asciiUppercase
from .constants import _ReparseException
from . import _utils
-from io import StringIO
-
-try:
- from io import BytesIO
-except ImportError:
- BytesIO = StringIO
-
# Non-unicode versions of constants for use in the pre-parser
spaceCharactersBytes = frozenset([item.encode("ascii") for item in spaceCharacters])
asciiLettersBytes = frozenset([item.encode("ascii") for item in asciiLetters])
@@ -40,13 +34,13 @@ if _utils.supports_lone_surrogates:
else:
invalid_unicode_re = re.compile(invalid_unicode_no_surrogate)
-non_bmp_invalid_codepoints = set([0x1FFFE, 0x1FFFF, 0x2FFFE, 0x2FFFF, 0x3FFFE,
- 0x3FFFF, 0x4FFFE, 0x4FFFF, 0x5FFFE, 0x5FFFF,
- 0x6FFFE, 0x6FFFF, 0x7FFFE, 0x7FFFF, 0x8FFFE,
- 0x8FFFF, 0x9FFFE, 0x9FFFF, 0xAFFFE, 0xAFFFF,
- 0xBFFFE, 0xBFFFF, 0xCFFFE, 0xCFFFF, 0xDFFFE,
- 0xDFFFF, 0xEFFFE, 0xEFFFF, 0xFFFFE, 0xFFFFF,
- 0x10FFFE, 0x10FFFF])
+non_bmp_invalid_codepoints = {0x1FFFE, 0x1FFFF, 0x2FFFE, 0x2FFFF, 0x3FFFE,
+ 0x3FFFF, 0x4FFFE, 0x4FFFF, 0x5FFFE, 0x5FFFF,
+ 0x6FFFE, 0x6FFFF, 0x7FFFE, 0x7FFFF, 0x8FFFE,
+ 0x8FFFF, 0x9FFFE, 0x9FFFF, 0xAFFFE, 0xAFFFF,
+ 0xBFFFE, 0xBFFFF, 0xCFFFE, 0xCFFFF, 0xDFFFE,
+ 0xDFFFF, 0xEFFFE, 0xEFFFF, 0xFFFFE, 0xFFFFF,
+ 0x10FFFE, 0x10FFFF}
ascii_punctuation_re = re.compile("[\u0009-\u000D\u0020-\u002F\u003A-\u0040\u005C\u005B-\u0060\u007B-\u007E]")
@@ -367,7 +361,7 @@ class HTMLUnicodeInputStream(object):
def unget(self, char):
# Only one character is allowed to be ungotten at once - it must
# be consumed again before any further call to unget
- if char is not None:
+ if char is not EOF:
if self.chunkOffset == 0:
# unget is called quite rarely, so it's a good idea to do
# more work here if it saves a bit of work in the frequently
@@ -449,7 +443,7 @@ class HTMLBinaryInputStream(HTMLUnicodeInputStream):
try:
stream.seek(stream.tell())
- except: # pylint:disable=bare-except
+ except Exception:
stream = BufferedStream(stream)
return stream
@@ -461,7 +455,7 @@ class HTMLBinaryInputStream(HTMLUnicodeInputStream):
if charEncoding[0] is not None:
return charEncoding
- # If we've been overriden, we've been overriden
+ # If we've been overridden, we've been overridden
charEncoding = lookupEncoding(self.override_encoding), "certain"
if charEncoding[0] is not None:
return charEncoding
@@ -664,9 +658,7 @@ class EncodingBytes(bytes):
"""Look for a sequence of bytes at the start of a string. If the bytes
are found return True and advance the position to the byte after the
match. Otherwise return False and leave the position alone"""
- p = self.position
- data = self[p:p + len(bytes)]
- rv = data.startswith(bytes)
+ rv = self.startswith(bytes, self.position)
if rv:
self.position += len(bytes)
return rv
@@ -674,15 +666,11 @@ class EncodingBytes(bytes):
def jumpTo(self, bytes):
"""Look for the next sequence of bytes matching a given sequence. If
a match is found advance the position to the last byte of the match"""
- newPosition = self[self.position:].find(bytes)
- if newPosition > -1:
- # XXX: This is ugly, but I can't see a nicer way to fix this.
- if self._position == -1:
- self._position = 0
- self._position += (newPosition + len(bytes) - 1)
- return True
- else:
+ try:
+ self._position = self.index(bytes, self.position) + len(bytes) - 1
+ except ValueError:
raise StopIteration
+ return True
class EncodingParser(object):
@@ -694,6 +682,9 @@ class EncodingParser(object):
self.encoding = None
def getEncoding(self):
+ if b" = (3, 7):
+ attributeMap = dict
+else:
+ attributeMap = OrderedDict
+
class HTMLTokenizer(object):
""" This class takes care of tokenizing HTML.
@@ -228,6 +234,14 @@ class HTMLTokenizer(object):
# Add token to the queue to be yielded
if (token["type"] in tagTokenTypes):
token["name"] = token["name"].translate(asciiUpper2Lower)
+ if token["type"] == tokenTypes["StartTag"]:
+ raw = token["data"]
+ data = attributeMap(raw)
+ if len(raw) > len(data):
+ # we had some duplicated attribute, fix so first wins
+ data.update(raw[::-1])
+ token["data"] = data
+
if token["type"] == tokenTypes["EndTag"]:
if token["data"]:
self.tokenQueue.append({"type": tokenTypes["ParseError"],
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__init__.py
index a5ba4bf..07bad5d 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__init__.py
@@ -1,14 +1,5 @@
from __future__ import absolute_import, division, unicode_literals
-from .py import Trie as PyTrie
+from .py import Trie
-Trie = PyTrie
-
-# pylint:disable=wrong-import-position
-try:
- from .datrie import Trie as DATrie
-except ImportError:
- pass
-else:
- Trie = DATrie
-# pylint:enable=wrong-import-position
+__all__ = ["Trie"]
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__pycache__/__init__.cpython-38.pyc
index 4efa34f..0ab091f 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__pycache__/_base.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__pycache__/_base.cpython-38.pyc
index 487202b..e66060d 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__pycache__/_base.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__pycache__/_base.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__pycache__/datrie.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__pycache__/datrie.cpython-38.pyc
deleted file mode 100644
index 058d54c..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__pycache__/datrie.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__pycache__/py.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__pycache__/py.cpython-38.pyc
index c326a44..1af14f5 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__pycache__/py.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/__pycache__/py.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/datrie.py b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/datrie.py
deleted file mode 100644
index e2e5f86..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_trie/datrie.py
+++ /dev/null
@@ -1,44 +0,0 @@
-from __future__ import absolute_import, division, unicode_literals
-
-from datrie import Trie as DATrie
-from pip._vendor.six import text_type
-
-from ._base import Trie as ABCTrie
-
-
-class Trie(ABCTrie):
- def __init__(self, data):
- chars = set()
- for key in data.keys():
- if not isinstance(key, text_type):
- raise TypeError("All keys must be strings")
- for char in key:
- chars.add(char)
-
- self._data = DATrie("".join(chars))
- for key, value in data.items():
- self._data[key] = value
-
- def __contains__(self, key):
- return key in self._data
-
- def __len__(self):
- return len(self._data)
-
- def __iter__(self):
- raise NotImplementedError()
-
- def __getitem__(self, key):
- return self._data[key]
-
- def keys(self, prefix=None):
- return self._data.keys(prefix)
-
- def has_keys_with_prefix(self, prefix):
- return self._data.has_keys_with_prefix(prefix)
-
- def longest_prefix(self, prefix):
- return self._data.longest_prefix(prefix)
-
- def longest_prefix_item(self, prefix):
- return self._data.longest_prefix_item(prefix)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_utils.py b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_utils.py
index 0703afb..d7c4926 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_utils.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/_utils.py
@@ -2,12 +2,20 @@ from __future__ import absolute_import, division, unicode_literals
from types import ModuleType
-from pip._vendor.six import text_type
-
try:
- import xml.etree.cElementTree as default_etree
+ from collections.abc import Mapping
except ImportError:
+ from collections import Mapping
+
+from pip._vendor.six import text_type, PY3
+
+if PY3:
import xml.etree.ElementTree as default_etree
+else:
+ try:
+ import xml.etree.cElementTree as default_etree
+ except ImportError:
+ import xml.etree.ElementTree as default_etree
__all__ = ["default_etree", "MethodDispatcher", "isSurrogatePair",
@@ -27,7 +35,7 @@ try:
# We need this with u"" because of http://bugs.jython.org/issue2039
_x = eval('u"\\uD800"') # pylint:disable=eval-used
assert isinstance(_x, text_type)
-except: # pylint:disable=bare-except
+except Exception:
supports_lone_surrogates = False
else:
supports_lone_surrogates = True
@@ -47,9 +55,6 @@ class MethodDispatcher(dict):
"""
def __init__(self, items=()):
- # Using _dictEntries instead of directly assigning to self is about
- # twice as fast. Please do careful performance testing before changing
- # anything here.
_dictEntries = []
for name, value in items:
if isinstance(name, (list, tuple, frozenset, set)):
@@ -64,6 +69,36 @@ class MethodDispatcher(dict):
def __getitem__(self, key):
return dict.get(self, key, self.default)
+ def __get__(self, instance, owner=None):
+ return BoundMethodDispatcher(instance, self)
+
+
+class BoundMethodDispatcher(Mapping):
+ """Wraps a MethodDispatcher, binding its return values to `instance`"""
+ def __init__(self, instance, dispatcher):
+ self.instance = instance
+ self.dispatcher = dispatcher
+
+ def __getitem__(self, key):
+ # see https://docs.python.org/3/reference/datamodel.html#object.__get__
+ # on a function, __get__ is used to bind a function to an instance as a bound method
+ return self.dispatcher[key].__get__(self.instance)
+
+ def get(self, key, default):
+ if key in self.dispatcher:
+ return self[key]
+ else:
+ return default
+
+ def __iter__(self):
+ return iter(self.dispatcher)
+
+ def __len__(self):
+ return len(self.dispatcher)
+
+ def __contains__(self, key):
+ return key in self.dispatcher
+
# Some utility functions to deal with weirdness around UCS2 vs UCS4
# python builds
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/constants.py b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/constants.py
index 1ff8041..fe3e237 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/constants.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/constants.py
@@ -519,8 +519,8 @@ adjustForeignAttributes = {
"xmlns:xlink": ("xmlns", "xlink", namespaces["xmlns"])
}
-unadjustForeignAttributes = dict([((ns, local), qname) for qname, (prefix, local, ns) in
- adjustForeignAttributes.items()])
+unadjustForeignAttributes = {(ns, local): qname for qname, (prefix, local, ns) in
+ adjustForeignAttributes.items()}
spaceCharacters = frozenset([
"\t",
@@ -544,8 +544,7 @@ asciiLetters = frozenset(string.ascii_letters)
digits = frozenset(string.digits)
hexDigits = frozenset(string.hexdigits)
-asciiUpper2Lower = dict([(ord(c), ord(c.lower()))
- for c in string.ascii_uppercase])
+asciiUpper2Lower = {ord(c): ord(c.lower()) for c in string.ascii_uppercase}
# Heading elements need to be ordered
headingElements = (
@@ -2934,7 +2933,7 @@ tagTokenTypes = frozenset([tokenTypes["StartTag"], tokenTypes["EndTag"],
tokenTypes["EmptyTag"]])
-prefixes = dict([(v, k) for k, v in namespaces.items()])
+prefixes = {v: k for k, v in namespaces.items()}
prefixes["http://www.w3.org/1998/Math/MathML"] = "math"
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/__init__.cpython-38.pyc
index af84a4d..ed38dfa 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/alphabeticalattributes.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/alphabeticalattributes.cpython-38.pyc
index ed1a3d2..7f322c5 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/alphabeticalattributes.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/alphabeticalattributes.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/base.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/base.cpython-38.pyc
index edc979c..c2829b4 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/base.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/base.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/inject_meta_charset.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/inject_meta_charset.cpython-38.pyc
index deb626f..d09bd02 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/inject_meta_charset.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/inject_meta_charset.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/lint.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/lint.cpython-38.pyc
index b0f0e20..9bd3426 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/lint.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/lint.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/optionaltags.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/optionaltags.cpython-38.pyc
index 898672a..7ecefd2 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/optionaltags.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/optionaltags.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/sanitizer.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/sanitizer.cpython-38.pyc
index 2723dcd..3a8ae9d 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/sanitizer.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/sanitizer.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/whitespace.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/whitespace.cpython-38.pyc
index 812ecc7..db459a1 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/whitespace.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/__pycache__/whitespace.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/sanitizer.py b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/sanitizer.py
index af8e77b..aa7431d 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/sanitizer.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/filters/sanitizer.py
@@ -1,6 +1,15 @@
+"""Deprecated from html5lib 1.1.
+
+See `here `_ for
+information about its deprecation; `Bleach `_
+is recommended as a replacement. Please let us know in the aforementioned issue
+if Bleach is unsuitable for your needs.
+
+"""
from __future__ import absolute_import, division, unicode_literals
import re
+import warnings
from xml.sax.saxutils import escape, unescape
from pip._vendor.six.moves import urllib_parse as urlparse
@@ -11,6 +20,14 @@ from ..constants import namespaces, prefixes
__all__ = ["Filter"]
+_deprecation_msg = (
+ "html5lib's sanitizer is deprecated; see " +
+ "https://github.com/html5lib/html5lib-python/issues/443 and please let " +
+ "us know if Bleach is unsuitable for your needs"
+)
+
+warnings.warn(_deprecation_msg, DeprecationWarning)
+
allowed_elements = frozenset((
(namespaces['html'], 'a'),
(namespaces['html'], 'abbr'),
@@ -750,6 +767,9 @@ class Filter(base.Filter):
"""
super(Filter, self).__init__(source)
+
+ warnings.warn(_deprecation_msg, DeprecationWarning)
+
self.allowed_elements = allowed_elements
self.allowed_attributes = allowed_attributes
self.allowed_css_properties = allowed_css_properties
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/html5parser.py b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/html5parser.py
index ae41a13..d06784f 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/html5parser.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/html5parser.py
@@ -2,7 +2,6 @@ from __future__ import absolute_import, division, unicode_literals
from pip._vendor.six import with_metaclass, viewkeys
import types
-from collections import OrderedDict
from . import _inputstream
from . import _tokenizer
@@ -119,8 +118,8 @@ class HTMLParser(object):
self.tree = tree(namespaceHTMLElements)
self.errors = []
- self.phases = dict([(name, cls(self, self.tree)) for name, cls in
- getPhases(debug).items()])
+ self.phases = {name: cls(self, self.tree) for name, cls in
+ getPhases(debug).items()}
def _parse(self, stream, innerHTML=False, container="div", scripting=False, **kwargs):
@@ -202,7 +201,7 @@ class HTMLParser(object):
DoctypeToken = tokenTypes["Doctype"]
ParseErrorToken = tokenTypes["ParseError"]
- for token in self.normalizedTokens():
+ for token in self.tokenizer:
prev_token = None
new_token = token
while new_token is not None:
@@ -260,10 +259,6 @@ class HTMLParser(object):
if reprocess:
assert self.phase not in phases
- def normalizedTokens(self):
- for token in self.tokenizer:
- yield self.normalizeToken(token)
-
def parse(self, stream, *args, **kwargs):
"""Parse a HTML document into a well-formed tree
@@ -325,17 +320,6 @@ class HTMLParser(object):
if self.strict:
raise ParseError(E[errorcode] % datavars)
- def normalizeToken(self, token):
- # HTML5 specific normalizations to the token stream
- if token["type"] == tokenTypes["StartTag"]:
- raw = token["data"]
- token["data"] = OrderedDict(raw)
- if len(raw) > len(token["data"]):
- # we had some duplicated attribute, fix so first wins
- token["data"].update(raw[::-1])
-
- return token
-
def adjustMathMLAttributes(self, token):
adjust_attributes(token, adjustMathMLAttributes)
@@ -413,16 +397,12 @@ class HTMLParser(object):
def getPhases(debug):
def log(function):
"""Logger that records which phase processes each token"""
- type_names = dict((value, key) for key, value in
- tokenTypes.items())
+ type_names = {value: key for key, value in tokenTypes.items()}
def wrapped(self, *args, **kwargs):
if function.__name__.startswith("process") and len(args) > 0:
token = args[0]
- try:
- info = {"type": type_names[token['type']]}
- except:
- raise
+ info = {"type": type_names[token['type']]}
if token['type'] in tagTokenTypes:
info["name"] = token['name']
@@ -446,10 +426,13 @@ def getPhases(debug):
class Phase(with_metaclass(getMetaclass(debug, log))):
"""Base class for helper object that implements each phase of processing
"""
+ __slots__ = ("parser", "tree", "__startTagCache", "__endTagCache")
def __init__(self, parser, tree):
self.parser = parser
self.tree = tree
+ self.__startTagCache = {}
+ self.__endTagCache = {}
def processEOF(self):
raise NotImplementedError
@@ -469,7 +452,21 @@ def getPhases(debug):
self.tree.insertText(token["data"])
def processStartTag(self, token):
- return self.startTagHandler[token["name"]](token)
+ # Note the caching is done here rather than BoundMethodDispatcher as doing it there
+ # requires a circular reference to the Phase, and this ends up with a significant
+ # (CPython 2.7, 3.8) GC cost when parsing many short inputs
+ name = token["name"]
+ # In Py2, using `in` is quicker in general than try/except KeyError
+ # In Py3, `in` is quicker when there are few cache hits (typically short inputs)
+ if name in self.__startTagCache:
+ func = self.__startTagCache[name]
+ else:
+ func = self.__startTagCache[name] = self.startTagHandler[name]
+ # bound the cache size in case we get loads of unknown tags
+ while len(self.__startTagCache) > len(self.startTagHandler) * 1.1:
+ # this makes the eviction policy random on Py < 3.7 and FIFO >= 3.7
+ self.__startTagCache.pop(next(iter(self.__startTagCache)))
+ return func(token)
def startTagHtml(self, token):
if not self.parser.firstStartTag and token["name"] == "html":
@@ -482,9 +479,25 @@ def getPhases(debug):
self.parser.firstStartTag = False
def processEndTag(self, token):
- return self.endTagHandler[token["name"]](token)
+ # Note the caching is done here rather than BoundMethodDispatcher as doing it there
+ # requires a circular reference to the Phase, and this ends up with a significant
+ # (CPython 2.7, 3.8) GC cost when parsing many short inputs
+ name = token["name"]
+ # In Py2, using `in` is quicker in general than try/except KeyError
+ # In Py3, `in` is quicker when there are few cache hits (typically short inputs)
+ if name in self.__endTagCache:
+ func = self.__endTagCache[name]
+ else:
+ func = self.__endTagCache[name] = self.endTagHandler[name]
+ # bound the cache size in case we get loads of unknown tags
+ while len(self.__endTagCache) > len(self.endTagHandler) * 1.1:
+ # this makes the eviction policy random on Py < 3.7 and FIFO >= 3.7
+ self.__endTagCache.pop(next(iter(self.__endTagCache)))
+ return func(token)
class InitialPhase(Phase):
+ __slots__ = tuple()
+
def processSpaceCharacters(self, token):
pass
@@ -613,6 +626,8 @@ def getPhases(debug):
return True
class BeforeHtmlPhase(Phase):
+ __slots__ = tuple()
+
# helper methods
def insertHtmlElement(self):
self.tree.insertRoot(impliedTagToken("html", "StartTag"))
@@ -648,19 +663,7 @@ def getPhases(debug):
return token
class BeforeHeadPhase(Phase):
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
-
- self.startTagHandler = _utils.MethodDispatcher([
- ("html", self.startTagHtml),
- ("head", self.startTagHead)
- ])
- self.startTagHandler.default = self.startTagOther
-
- self.endTagHandler = _utils.MethodDispatcher([
- (("head", "body", "html", "br"), self.endTagImplyHead)
- ])
- self.endTagHandler.default = self.endTagOther
+ __slots__ = tuple()
def processEOF(self):
self.startTagHead(impliedTagToken("head", "StartTag"))
@@ -693,28 +696,19 @@ def getPhases(debug):
self.parser.parseError("end-tag-after-implied-root",
{"name": token["name"]})
+ startTagHandler = _utils.MethodDispatcher([
+ ("html", startTagHtml),
+ ("head", startTagHead)
+ ])
+ startTagHandler.default = startTagOther
+
+ endTagHandler = _utils.MethodDispatcher([
+ (("head", "body", "html", "br"), endTagImplyHead)
+ ])
+ endTagHandler.default = endTagOther
+
class InHeadPhase(Phase):
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
-
- self.startTagHandler = _utils.MethodDispatcher([
- ("html", self.startTagHtml),
- ("title", self.startTagTitle),
- (("noframes", "style"), self.startTagNoFramesStyle),
- ("noscript", self.startTagNoscript),
- ("script", self.startTagScript),
- (("base", "basefont", "bgsound", "command", "link"),
- self.startTagBaseLinkCommand),
- ("meta", self.startTagMeta),
- ("head", self.startTagHead)
- ])
- self.startTagHandler.default = self.startTagOther
-
- self.endTagHandler = _utils.MethodDispatcher([
- ("head", self.endTagHead),
- (("br", "html", "body"), self.endTagHtmlBodyBr)
- ])
- self.endTagHandler.default = self.endTagOther
+ __slots__ = tuple()
# the real thing
def processEOF(self):
@@ -796,22 +790,27 @@ def getPhases(debug):
def anythingElse(self):
self.endTagHead(impliedTagToken("head"))
+ startTagHandler = _utils.MethodDispatcher([
+ ("html", startTagHtml),
+ ("title", startTagTitle),
+ (("noframes", "style"), startTagNoFramesStyle),
+ ("noscript", startTagNoscript),
+ ("script", startTagScript),
+ (("base", "basefont", "bgsound", "command", "link"),
+ startTagBaseLinkCommand),
+ ("meta", startTagMeta),
+ ("head", startTagHead)
+ ])
+ startTagHandler.default = startTagOther
+
+ endTagHandler = _utils.MethodDispatcher([
+ ("head", endTagHead),
+ (("br", "html", "body"), endTagHtmlBodyBr)
+ ])
+ endTagHandler.default = endTagOther
+
class InHeadNoscriptPhase(Phase):
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
-
- self.startTagHandler = _utils.MethodDispatcher([
- ("html", self.startTagHtml),
- (("basefont", "bgsound", "link", "meta", "noframes", "style"), self.startTagBaseLinkCommand),
- (("head", "noscript"), self.startTagHeadNoscript),
- ])
- self.startTagHandler.default = self.startTagOther
-
- self.endTagHandler = _utils.MethodDispatcher([
- ("noscript", self.endTagNoscript),
- ("br", self.endTagBr),
- ])
- self.endTagHandler.default = self.endTagOther
+ __slots__ = tuple()
def processEOF(self):
self.parser.parseError("eof-in-head-noscript")
@@ -860,23 +859,21 @@ def getPhases(debug):
# Caller must raise parse error first!
self.endTagNoscript(impliedTagToken("noscript"))
- class AfterHeadPhase(Phase):
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
+ startTagHandler = _utils.MethodDispatcher([
+ ("html", startTagHtml),
+ (("basefont", "bgsound", "link", "meta", "noframes", "style"), startTagBaseLinkCommand),
+ (("head", "noscript"), startTagHeadNoscript),
+ ])
+ startTagHandler.default = startTagOther
- self.startTagHandler = _utils.MethodDispatcher([
- ("html", self.startTagHtml),
- ("body", self.startTagBody),
- ("frameset", self.startTagFrameset),
- (("base", "basefont", "bgsound", "link", "meta", "noframes", "script",
- "style", "title"),
- self.startTagFromHead),
- ("head", self.startTagHead)
- ])
- self.startTagHandler.default = self.startTagOther
- self.endTagHandler = _utils.MethodDispatcher([(("body", "html", "br"),
- self.endTagHtmlBodyBr)])
- self.endTagHandler.default = self.endTagOther
+ endTagHandler = _utils.MethodDispatcher([
+ ("noscript", endTagNoscript),
+ ("br", endTagBr),
+ ])
+ endTagHandler.default = endTagOther
+
+ class AfterHeadPhase(Phase):
+ __slots__ = tuple()
def processEOF(self):
self.anythingElse()
@@ -927,80 +924,30 @@ def getPhases(debug):
self.parser.phase = self.parser.phases["inBody"]
self.parser.framesetOK = True
+ startTagHandler = _utils.MethodDispatcher([
+ ("html", startTagHtml),
+ ("body", startTagBody),
+ ("frameset", startTagFrameset),
+ (("base", "basefont", "bgsound", "link", "meta", "noframes", "script",
+ "style", "title"),
+ startTagFromHead),
+ ("head", startTagHead)
+ ])
+ startTagHandler.default = startTagOther
+ endTagHandler = _utils.MethodDispatcher([(("body", "html", "br"),
+ endTagHtmlBodyBr)])
+ endTagHandler.default = endTagOther
+
class InBodyPhase(Phase):
# http://www.whatwg.org/specs/web-apps/current-work/#parsing-main-inbody
# the really-really-really-very crazy mode
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
+ __slots__ = ("processSpaceCharacters",)
+ def __init__(self, *args, **kwargs):
+ super(InBodyPhase, self).__init__(*args, **kwargs)
# Set this to the default handler
self.processSpaceCharacters = self.processSpaceCharactersNonPre
- self.startTagHandler = _utils.MethodDispatcher([
- ("html", self.startTagHtml),
- (("base", "basefont", "bgsound", "command", "link", "meta",
- "script", "style", "title"),
- self.startTagProcessInHead),
- ("body", self.startTagBody),
- ("frameset", self.startTagFrameset),
- (("address", "article", "aside", "blockquote", "center", "details",
- "dir", "div", "dl", "fieldset", "figcaption", "figure",
- "footer", "header", "hgroup", "main", "menu", "nav", "ol", "p",
- "section", "summary", "ul"),
- self.startTagCloseP),
- (headingElements, self.startTagHeading),
- (("pre", "listing"), self.startTagPreListing),
- ("form", self.startTagForm),
- (("li", "dd", "dt"), self.startTagListItem),
- ("plaintext", self.startTagPlaintext),
- ("a", self.startTagA),
- (("b", "big", "code", "em", "font", "i", "s", "small", "strike",
- "strong", "tt", "u"), self.startTagFormatting),
- ("nobr", self.startTagNobr),
- ("button", self.startTagButton),
- (("applet", "marquee", "object"), self.startTagAppletMarqueeObject),
- ("xmp", self.startTagXmp),
- ("table", self.startTagTable),
- (("area", "br", "embed", "img", "keygen", "wbr"),
- self.startTagVoidFormatting),
- (("param", "source", "track"), self.startTagParamSource),
- ("input", self.startTagInput),
- ("hr", self.startTagHr),
- ("image", self.startTagImage),
- ("isindex", self.startTagIsIndex),
- ("textarea", self.startTagTextarea),
- ("iframe", self.startTagIFrame),
- ("noscript", self.startTagNoscript),
- (("noembed", "noframes"), self.startTagRawtext),
- ("select", self.startTagSelect),
- (("rp", "rt"), self.startTagRpRt),
- (("option", "optgroup"), self.startTagOpt),
- (("math"), self.startTagMath),
- (("svg"), self.startTagSvg),
- (("caption", "col", "colgroup", "frame", "head",
- "tbody", "td", "tfoot", "th", "thead",
- "tr"), self.startTagMisplaced)
- ])
- self.startTagHandler.default = self.startTagOther
-
- self.endTagHandler = _utils.MethodDispatcher([
- ("body", self.endTagBody),
- ("html", self.endTagHtml),
- (("address", "article", "aside", "blockquote", "button", "center",
- "details", "dialog", "dir", "div", "dl", "fieldset", "figcaption", "figure",
- "footer", "header", "hgroup", "listing", "main", "menu", "nav", "ol", "pre",
- "section", "summary", "ul"), self.endTagBlock),
- ("form", self.endTagForm),
- ("p", self.endTagP),
- (("dd", "dt", "li"), self.endTagListItem),
- (headingElements, self.endTagHeading),
- (("a", "b", "big", "code", "em", "font", "i", "nobr", "s", "small",
- "strike", "strong", "tt", "u"), self.endTagFormatting),
- (("applet", "marquee", "object"), self.endTagAppletMarqueeObject),
- ("br", self.endTagBr),
- ])
- self.endTagHandler.default = self.endTagOther
-
def isMatchingFormattingElement(self, node1, node2):
return (node1.name == node2.name and
node1.namespace == node2.namespace and
@@ -1650,14 +1597,73 @@ def getPhases(debug):
self.parser.parseError("unexpected-end-tag", {"name": token["name"]})
break
+ startTagHandler = _utils.MethodDispatcher([
+ ("html", Phase.startTagHtml),
+ (("base", "basefont", "bgsound", "command", "link", "meta",
+ "script", "style", "title"),
+ startTagProcessInHead),
+ ("body", startTagBody),
+ ("frameset", startTagFrameset),
+ (("address", "article", "aside", "blockquote", "center", "details",
+ "dir", "div", "dl", "fieldset", "figcaption", "figure",
+ "footer", "header", "hgroup", "main", "menu", "nav", "ol", "p",
+ "section", "summary", "ul"),
+ startTagCloseP),
+ (headingElements, startTagHeading),
+ (("pre", "listing"), startTagPreListing),
+ ("form", startTagForm),
+ (("li", "dd", "dt"), startTagListItem),
+ ("plaintext", startTagPlaintext),
+ ("a", startTagA),
+ (("b", "big", "code", "em", "font", "i", "s", "small", "strike",
+ "strong", "tt", "u"), startTagFormatting),
+ ("nobr", startTagNobr),
+ ("button", startTagButton),
+ (("applet", "marquee", "object"), startTagAppletMarqueeObject),
+ ("xmp", startTagXmp),
+ ("table", startTagTable),
+ (("area", "br", "embed", "img", "keygen", "wbr"),
+ startTagVoidFormatting),
+ (("param", "source", "track"), startTagParamSource),
+ ("input", startTagInput),
+ ("hr", startTagHr),
+ ("image", startTagImage),
+ ("isindex", startTagIsIndex),
+ ("textarea", startTagTextarea),
+ ("iframe", startTagIFrame),
+ ("noscript", startTagNoscript),
+ (("noembed", "noframes"), startTagRawtext),
+ ("select", startTagSelect),
+ (("rp", "rt"), startTagRpRt),
+ (("option", "optgroup"), startTagOpt),
+ (("math"), startTagMath),
+ (("svg"), startTagSvg),
+ (("caption", "col", "colgroup", "frame", "head",
+ "tbody", "td", "tfoot", "th", "thead",
+ "tr"), startTagMisplaced)
+ ])
+ startTagHandler.default = startTagOther
+
+ endTagHandler = _utils.MethodDispatcher([
+ ("body", endTagBody),
+ ("html", endTagHtml),
+ (("address", "article", "aside", "blockquote", "button", "center",
+ "details", "dialog", "dir", "div", "dl", "fieldset", "figcaption", "figure",
+ "footer", "header", "hgroup", "listing", "main", "menu", "nav", "ol", "pre",
+ "section", "summary", "ul"), endTagBlock),
+ ("form", endTagForm),
+ ("p", endTagP),
+ (("dd", "dt", "li"), endTagListItem),
+ (headingElements, endTagHeading),
+ (("a", "b", "big", "code", "em", "font", "i", "nobr", "s", "small",
+ "strike", "strong", "tt", "u"), endTagFormatting),
+ (("applet", "marquee", "object"), endTagAppletMarqueeObject),
+ ("br", endTagBr),
+ ])
+ endTagHandler.default = endTagOther
+
class TextPhase(Phase):
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
- self.startTagHandler = _utils.MethodDispatcher([])
- self.startTagHandler.default = self.startTagOther
- self.endTagHandler = _utils.MethodDispatcher([
- ("script", self.endTagScript)])
- self.endTagHandler.default = self.endTagOther
+ __slots__ = tuple()
def processCharacters(self, token):
self.tree.insertText(token["data"])
@@ -1683,30 +1689,15 @@ def getPhases(debug):
self.tree.openElements.pop()
self.parser.phase = self.parser.originalPhase
+ startTagHandler = _utils.MethodDispatcher([])
+ startTagHandler.default = startTagOther
+ endTagHandler = _utils.MethodDispatcher([
+ ("script", endTagScript)])
+ endTagHandler.default = endTagOther
+
class InTablePhase(Phase):
# http://www.whatwg.org/specs/web-apps/current-work/#in-table
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
- self.startTagHandler = _utils.MethodDispatcher([
- ("html", self.startTagHtml),
- ("caption", self.startTagCaption),
- ("colgroup", self.startTagColgroup),
- ("col", self.startTagCol),
- (("tbody", "tfoot", "thead"), self.startTagRowGroup),
- (("td", "th", "tr"), self.startTagImplyTbody),
- ("table", self.startTagTable),
- (("style", "script"), self.startTagStyleScript),
- ("input", self.startTagInput),
- ("form", self.startTagForm)
- ])
- self.startTagHandler.default = self.startTagOther
-
- self.endTagHandler = _utils.MethodDispatcher([
- ("table", self.endTagTable),
- (("body", "caption", "col", "colgroup", "html", "tbody", "td",
- "tfoot", "th", "thead", "tr"), self.endTagIgnore)
- ])
- self.endTagHandler.default = self.endTagOther
+ __slots__ = tuple()
# helper methods
def clearStackToTableContext(self):
@@ -1828,9 +1819,32 @@ def getPhases(debug):
self.parser.phases["inBody"].processEndTag(token)
self.tree.insertFromTable = False
+ startTagHandler = _utils.MethodDispatcher([
+ ("html", Phase.startTagHtml),
+ ("caption", startTagCaption),
+ ("colgroup", startTagColgroup),
+ ("col", startTagCol),
+ (("tbody", "tfoot", "thead"), startTagRowGroup),
+ (("td", "th", "tr"), startTagImplyTbody),
+ ("table", startTagTable),
+ (("style", "script"), startTagStyleScript),
+ ("input", startTagInput),
+ ("form", startTagForm)
+ ])
+ startTagHandler.default = startTagOther
+
+ endTagHandler = _utils.MethodDispatcher([
+ ("table", endTagTable),
+ (("body", "caption", "col", "colgroup", "html", "tbody", "td",
+ "tfoot", "th", "thead", "tr"), endTagIgnore)
+ ])
+ endTagHandler.default = endTagOther
+
class InTableTextPhase(Phase):
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
+ __slots__ = ("originalPhase", "characterTokens")
+
+ def __init__(self, *args, **kwargs):
+ super(InTableTextPhase, self).__init__(*args, **kwargs)
self.originalPhase = None
self.characterTokens = []
@@ -1875,23 +1889,7 @@ def getPhases(debug):
class InCaptionPhase(Phase):
# http://www.whatwg.org/specs/web-apps/current-work/#in-caption
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
-
- self.startTagHandler = _utils.MethodDispatcher([
- ("html", self.startTagHtml),
- (("caption", "col", "colgroup", "tbody", "td", "tfoot", "th",
- "thead", "tr"), self.startTagTableElement)
- ])
- self.startTagHandler.default = self.startTagOther
-
- self.endTagHandler = _utils.MethodDispatcher([
- ("caption", self.endTagCaption),
- ("table", self.endTagTable),
- (("body", "col", "colgroup", "html", "tbody", "td", "tfoot", "th",
- "thead", "tr"), self.endTagIgnore)
- ])
- self.endTagHandler.default = self.endTagOther
+ __slots__ = tuple()
def ignoreEndTagCaption(self):
return not self.tree.elementInScope("caption", variant="table")
@@ -1944,23 +1942,24 @@ def getPhases(debug):
def endTagOther(self, token):
return self.parser.phases["inBody"].processEndTag(token)
+ startTagHandler = _utils.MethodDispatcher([
+ ("html", Phase.startTagHtml),
+ (("caption", "col", "colgroup", "tbody", "td", "tfoot", "th",
+ "thead", "tr"), startTagTableElement)
+ ])
+ startTagHandler.default = startTagOther
+
+ endTagHandler = _utils.MethodDispatcher([
+ ("caption", endTagCaption),
+ ("table", endTagTable),
+ (("body", "col", "colgroup", "html", "tbody", "td", "tfoot", "th",
+ "thead", "tr"), endTagIgnore)
+ ])
+ endTagHandler.default = endTagOther
+
class InColumnGroupPhase(Phase):
# http://www.whatwg.org/specs/web-apps/current-work/#in-column
-
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
-
- self.startTagHandler = _utils.MethodDispatcher([
- ("html", self.startTagHtml),
- ("col", self.startTagCol)
- ])
- self.startTagHandler.default = self.startTagOther
-
- self.endTagHandler = _utils.MethodDispatcher([
- ("colgroup", self.endTagColgroup),
- ("col", self.endTagCol)
- ])
- self.endTagHandler.default = self.endTagOther
+ __slots__ = tuple()
def ignoreEndTagColgroup(self):
return self.tree.openElements[-1].name == "html"
@@ -2010,26 +2009,21 @@ def getPhases(debug):
if not ignoreEndTag:
return token
+ startTagHandler = _utils.MethodDispatcher([
+ ("html", Phase.startTagHtml),
+ ("col", startTagCol)
+ ])
+ startTagHandler.default = startTagOther
+
+ endTagHandler = _utils.MethodDispatcher([
+ ("colgroup", endTagColgroup),
+ ("col", endTagCol)
+ ])
+ endTagHandler.default = endTagOther
+
class InTableBodyPhase(Phase):
# http://www.whatwg.org/specs/web-apps/current-work/#in-table0
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
- self.startTagHandler = _utils.MethodDispatcher([
- ("html", self.startTagHtml),
- ("tr", self.startTagTr),
- (("td", "th"), self.startTagTableCell),
- (("caption", "col", "colgroup", "tbody", "tfoot", "thead"),
- self.startTagTableOther)
- ])
- self.startTagHandler.default = self.startTagOther
-
- self.endTagHandler = _utils.MethodDispatcher([
- (("tbody", "tfoot", "thead"), self.endTagTableRowGroup),
- ("table", self.endTagTable),
- (("body", "caption", "col", "colgroup", "html", "td", "th",
- "tr"), self.endTagIgnore)
- ])
- self.endTagHandler.default = self.endTagOther
+ __slots__ = tuple()
# helper methods
def clearStackToTableBodyContext(self):
@@ -2108,26 +2102,26 @@ def getPhases(debug):
def endTagOther(self, token):
return self.parser.phases["inTable"].processEndTag(token)
+ startTagHandler = _utils.MethodDispatcher([
+ ("html", Phase.startTagHtml),
+ ("tr", startTagTr),
+ (("td", "th"), startTagTableCell),
+ (("caption", "col", "colgroup", "tbody", "tfoot", "thead"),
+ startTagTableOther)
+ ])
+ startTagHandler.default = startTagOther
+
+ endTagHandler = _utils.MethodDispatcher([
+ (("tbody", "tfoot", "thead"), endTagTableRowGroup),
+ ("table", endTagTable),
+ (("body", "caption", "col", "colgroup", "html", "td", "th",
+ "tr"), endTagIgnore)
+ ])
+ endTagHandler.default = endTagOther
+
class InRowPhase(Phase):
# http://www.whatwg.org/specs/web-apps/current-work/#in-row
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
- self.startTagHandler = _utils.MethodDispatcher([
- ("html", self.startTagHtml),
- (("td", "th"), self.startTagTableCell),
- (("caption", "col", "colgroup", "tbody", "tfoot", "thead",
- "tr"), self.startTagTableOther)
- ])
- self.startTagHandler.default = self.startTagOther
-
- self.endTagHandler = _utils.MethodDispatcher([
- ("tr", self.endTagTr),
- ("table", self.endTagTable),
- (("tbody", "tfoot", "thead"), self.endTagTableRowGroup),
- (("body", "caption", "col", "colgroup", "html", "td", "th"),
- self.endTagIgnore)
- ])
- self.endTagHandler.default = self.endTagOther
+ __slots__ = tuple()
# helper methods (XXX unify this with other table helper methods)
def clearStackToTableRowContext(self):
@@ -2197,23 +2191,26 @@ def getPhases(debug):
def endTagOther(self, token):
return self.parser.phases["inTable"].processEndTag(token)
+ startTagHandler = _utils.MethodDispatcher([
+ ("html", Phase.startTagHtml),
+ (("td", "th"), startTagTableCell),
+ (("caption", "col", "colgroup", "tbody", "tfoot", "thead",
+ "tr"), startTagTableOther)
+ ])
+ startTagHandler.default = startTagOther
+
+ endTagHandler = _utils.MethodDispatcher([
+ ("tr", endTagTr),
+ ("table", endTagTable),
+ (("tbody", "tfoot", "thead"), endTagTableRowGroup),
+ (("body", "caption", "col", "colgroup", "html", "td", "th"),
+ endTagIgnore)
+ ])
+ endTagHandler.default = endTagOther
+
class InCellPhase(Phase):
# http://www.whatwg.org/specs/web-apps/current-work/#in-cell
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
- self.startTagHandler = _utils.MethodDispatcher([
- ("html", self.startTagHtml),
- (("caption", "col", "colgroup", "tbody", "td", "tfoot", "th",
- "thead", "tr"), self.startTagTableOther)
- ])
- self.startTagHandler.default = self.startTagOther
-
- self.endTagHandler = _utils.MethodDispatcher([
- (("td", "th"), self.endTagTableCell),
- (("body", "caption", "col", "colgroup", "html"), self.endTagIgnore),
- (("table", "tbody", "tfoot", "thead", "tr"), self.endTagImply)
- ])
- self.endTagHandler.default = self.endTagOther
+ __slots__ = tuple()
# helper
def closeCell(self):
@@ -2273,26 +2270,22 @@ def getPhases(debug):
def endTagOther(self, token):
return self.parser.phases["inBody"].processEndTag(token)
+ startTagHandler = _utils.MethodDispatcher([
+ ("html", Phase.startTagHtml),
+ (("caption", "col", "colgroup", "tbody", "td", "tfoot", "th",
+ "thead", "tr"), startTagTableOther)
+ ])
+ startTagHandler.default = startTagOther
+
+ endTagHandler = _utils.MethodDispatcher([
+ (("td", "th"), endTagTableCell),
+ (("body", "caption", "col", "colgroup", "html"), endTagIgnore),
+ (("table", "tbody", "tfoot", "thead", "tr"), endTagImply)
+ ])
+ endTagHandler.default = endTagOther
+
class InSelectPhase(Phase):
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
-
- self.startTagHandler = _utils.MethodDispatcher([
- ("html", self.startTagHtml),
- ("option", self.startTagOption),
- ("optgroup", self.startTagOptgroup),
- ("select", self.startTagSelect),
- (("input", "keygen", "textarea"), self.startTagInput),
- ("script", self.startTagScript)
- ])
- self.startTagHandler.default = self.startTagOther
-
- self.endTagHandler = _utils.MethodDispatcher([
- ("option", self.endTagOption),
- ("optgroup", self.endTagOptgroup),
- ("select", self.endTagSelect)
- ])
- self.endTagHandler.default = self.endTagOther
+ __slots__ = tuple()
# http://www.whatwg.org/specs/web-apps/current-work/#in-select
def processEOF(self):
@@ -2373,21 +2366,25 @@ def getPhases(debug):
self.parser.parseError("unexpected-end-tag-in-select",
{"name": token["name"]})
+ startTagHandler = _utils.MethodDispatcher([
+ ("html", Phase.startTagHtml),
+ ("option", startTagOption),
+ ("optgroup", startTagOptgroup),
+ ("select", startTagSelect),
+ (("input", "keygen", "textarea"), startTagInput),
+ ("script", startTagScript)
+ ])
+ startTagHandler.default = startTagOther
+
+ endTagHandler = _utils.MethodDispatcher([
+ ("option", endTagOption),
+ ("optgroup", endTagOptgroup),
+ ("select", endTagSelect)
+ ])
+ endTagHandler.default = endTagOther
+
class InSelectInTablePhase(Phase):
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
-
- self.startTagHandler = _utils.MethodDispatcher([
- (("caption", "table", "tbody", "tfoot", "thead", "tr", "td", "th"),
- self.startTagTable)
- ])
- self.startTagHandler.default = self.startTagOther
-
- self.endTagHandler = _utils.MethodDispatcher([
- (("caption", "table", "tbody", "tfoot", "thead", "tr", "td", "th"),
- self.endTagTable)
- ])
- self.endTagHandler.default = self.endTagOther
+ __slots__ = tuple()
def processEOF(self):
self.parser.phases["inSelect"].processEOF()
@@ -2412,7 +2409,21 @@ def getPhases(debug):
def endTagOther(self, token):
return self.parser.phases["inSelect"].processEndTag(token)
+ startTagHandler = _utils.MethodDispatcher([
+ (("caption", "table", "tbody", "tfoot", "thead", "tr", "td", "th"),
+ startTagTable)
+ ])
+ startTagHandler.default = startTagOther
+
+ endTagHandler = _utils.MethodDispatcher([
+ (("caption", "table", "tbody", "tfoot", "thead", "tr", "td", "th"),
+ endTagTable)
+ ])
+ endTagHandler.default = endTagOther
+
class InForeignContentPhase(Phase):
+ __slots__ = tuple()
+
breakoutElements = frozenset(["b", "big", "blockquote", "body", "br",
"center", "code", "dd", "div", "dl", "dt",
"em", "embed", "h1", "h2", "h3",
@@ -2422,9 +2433,6 @@ def getPhases(debug):
"span", "strong", "strike", "sub", "sup",
"table", "tt", "u", "ul", "var"])
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
-
def adjustSVGTagNames(self, token):
replacements = {"altglyph": "altGlyph",
"altglyphdef": "altGlyphDef",
@@ -2478,7 +2486,7 @@ def getPhases(debug):
currentNode = self.tree.openElements[-1]
if (token["name"] in self.breakoutElements or
(token["name"] == "font" and
- set(token["data"].keys()) & set(["color", "face", "size"]))):
+ set(token["data"].keys()) & {"color", "face", "size"})):
self.parser.parseError("unexpected-html-element-in-foreign-content",
{"name": token["name"]})
while (self.tree.openElements[-1].namespace !=
@@ -2528,16 +2536,7 @@ def getPhases(debug):
return new_token
class AfterBodyPhase(Phase):
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
-
- self.startTagHandler = _utils.MethodDispatcher([
- ("html", self.startTagHtml)
- ])
- self.startTagHandler.default = self.startTagOther
-
- self.endTagHandler = _utils.MethodDispatcher([("html", self.endTagHtml)])
- self.endTagHandler.default = self.endTagOther
+ __slots__ = tuple()
def processEOF(self):
# Stop parsing
@@ -2574,23 +2573,17 @@ def getPhases(debug):
self.parser.phase = self.parser.phases["inBody"]
return token
+ startTagHandler = _utils.MethodDispatcher([
+ ("html", startTagHtml)
+ ])
+ startTagHandler.default = startTagOther
+
+ endTagHandler = _utils.MethodDispatcher([("html", endTagHtml)])
+ endTagHandler.default = endTagOther
+
class InFramesetPhase(Phase):
# http://www.whatwg.org/specs/web-apps/current-work/#in-frameset
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
-
- self.startTagHandler = _utils.MethodDispatcher([
- ("html", self.startTagHtml),
- ("frameset", self.startTagFrameset),
- ("frame", self.startTagFrame),
- ("noframes", self.startTagNoframes)
- ])
- self.startTagHandler.default = self.startTagOther
-
- self.endTagHandler = _utils.MethodDispatcher([
- ("frameset", self.endTagFrameset)
- ])
- self.endTagHandler.default = self.endTagOther
+ __slots__ = tuple()
def processEOF(self):
if self.tree.openElements[-1].name != "html":
@@ -2631,21 +2624,22 @@ def getPhases(debug):
self.parser.parseError("unexpected-end-tag-in-frameset",
{"name": token["name"]})
+ startTagHandler = _utils.MethodDispatcher([
+ ("html", Phase.startTagHtml),
+ ("frameset", startTagFrameset),
+ ("frame", startTagFrame),
+ ("noframes", startTagNoframes)
+ ])
+ startTagHandler.default = startTagOther
+
+ endTagHandler = _utils.MethodDispatcher([
+ ("frameset", endTagFrameset)
+ ])
+ endTagHandler.default = endTagOther
+
class AfterFramesetPhase(Phase):
# http://www.whatwg.org/specs/web-apps/current-work/#after3
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
-
- self.startTagHandler = _utils.MethodDispatcher([
- ("html", self.startTagHtml),
- ("noframes", self.startTagNoframes)
- ])
- self.startTagHandler.default = self.startTagOther
-
- self.endTagHandler = _utils.MethodDispatcher([
- ("html", self.endTagHtml)
- ])
- self.endTagHandler.default = self.endTagOther
+ __slots__ = tuple()
def processEOF(self):
# Stop parsing
@@ -2668,14 +2662,19 @@ def getPhases(debug):
self.parser.parseError("unexpected-end-tag-after-frameset",
{"name": token["name"]})
- class AfterAfterBodyPhase(Phase):
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
+ startTagHandler = _utils.MethodDispatcher([
+ ("html", Phase.startTagHtml),
+ ("noframes", startTagNoframes)
+ ])
+ startTagHandler.default = startTagOther
- self.startTagHandler = _utils.MethodDispatcher([
- ("html", self.startTagHtml)
- ])
- self.startTagHandler.default = self.startTagOther
+ endTagHandler = _utils.MethodDispatcher([
+ ("html", endTagHtml)
+ ])
+ endTagHandler.default = endTagOther
+
+ class AfterAfterBodyPhase(Phase):
+ __slots__ = tuple()
def processEOF(self):
pass
@@ -2706,15 +2705,13 @@ def getPhases(debug):
self.parser.phase = self.parser.phases["inBody"]
return token
- class AfterAfterFramesetPhase(Phase):
- def __init__(self, parser, tree):
- Phase.__init__(self, parser, tree)
+ startTagHandler = _utils.MethodDispatcher([
+ ("html", startTagHtml)
+ ])
+ startTagHandler.default = startTagOther
- self.startTagHandler = _utils.MethodDispatcher([
- ("html", self.startTagHtml),
- ("noframes", self.startTagNoFrames)
- ])
- self.startTagHandler.default = self.startTagOther
+ class AfterAfterFramesetPhase(Phase):
+ __slots__ = tuple()
def processEOF(self):
pass
@@ -2741,6 +2738,13 @@ def getPhases(debug):
def processEndTag(self, token):
self.parser.parseError("expected-eof-but-got-end-tag",
{"name": token["name"]})
+
+ startTagHandler = _utils.MethodDispatcher([
+ ("html", startTagHtml),
+ ("noframes", startTagNoFrames)
+ ])
+ startTagHandler.default = startTagOther
+
# pylint:enable=unused-argument
return {
@@ -2774,8 +2778,8 @@ def getPhases(debug):
def adjust_attributes(token, replacements):
needs_adjustment = viewkeys(token['data']) & viewkeys(replacements)
if needs_adjustment:
- token['data'] = OrderedDict((replacements.get(k, k), v)
- for k, v in token['data'].items())
+ token['data'] = type(token['data'])((replacements.get(k, k), v)
+ for k, v in token['data'].items())
def impliedTagToken(name, type="EndTag", attributes=None,
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/serializer.py b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/serializer.py
index 53f4d44..d5669d8 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/serializer.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/serializer.py
@@ -274,7 +274,7 @@ class HTMLSerializer(object):
if token["systemId"]:
if token["systemId"].find('"') >= 0:
if token["systemId"].find("'") >= 0:
- self.serializeError("System identifer contains both single and double quote characters")
+ self.serializeError("System identifier contains both single and double quote characters")
quote_char = "'"
else:
quote_char = '"'
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treeadapters/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treeadapters/__pycache__/__init__.cpython-38.pyc
index e0424d5..112b8d6 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treeadapters/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treeadapters/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treeadapters/__pycache__/genshi.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treeadapters/__pycache__/genshi.cpython-38.pyc
index 72b06b4..5aa2992 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treeadapters/__pycache__/genshi.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treeadapters/__pycache__/genshi.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treeadapters/__pycache__/sax.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treeadapters/__pycache__/sax.cpython-38.pyc
index 6979244..0cffd9c 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treeadapters/__pycache__/sax.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treeadapters/__pycache__/sax.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/__init__.cpython-38.pyc
index 8d5aaab..81d4748 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/base.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/base.cpython-38.pyc
index 0bbf798..f235e7c 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/base.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/base.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/dom.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/dom.cpython-38.pyc
index 6e587cd..2a10a3f 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/dom.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/dom.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/etree.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/etree.cpython-38.pyc
index 7515947..abdc5b1 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/etree.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/etree.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/etree_lxml.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/etree_lxml.cpython-38.pyc
index f229e3d..75a8392 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/etree_lxml.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/etree_lxml.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/base.py b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/base.py
index 73973db..965fce2 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/base.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/base.py
@@ -10,9 +10,9 @@ Marker = None
listElementsMap = {
None: (frozenset(scopingElements), False),
- "button": (frozenset(scopingElements | set([(namespaces["html"], "button")])), False),
- "list": (frozenset(scopingElements | set([(namespaces["html"], "ol"),
- (namespaces["html"], "ul")])), False),
+ "button": (frozenset(scopingElements | {(namespaces["html"], "button")}), False),
+ "list": (frozenset(scopingElements | {(namespaces["html"], "ol"),
+ (namespaces["html"], "ul")}), False),
"table": (frozenset([(namespaces["html"], "html"),
(namespaces["html"], "table")]), False),
"select": (frozenset([(namespaces["html"], "optgroup"),
@@ -28,7 +28,7 @@ class Node(object):
:arg name: The tag name associated with the node
"""
- # The tag name assocaited with the node
+ # The tag name associated with the node
self.name = name
# The parent of the current node (or None for the document node)
self.parent = None
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/etree.py b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/etree.py
index 0dedf44..ea92dc3 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/etree.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/etree.py
@@ -5,6 +5,8 @@ from pip._vendor.six import text_type
import re
+from copy import copy
+
from . import base
from .. import _ihatexml
from .. import constants
@@ -61,16 +63,17 @@ def getETreeBuilder(ElementTreeImplementation, fullTree=False):
return self._element.attrib
def _setAttributes(self, attributes):
- # Delete existing attributes first
- # XXX - there may be a better way to do this...
- for key in list(self._element.attrib.keys()):
- del self._element.attrib[key]
- for key, value in attributes.items():
- if isinstance(key, tuple):
- name = "{%s}%s" % (key[2], key[1])
- else:
- name = key
- self._element.set(name, value)
+ el_attrib = self._element.attrib
+ el_attrib.clear()
+ if attributes:
+ # calling .items _always_ allocates, and the above truthy check is cheaper than the
+ # allocation on average
+ for key, value in attributes.items():
+ if isinstance(key, tuple):
+ name = "{%s}%s" % (key[2], key[1])
+ else:
+ name = key
+ el_attrib[name] = value
attributes = property(_getAttributes, _setAttributes)
@@ -129,8 +132,8 @@ def getETreeBuilder(ElementTreeImplementation, fullTree=False):
def cloneNode(self):
element = type(self)(self.name, self.namespace)
- for name, value in self.attributes.items():
- element.attributes[name] = value
+ if self._element.attrib:
+ element._element.attrib = copy(self._element.attrib)
return element
def reparentChildren(self, newParent):
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/etree_lxml.py b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/etree_lxml.py
index ca12a99..f037759 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/etree_lxml.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treebuilders/etree_lxml.py
@@ -16,6 +16,11 @@ import warnings
import re
import sys
+try:
+ from collections.abc import MutableMapping
+except ImportError:
+ from collections import MutableMapping
+
from . import base
from ..constants import DataLossWarning
from .. import constants
@@ -23,6 +28,7 @@ from . import etree as etree_builders
from .. import _ihatexml
import lxml.etree as etree
+from pip._vendor.six import PY3, binary_type
fullTree = True
@@ -44,7 +50,11 @@ class Document(object):
self._childNodes = []
def appendChild(self, element):
- self._elementTree.getroot().addnext(element._element)
+ last = self._elementTree.getroot()
+ for last in self._elementTree.getroot().itersiblings():
+ pass
+
+ last.addnext(element._element)
def _getChildNodes(self):
return self._childNodes
@@ -185,26 +195,37 @@ class TreeBuilder(base.TreeBuilder):
infosetFilter = self.infosetFilter = _ihatexml.InfosetFilter(preventDoubleDashComments=True)
self.namespaceHTMLElements = namespaceHTMLElements
- class Attributes(dict):
- def __init__(self, element, value=None):
- if value is None:
- value = {}
+ class Attributes(MutableMapping):
+ def __init__(self, element):
self._element = element
- dict.__init__(self, value) # pylint:disable=non-parent-init-called
- for key, value in self.items():
- if isinstance(key, tuple):
- name = "{%s}%s" % (key[2], infosetFilter.coerceAttribute(key[1]))
- else:
- name = infosetFilter.coerceAttribute(key)
- self._element._element.attrib[name] = value
- def __setitem__(self, key, value):
- dict.__setitem__(self, key, value)
+ def _coerceKey(self, key):
if isinstance(key, tuple):
name = "{%s}%s" % (key[2], infosetFilter.coerceAttribute(key[1]))
else:
name = infosetFilter.coerceAttribute(key)
- self._element._element.attrib[name] = value
+ return name
+
+ def __getitem__(self, key):
+ value = self._element._element.attrib[self._coerceKey(key)]
+ if not PY3 and isinstance(value, binary_type):
+ value = value.decode("ascii")
+ return value
+
+ def __setitem__(self, key, value):
+ self._element._element.attrib[self._coerceKey(key)] = value
+
+ def __delitem__(self, key):
+ del self._element._element.attrib[self._coerceKey(key)]
+
+ def __iter__(self):
+ return iter(self._element._element.attrib)
+
+ def __len__(self):
+ return len(self._element._element.attrib)
+
+ def clear(self):
+ return self._element._element.attrib.clear()
class Element(builder.Element):
def __init__(self, name, namespace):
@@ -225,8 +246,10 @@ class TreeBuilder(base.TreeBuilder):
def _getAttributes(self):
return self._attributes
- def _setAttributes(self, attributes):
- self._attributes = Attributes(self, attributes)
+ def _setAttributes(self, value):
+ attributes = self.attributes
+ attributes.clear()
+ attributes.update(value)
attributes = property(_getAttributes, _setAttributes)
@@ -234,8 +257,11 @@ class TreeBuilder(base.TreeBuilder):
data = infosetFilter.coerceCharacters(data)
builder.Element.insertText(self, data, insertBefore)
- def appendChild(self, child):
- builder.Element.appendChild(self, child)
+ def cloneNode(self):
+ element = type(self)(self.name, self.namespace)
+ if self._element.attrib:
+ element._element.attrib.update(self._element.attrib)
+ return element
class Comment(builder.Comment):
def __init__(self, data):
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__init__.py
index 9bec207..b2d3aac 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__init__.py
@@ -2,10 +2,10 @@
tree, generating tokens identical to those produced by the tokenizer
module.
-To create a tree walker for a new type of tree, you need to do
+To create a tree walker for a new type of tree, you need to
implement a tree walker object (called TreeWalker by convention) that
-implements a 'serialize' method taking a tree as sole argument and
-returning an iterator generating tokens.
+implements a 'serialize' method which takes a tree as sole argument and
+returns an iterator which generates tokens.
"""
from __future__ import absolute_import, division, unicode_literals
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/__init__.cpython-38.pyc
index 4449dd9..8d27bb5 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/base.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/base.cpython-38.pyc
index 82327dd..b200fe5 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/base.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/base.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/dom.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/dom.cpython-38.pyc
index 8434bef..fba16ba 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/dom.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/dom.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/etree.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/etree.cpython-38.pyc
index 379d041..b584c36 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/etree.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/etree.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/etree_lxml.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/etree_lxml.cpython-38.pyc
index b0f9fd5..b9d4073 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/etree_lxml.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/etree_lxml.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/genshi.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/genshi.cpython-38.pyc
index b9c6943..f60fce9 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/genshi.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/genshi.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/etree.py b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/etree.py
index 95fc0c1..837b27e 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/etree.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/etree.py
@@ -127,4 +127,5 @@ def getETreeBuilder(ElementTreeImplementation):
return locals()
+
getETreeModule = moduleFactoryFactory(getETreeBuilder)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/etree_lxml.py b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/etree_lxml.py
index e81ddf3..c56af39 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/etree_lxml.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/html5lib/treewalkers/etree_lxml.py
@@ -1,6 +1,8 @@
from __future__ import absolute_import, division, unicode_literals
from pip._vendor.six import text_type
+from collections import OrderedDict
+
from lxml import etree
from ..treebuilders.etree import tag_regexp
@@ -163,7 +165,7 @@ class TreeWalker(base.NonRecursiveTreeWalker):
else:
namespace = None
tag = ensure_str(node.tag)
- attrs = {}
+ attrs = OrderedDict()
for name, value in list(node.attrib.items()):
name = ensure_str(name)
value = ensure_str(value)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-38.pyc
index ec91948..603344f 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-38.pyc
index 39ceb26..d165624 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-38.pyc
index cf382db..eab2a28 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/core.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/core.cpython-38.pyc
index f875e74..737c6c4 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/core.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/core.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-38.pyc
index 5f6d491..440391d 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-38.pyc
index b93de18..d3df767 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-38.pyc
index 8aa86b0..d2017f9 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-38.pyc
index 3a06faa..e1f03a3 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/idna/core.py b/venv/lib/python3.8/site-packages/pip/_vendor/idna/core.py
index 104624a..41ec5c7 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/idna/core.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/idna/core.py
@@ -9,7 +9,7 @@ _virama_combining_class = 9
_alabel_prefix = b'xn--'
_unicode_dots_re = re.compile(u'[\u002e\u3002\uff0e\uff61]')
-if sys.version_info[0] == 3:
+if sys.version_info[0] >= 3:
unicode = str
unichr = chr
@@ -300,6 +300,10 @@ def ulabel(label):
label = label.lower()
if label.startswith(_alabel_prefix):
label = label[len(_alabel_prefix):]
+ if not label:
+ raise IDNAError('Malformed A-label, no Punycode eligible content found')
+ if label.decode('ascii')[-1] == '-':
+ raise IDNAError('A-label must not end with a hyphen')
else:
check_label(label)
return label.decode('ascii')
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/idna/idnadata.py b/venv/lib/python3.8/site-packages/pip/_vendor/idna/idnadata.py
index a80c959..a284e4c 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/idna/idnadata.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/idna/idnadata.py
@@ -1,6 +1,6 @@
# This file is automatically generated by tools/idna-data
-__version__ = "11.0.0"
+__version__ = "13.0.0"
scripts = {
'Greek': (
0x37000000374,
@@ -48,16 +48,18 @@ scripts = {
0x300700003008,
0x30210000302a,
0x30380000303c,
- 0x340000004db6,
- 0x4e0000009ff0,
+ 0x340000004dc0,
+ 0x4e0000009ffd,
0xf9000000fa6e,
0xfa700000fada,
- 0x200000002a6d7,
+ 0x16ff000016ff2,
+ 0x200000002a6de,
0x2a7000002b735,
0x2b7400002b81e,
0x2b8200002cea2,
0x2ceb00002ebe1,
0x2f8000002fa1e,
+ 0x300000003134b,
),
'Hebrew': (
0x591000005c8,
@@ -74,6 +76,7 @@ scripts = {
0x304100003097,
0x309d000030a0,
0x1b0010001b11f,
+ 0x1b1500001b153,
0x1f2000001f201,
),
'Katakana': (
@@ -85,6 +88,7 @@ scripts = {
0xff660000ff70,
0xff710000ff9e,
0x1b0000001b001,
+ 0x1b1640001b168,
),
}
joining_types = {
@@ -387,9 +391,9 @@ joining_types = {
0x853: 68,
0x854: 82,
0x855: 68,
- 0x856: 85,
- 0x857: 85,
- 0x858: 85,
+ 0x856: 82,
+ 0x857: 82,
+ 0x858: 82,
0x860: 68,
0x861: 85,
0x862: 68,
@@ -430,6 +434,16 @@ joining_types = {
0x8bb: 68,
0x8bc: 68,
0x8bd: 68,
+ 0x8be: 68,
+ 0x8bf: 68,
+ 0x8c0: 68,
+ 0x8c1: 68,
+ 0x8c2: 68,
+ 0x8c3: 68,
+ 0x8c4: 68,
+ 0x8c5: 68,
+ 0x8c6: 68,
+ 0x8c7: 68,
0x8e2: 85,
0x1806: 85,
0x1807: 68,
@@ -754,6 +768,34 @@ joining_types = {
0x10f52: 68,
0x10f53: 68,
0x10f54: 82,
+ 0x10fb0: 68,
+ 0x10fb1: 85,
+ 0x10fb2: 68,
+ 0x10fb3: 68,
+ 0x10fb4: 82,
+ 0x10fb5: 82,
+ 0x10fb6: 82,
+ 0x10fb7: 85,
+ 0x10fb8: 68,
+ 0x10fb9: 82,
+ 0x10fba: 82,
+ 0x10fbb: 68,
+ 0x10fbc: 68,
+ 0x10fbd: 82,
+ 0x10fbe: 68,
+ 0x10fbf: 68,
+ 0x10fc0: 85,
+ 0x10fc1: 68,
+ 0x10fc2: 82,
+ 0x10fc3: 82,
+ 0x10fc4: 68,
+ 0x10fc5: 85,
+ 0x10fc6: 85,
+ 0x10fc7: 85,
+ 0x10fc8: 85,
+ 0x10fc9: 82,
+ 0x10fca: 68,
+ 0x10fcb: 76,
0x110bd: 85,
0x110cd: 85,
0x1e900: 68,
@@ -824,6 +866,7 @@ joining_types = {
0x1e941: 68,
0x1e942: 68,
0x1e943: 68,
+ 0x1e94b: 84,
}
codepoint_classes = {
'PVALID': (
@@ -1126,7 +1169,7 @@ codepoint_classes = {
0x8400000085c,
0x8600000086b,
0x8a0000008b5,
- 0x8b6000008be,
+ 0x8b6000008c8,
0x8d3000008e2,
0x8e300000958,
0x96000000964,
@@ -1185,7 +1228,7 @@ codepoint_classes = {
0xb3c00000b45,
0xb4700000b49,
0xb4b00000b4e,
- 0xb5600000b58,
+ 0xb5500000b58,
0xb5f00000b64,
0xb6600000b70,
0xb7100000b72,
@@ -1230,8 +1273,7 @@ codepoint_classes = {
0xce000000ce4,
0xce600000cf0,
0xcf100000cf3,
- 0xd0000000d04,
- 0xd0500000d0d,
+ 0xd0000000d0d,
0xd0e00000d11,
0xd1200000d45,
0xd4600000d49,
@@ -1240,7 +1282,7 @@ codepoint_classes = {
0xd5f00000d64,
0xd6600000d70,
0xd7a00000d80,
- 0xd8200000d84,
+ 0xd8100000d84,
0xd8500000d97,
0xd9a00000db2,
0xdb300000dbc,
@@ -1258,18 +1300,11 @@ codepoint_classes = {
0xe5000000e5a,
0xe8100000e83,
0xe8400000e85,
- 0xe8700000e89,
- 0xe8a00000e8b,
- 0xe8d00000e8e,
- 0xe9400000e98,
- 0xe9900000ea0,
- 0xea100000ea4,
+ 0xe8600000e8b,
+ 0xe8c00000ea4,
0xea500000ea6,
- 0xea700000ea8,
- 0xeaa00000eac,
- 0xead00000eb3,
- 0xeb400000eba,
- 0xebb00000ebe,
+ 0xea700000eb3,
+ 0xeb400000ebe,
0xec000000ec5,
0xec600000ec7,
0xec800000ece,
@@ -1362,6 +1397,7 @@ codepoint_classes = {
0x1a9000001a9a,
0x1aa700001aa8,
0x1ab000001abe,
+ 0x1abf00001ac1,
0x1b0000001b4c,
0x1b5000001b5a,
0x1b6b00001b74,
@@ -1370,7 +1406,7 @@ codepoint_classes = {
0x1c4000001c4a,
0x1c4d00001c7e,
0x1cd000001cd3,
- 0x1cd400001cfa,
+ 0x1cd400001cfb,
0x1d0000001d2c,
0x1d2f00001d30,
0x1d3b00001d3c,
@@ -1613,10 +1649,10 @@ codepoint_classes = {
0x30a1000030fb,
0x30fc000030ff,
0x310500003130,
- 0x31a0000031bb,
+ 0x31a0000031c0,
0x31f000003200,
- 0x340000004db6,
- 0x4e0000009ff0,
+ 0x340000004dc0,
+ 0x4e0000009ffd,
0xa0000000a48d,
0xa4d00000a4fe,
0xa5000000a60d,
@@ -1727,8 +1763,15 @@ codepoint_classes = {
0xa7b50000a7b6,
0xa7b70000a7b8,
0xa7b90000a7ba,
- 0xa7f70000a7f8,
+ 0xa7bb0000a7bc,
+ 0xa7bd0000a7be,
+ 0xa7bf0000a7c0,
+ 0xa7c30000a7c4,
+ 0xa7c80000a7c9,
+ 0xa7ca0000a7cb,
+ 0xa7f60000a7f8,
0xa7fa0000a828,
+ 0xa82c0000a82d,
0xa8400000a874,
0xa8800000a8c6,
0xa8d00000a8da,
@@ -1753,7 +1796,7 @@ codepoint_classes = {
0xab200000ab27,
0xab280000ab2f,
0xab300000ab5b,
- 0xab600000ab66,
+ 0xab600000ab6a,
0xabc00000abeb,
0xabec0000abee,
0xabf00000abfa,
@@ -1827,9 +1870,14 @@ codepoint_classes = {
0x10cc000010cf3,
0x10d0000010d28,
0x10d3000010d3a,
+ 0x10e8000010eaa,
+ 0x10eab00010ead,
+ 0x10eb000010eb2,
0x10f0000010f1d,
0x10f2700010f28,
0x10f3000010f51,
+ 0x10fb000010fc5,
+ 0x10fe000010ff7,
0x1100000011047,
0x1106600011070,
0x1107f000110bb,
@@ -1837,12 +1885,12 @@ codepoint_classes = {
0x110f0000110fa,
0x1110000011135,
0x1113600011140,
- 0x1114400011147,
+ 0x1114400011148,
0x1115000011174,
0x1117600011177,
0x11180000111c5,
0x111c9000111cd,
- 0x111d0000111db,
+ 0x111ce000111db,
0x111dc000111dd,
0x1120000011212,
0x1121300011238,
@@ -1871,7 +1919,7 @@ codepoint_classes = {
0x1137000011375,
0x114000001144b,
0x114500001145a,
- 0x1145e0001145f,
+ 0x1145e00011462,
0x11480000114c6,
0x114c7000114c8,
0x114d0000114da,
@@ -1881,18 +1929,28 @@ codepoint_classes = {
0x1160000011641,
0x1164400011645,
0x116500001165a,
- 0x11680000116b8,
+ 0x11680000116b9,
0x116c0000116ca,
0x117000001171b,
0x1171d0001172c,
0x117300001173a,
0x118000001183b,
0x118c0000118ea,
- 0x118ff00011900,
+ 0x118ff00011907,
+ 0x119090001190a,
+ 0x1190c00011914,
+ 0x1191500011917,
+ 0x1191800011936,
+ 0x1193700011939,
+ 0x1193b00011944,
+ 0x119500001195a,
+ 0x119a0000119a8,
+ 0x119aa000119d8,
+ 0x119da000119e2,
+ 0x119e3000119e5,
0x11a0000011a3f,
0x11a4700011a48,
- 0x11a5000011a84,
- 0x11a8600011a9a,
+ 0x11a5000011a9a,
0x11a9d00011a9e,
0x11ac000011af9,
0x11c0000011c09,
@@ -1916,6 +1974,7 @@ codepoint_classes = {
0x11d9300011d99,
0x11da000011daa,
0x11ee000011ef7,
+ 0x11fb000011fb1,
0x120000001239a,
0x1248000012544,
0x130000001342f,
@@ -1931,13 +1990,18 @@ codepoint_classes = {
0x16b6300016b78,
0x16b7d00016b90,
0x16e6000016e80,
- 0x16f0000016f45,
- 0x16f5000016f7f,
+ 0x16f0000016f4b,
+ 0x16f4f00016f88,
0x16f8f00016fa0,
0x16fe000016fe2,
- 0x17000000187f2,
- 0x1880000018af3,
+ 0x16fe300016fe5,
+ 0x16ff000016ff2,
+ 0x17000000187f8,
+ 0x1880000018cd6,
+ 0x18d0000018d09,
0x1b0000001b11f,
+ 0x1b1500001b153,
+ 0x1b1640001b168,
0x1b1700001b2fc,
0x1bc000001bc6b,
0x1bc700001bc7d,
@@ -1955,15 +2019,22 @@ codepoint_classes = {
0x1e01b0001e022,
0x1e0230001e025,
0x1e0260001e02b,
+ 0x1e1000001e12d,
+ 0x1e1300001e13e,
+ 0x1e1400001e14a,
+ 0x1e14e0001e14f,
+ 0x1e2c00001e2fa,
0x1e8000001e8c5,
0x1e8d00001e8d7,
- 0x1e9220001e94b,
+ 0x1e9220001e94c,
0x1e9500001e95a,
- 0x200000002a6d7,
+ 0x1fbf00001fbfa,
+ 0x200000002a6de,
0x2a7000002b735,
0x2b7400002b81e,
0x2b8200002cea2,
0x2ceb00002ebe1,
+ 0x300000003134b,
),
'CONTEXTJ': (
0x200c0000200e,
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/idna/package_data.py b/venv/lib/python3.8/site-packages/pip/_vendor/idna/package_data.py
index 257e898..ce1c521 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/idna/package_data.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/idna/package_data.py
@@ -1,2 +1,2 @@
-__version__ = '2.8'
+__version__ = '2.10'
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/idna/uts46data.py b/venv/lib/python3.8/site-packages/pip/_vendor/idna/uts46data.py
index a68ed4c..3766dd4 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/idna/uts46data.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/idna/uts46data.py
@@ -4,7 +4,7 @@
"""IDNA Mapping Table from UTS46."""
-__version__ = "11.0.0"
+__version__ = "13.0.0"
def _seg_0():
return [
(0x0, '3'),
@@ -1074,7 +1074,7 @@ def _seg_10():
(0x8A0, 'V'),
(0x8B5, 'X'),
(0x8B6, 'V'),
- (0x8BE, 'X'),
+ (0x8C8, 'X'),
(0x8D3, 'V'),
(0x8E2, 'X'),
(0x8E3, 'V'),
@@ -1205,7 +1205,7 @@ def _seg_11():
(0xB49, 'X'),
(0xB4B, 'V'),
(0xB4E, 'X'),
- (0xB56, 'V'),
+ (0xB55, 'V'),
(0xB58, 'X'),
(0xB5C, 'M', u'ଡ଼'),
(0xB5D, 'M', u'ଢ଼'),
@@ -1272,7 +1272,7 @@ def _seg_12():
(0xC64, 'X'),
(0xC66, 'V'),
(0xC70, 'X'),
- (0xC78, 'V'),
+ (0xC77, 'V'),
(0xC8D, 'X'),
(0xC8E, 'V'),
(0xC91, 'X'),
@@ -1299,8 +1299,6 @@ def _seg_12():
(0xCF1, 'V'),
(0xCF3, 'X'),
(0xD00, 'V'),
- (0xD04, 'X'),
- (0xD05, 'V'),
(0xD0D, 'X'),
(0xD0E, 'V'),
(0xD11, 'X'),
@@ -1314,7 +1312,7 @@ def _seg_12():
(0xD64, 'X'),
(0xD66, 'V'),
(0xD80, 'X'),
- (0xD82, 'V'),
+ (0xD81, 'V'),
(0xD84, 'X'),
(0xD85, 'V'),
(0xD97, 'X'),
@@ -1348,33 +1346,19 @@ def _seg_12():
(0xE83, 'X'),
(0xE84, 'V'),
(0xE85, 'X'),
- (0xE87, 'V'),
- (0xE89, 'X'),
- (0xE8A, 'V'),
+ (0xE86, 'V'),
(0xE8B, 'X'),
- (0xE8D, 'V'),
- (0xE8E, 'X'),
- (0xE94, 'V'),
- ]
-
-def _seg_13():
- return [
- (0xE98, 'X'),
- (0xE99, 'V'),
- (0xEA0, 'X'),
- (0xEA1, 'V'),
+ (0xE8C, 'V'),
(0xEA4, 'X'),
(0xEA5, 'V'),
(0xEA6, 'X'),
(0xEA7, 'V'),
- (0xEA8, 'X'),
- (0xEAA, 'V'),
- (0xEAC, 'X'),
- (0xEAD, 'V'),
(0xEB3, 'M', u'ໍາ'),
(0xEB4, 'V'),
- (0xEBA, 'X'),
- (0xEBB, 'V'),
+ ]
+
+def _seg_13():
+ return [
(0xEBE, 'X'),
(0xEC0, 'V'),
(0xEC5, 'X'),
@@ -1459,10 +1443,6 @@ def _seg_13():
(0x1260, 'V'),
(0x1289, 'X'),
(0x128A, 'V'),
- ]
-
-def _seg_14():
- return [
(0x128E, 'X'),
(0x1290, 'V'),
(0x12B1, 'X'),
@@ -1479,6 +1459,10 @@ def _seg_14():
(0x12D8, 'V'),
(0x1311, 'X'),
(0x1312, 'V'),
+ ]
+
+def _seg_14():
+ return [
(0x1316, 'X'),
(0x1318, 'V'),
(0x135B, 'X'),
@@ -1563,15 +1547,11 @@ def _seg_14():
(0x1A7F, 'V'),
(0x1A8A, 'X'),
(0x1A90, 'V'),
- ]
-
-def _seg_15():
- return [
(0x1A9A, 'X'),
(0x1AA0, 'V'),
(0x1AAE, 'X'),
(0x1AB0, 'V'),
- (0x1ABF, 'X'),
+ (0x1AC1, 'X'),
(0x1B00, 'V'),
(0x1B4C, 'X'),
(0x1B50, 'V'),
@@ -1583,6 +1563,10 @@ def _seg_15():
(0x1C3B, 'V'),
(0x1C4A, 'X'),
(0x1C4D, 'V'),
+ ]
+
+def _seg_15():
+ return [
(0x1C80, 'M', u'в'),
(0x1C81, 'M', u'д'),
(0x1C82, 'M', u'о'),
@@ -1592,10 +1576,57 @@ def _seg_15():
(0x1C87, 'M', u'ѣ'),
(0x1C88, 'M', u'ꙋ'),
(0x1C89, 'X'),
+ (0x1C90, 'M', u'ა'),
+ (0x1C91, 'M', u'ბ'),
+ (0x1C92, 'M', u'გ'),
+ (0x1C93, 'M', u'დ'),
+ (0x1C94, 'M', u'ე'),
+ (0x1C95, 'M', u'ვ'),
+ (0x1C96, 'M', u'ზ'),
+ (0x1C97, 'M', u'თ'),
+ (0x1C98, 'M', u'ი'),
+ (0x1C99, 'M', u'კ'),
+ (0x1C9A, 'M', u'ლ'),
+ (0x1C9B, 'M', u'მ'),
+ (0x1C9C, 'M', u'ნ'),
+ (0x1C9D, 'M', u'ო'),
+ (0x1C9E, 'M', u'პ'),
+ (0x1C9F, 'M', u'ჟ'),
+ (0x1CA0, 'M', u'რ'),
+ (0x1CA1, 'M', u'ს'),
+ (0x1CA2, 'M', u'ტ'),
+ (0x1CA3, 'M', u'უ'),
+ (0x1CA4, 'M', u'ფ'),
+ (0x1CA5, 'M', u'ქ'),
+ (0x1CA6, 'M', u'ღ'),
+ (0x1CA7, 'M', u'ყ'),
+ (0x1CA8, 'M', u'შ'),
+ (0x1CA9, 'M', u'ჩ'),
+ (0x1CAA, 'M', u'ც'),
+ (0x1CAB, 'M', u'ძ'),
+ (0x1CAC, 'M', u'წ'),
+ (0x1CAD, 'M', u'ჭ'),
+ (0x1CAE, 'M', u'ხ'),
+ (0x1CAF, 'M', u'ჯ'),
+ (0x1CB0, 'M', u'ჰ'),
+ (0x1CB1, 'M', u'ჱ'),
+ (0x1CB2, 'M', u'ჲ'),
+ (0x1CB3, 'M', u'ჳ'),
+ (0x1CB4, 'M', u'ჴ'),
+ (0x1CB5, 'M', u'ჵ'),
+ (0x1CB6, 'M', u'ჶ'),
+ (0x1CB7, 'M', u'ჷ'),
+ (0x1CB8, 'M', u'ჸ'),
+ (0x1CB9, 'M', u'ჹ'),
+ (0x1CBA, 'M', u'ჺ'),
+ (0x1CBB, 'X'),
+ (0x1CBD, 'M', u'ჽ'),
+ (0x1CBE, 'M', u'ჾ'),
+ (0x1CBF, 'M', u'ჿ'),
(0x1CC0, 'V'),
(0x1CC8, 'X'),
(0x1CD0, 'V'),
- (0x1CFA, 'X'),
+ (0x1CFB, 'X'),
(0x1D00, 'V'),
(0x1D2C, 'M', u'a'),
(0x1D2D, 'M', u'æ'),
@@ -1636,6 +1667,10 @@ def _seg_15():
(0x1D50, 'M', u'm'),
(0x1D51, 'M', u'ŋ'),
(0x1D52, 'M', u'o'),
+ ]
+
+def _seg_16():
+ return [
(0x1D53, 'M', u'ɔ'),
(0x1D54, 'M', u'ᴖ'),
(0x1D55, 'M', u'ᴗ'),
@@ -1667,10 +1702,6 @@ def _seg_15():
(0x1D9C, 'M', u'c'),
(0x1D9D, 'M', u'ɕ'),
(0x1D9E, 'M', u'ð'),
- ]
-
-def _seg_16():
- return [
(0x1D9F, 'M', u'ɜ'),
(0x1DA0, 'M', u'f'),
(0x1DA1, 'M', u'ɟ'),
@@ -1740,6 +1771,10 @@ def _seg_16():
(0x1E1E, 'M', u'ḟ'),
(0x1E1F, 'V'),
(0x1E20, 'M', u'ḡ'),
+ ]
+
+def _seg_17():
+ return [
(0x1E21, 'V'),
(0x1E22, 'M', u'ḣ'),
(0x1E23, 'V'),
@@ -1771,10 +1806,6 @@ def _seg_16():
(0x1E3D, 'V'),
(0x1E3E, 'M', u'ḿ'),
(0x1E3F, 'V'),
- ]
-
-def _seg_17():
- return [
(0x1E40, 'M', u'ṁ'),
(0x1E41, 'V'),
(0x1E42, 'M', u'ṃ'),
@@ -1844,6 +1875,10 @@ def _seg_17():
(0x1E82, 'M', u'ẃ'),
(0x1E83, 'V'),
(0x1E84, 'M', u'ẅ'),
+ ]
+
+def _seg_18():
+ return [
(0x1E85, 'V'),
(0x1E86, 'M', u'ẇ'),
(0x1E87, 'V'),
@@ -1875,10 +1910,6 @@ def _seg_17():
(0x1EA6, 'M', u'ầ'),
(0x1EA7, 'V'),
(0x1EA8, 'M', u'ẩ'),
- ]
-
-def _seg_18():
- return [
(0x1EA9, 'V'),
(0x1EAA, 'M', u'ẫ'),
(0x1EAB, 'V'),
@@ -1948,6 +1979,10 @@ def _seg_18():
(0x1EEB, 'V'),
(0x1EEC, 'M', u'ử'),
(0x1EED, 'V'),
+ ]
+
+def _seg_19():
+ return [
(0x1EEE, 'M', u'ữ'),
(0x1EEF, 'V'),
(0x1EF0, 'M', u'ự'),
@@ -1979,10 +2014,6 @@ def _seg_18():
(0x1F18, 'M', u'ἐ'),
(0x1F19, 'M', u'ἑ'),
(0x1F1A, 'M', u'ἒ'),
- ]
-
-def _seg_19():
- return [
(0x1F1B, 'M', u'ἓ'),
(0x1F1C, 'M', u'ἔ'),
(0x1F1D, 'M', u'ἕ'),
@@ -2052,6 +2083,10 @@ def _seg_19():
(0x1F82, 'M', u'ἂι'),
(0x1F83, 'M', u'ἃι'),
(0x1F84, 'M', u'ἄι'),
+ ]
+
+def _seg_20():
+ return [
(0x1F85, 'M', u'ἅι'),
(0x1F86, 'M', u'ἆι'),
(0x1F87, 'M', u'ἇι'),
@@ -2083,10 +2118,6 @@ def _seg_19():
(0x1FA1, 'M', u'ὡι'),
(0x1FA2, 'M', u'ὢι'),
(0x1FA3, 'M', u'ὣι'),
- ]
-
-def _seg_20():
- return [
(0x1FA4, 'M', u'ὤι'),
(0x1FA5, 'M', u'ὥι'),
(0x1FA6, 'M', u'ὦι'),
@@ -2156,6 +2187,10 @@ def _seg_20():
(0x1FF0, 'X'),
(0x1FF2, 'M', u'ὼι'),
(0x1FF3, 'M', u'ωι'),
+ ]
+
+def _seg_21():
+ return [
(0x1FF4, 'M', u'ώι'),
(0x1FF5, 'X'),
(0x1FF6, 'V'),
@@ -2187,10 +2222,6 @@ def _seg_20():
(0x2035, 'V'),
(0x2036, 'M', u'‵‵'),
(0x2037, 'M', u'‵‵‵'),
- ]
-
-def _seg_21():
- return [
(0x2038, 'V'),
(0x203C, '3', u'!!'),
(0x203D, 'V'),
@@ -2260,6 +2291,10 @@ def _seg_21():
(0x20F1, 'X'),
(0x2100, '3', u'a/c'),
(0x2101, '3', u'a/s'),
+ ]
+
+def _seg_22():
+ return [
(0x2102, 'M', u'c'),
(0x2103, 'M', u'°c'),
(0x2104, 'V'),
@@ -2291,10 +2326,6 @@ def _seg_21():
(0x2127, 'V'),
(0x2128, 'M', u'z'),
(0x2129, 'V'),
- ]
-
-def _seg_22():
- return [
(0x212A, 'M', u'k'),
(0x212B, 'M', u'å'),
(0x212C, 'M', u'b'),
@@ -2364,6 +2395,10 @@ def _seg_22():
(0x2177, 'M', u'viii'),
(0x2178, 'M', u'ix'),
(0x2179, 'M', u'x'),
+ ]
+
+def _seg_23():
+ return [
(0x217A, 'M', u'xi'),
(0x217B, 'M', u'xii'),
(0x217C, 'M', u'l'),
@@ -2395,10 +2430,6 @@ def _seg_22():
(0x244B, 'X'),
(0x2460, 'M', u'1'),
(0x2461, 'M', u'2'),
- ]
-
-def _seg_23():
- return [
(0x2462, 'M', u'3'),
(0x2463, 'M', u'4'),
(0x2464, 'M', u'5'),
@@ -2468,6 +2499,10 @@ def _seg_23():
(0x24B7, 'M', u'b'),
(0x24B8, 'M', u'c'),
(0x24B9, 'M', u'd'),
+ ]
+
+def _seg_24():
+ return [
(0x24BA, 'M', u'e'),
(0x24BB, 'M', u'f'),
(0x24BC, 'M', u'g'),
@@ -2499,10 +2534,6 @@ def _seg_23():
(0x24D6, 'M', u'g'),
(0x24D7, 'M', u'h'),
(0x24D8, 'M', u'i'),
- ]
-
-def _seg_24():
- return [
(0x24D9, 'M', u'j'),
(0x24DA, 'M', u'k'),
(0x24DB, 'M', u'l'),
@@ -2533,10 +2564,7 @@ def _seg_24():
(0x2B74, 'X'),
(0x2B76, 'V'),
(0x2B96, 'X'),
- (0x2B98, 'V'),
- (0x2BC9, 'X'),
- (0x2BCA, 'V'),
- (0x2BFF, 'X'),
+ (0x2B97, 'V'),
(0x2C00, 'M', u'ⰰ'),
(0x2C01, 'M', u'ⰱ'),
(0x2C02, 'M', u'ⰲ'),
@@ -2575,6 +2603,10 @@ def _seg_24():
(0x2C23, 'M', u'ⱓ'),
(0x2C24, 'M', u'ⱔ'),
(0x2C25, 'M', u'ⱕ'),
+ ]
+
+def _seg_25():
+ return [
(0x2C26, 'M', u'ⱖ'),
(0x2C27, 'M', u'ⱗ'),
(0x2C28, 'M', u'ⱘ'),
@@ -2603,10 +2635,6 @@ def _seg_24():
(0x2C6E, 'M', u'ɱ'),
(0x2C6F, 'M', u'ɐ'),
(0x2C70, 'M', u'ɒ'),
- ]
-
-def _seg_25():
- return [
(0x2C71, 'V'),
(0x2C72, 'M', u'ⱳ'),
(0x2C73, 'V'),
@@ -2679,6 +2707,10 @@ def _seg_25():
(0x2CBC, 'M', u'ⲽ'),
(0x2CBD, 'V'),
(0x2CBE, 'M', u'ⲿ'),
+ ]
+
+def _seg_26():
+ return [
(0x2CBF, 'V'),
(0x2CC0, 'M', u'ⳁ'),
(0x2CC1, 'V'),
@@ -2707,10 +2739,6 @@ def _seg_25():
(0x2CD8, 'M', u'ⳙ'),
(0x2CD9, 'V'),
(0x2CDA, 'M', u'ⳛ'),
- ]
-
-def _seg_26():
- return [
(0x2CDB, 'V'),
(0x2CDC, 'M', u'ⳝ'),
(0x2CDD, 'V'),
@@ -2757,7 +2785,7 @@ def _seg_26():
(0x2DD8, 'V'),
(0x2DDF, 'X'),
(0x2DE0, 'V'),
- (0x2E4F, 'X'),
+ (0x2E53, 'X'),
(0x2E80, 'V'),
(0x2E9A, 'X'),
(0x2E9B, 'V'),
@@ -2783,6 +2811,10 @@ def _seg_26():
(0x2F0F, 'M', u'几'),
(0x2F10, 'M', u'凵'),
(0x2F11, 'M', u'刀'),
+ ]
+
+def _seg_27():
+ return [
(0x2F12, 'M', u'力'),
(0x2F13, 'M', u'勹'),
(0x2F14, 'M', u'匕'),
@@ -2811,10 +2843,6 @@ def _seg_26():
(0x2F2B, 'M', u'尸'),
(0x2F2C, 'M', u'屮'),
(0x2F2D, 'M', u'山'),
- ]
-
-def _seg_27():
- return [
(0x2F2E, 'M', u'巛'),
(0x2F2F, 'M', u'工'),
(0x2F30, 'M', u'己'),
@@ -2887,6 +2915,10 @@ def _seg_27():
(0x2F73, 'M', u'穴'),
(0x2F74, 'M', u'立'),
(0x2F75, 'M', u'竹'),
+ ]
+
+def _seg_28():
+ return [
(0x2F76, 'M', u'米'),
(0x2F77, 'M', u'糸'),
(0x2F78, 'M', u'缶'),
@@ -2915,10 +2947,6 @@ def _seg_27():
(0x2F8F, 'M', u'行'),
(0x2F90, 'M', u'衣'),
(0x2F91, 'M', u'襾'),
- ]
-
-def _seg_28():
- return [
(0x2F92, 'M', u'見'),
(0x2F93, 'M', u'角'),
(0x2F94, 'M', u'言'),
@@ -2991,6 +3019,10 @@ def _seg_28():
(0x3000, '3', u' '),
(0x3001, 'V'),
(0x3002, 'M', u'.'),
+ ]
+
+def _seg_29():
+ return [
(0x3003, 'V'),
(0x3036, 'M', u'〒'),
(0x3037, 'V'),
@@ -3019,10 +3051,6 @@ def _seg_28():
(0x3136, 'M', u'ᆭ'),
(0x3137, 'M', u'ᄃ'),
(0x3138, 'M', u'ᄄ'),
- ]
-
-def _seg_29():
- return [
(0x3139, 'M', u'ᄅ'),
(0x313A, 'M', u'ᆰ'),
(0x313B, 'M', u'ᆱ'),
@@ -3095,6 +3123,10 @@ def _seg_29():
(0x317E, 'M', u'ᄶ'),
(0x317F, 'M', u'ᅀ'),
(0x3180, 'M', u'ᅇ'),
+ ]
+
+def _seg_30():
+ return [
(0x3181, 'M', u'ᅌ'),
(0x3182, 'M', u'ᇱ'),
(0x3183, 'M', u'ᇲ'),
@@ -3123,15 +3155,9 @@ def _seg_29():
(0x319B, 'M', u'丙'),
(0x319C, 'M', u'丁'),
(0x319D, 'M', u'天'),
- ]
-
-def _seg_30():
- return [
(0x319E, 'M', u'地'),
(0x319F, 'M', u'人'),
(0x31A0, 'V'),
- (0x31BB, 'X'),
- (0x31C0, 'V'),
(0x31E4, 'X'),
(0x31F0, 'V'),
(0x3200, '3', u'(ᄀ)'),
@@ -3201,6 +3227,10 @@ def _seg_30():
(0x3240, '3', u'(祭)'),
(0x3241, '3', u'(休)'),
(0x3242, '3', u'(自)'),
+ ]
+
+def _seg_31():
+ return [
(0x3243, '3', u'(至)'),
(0x3244, 'M', u'問'),
(0x3245, 'M', u'幼'),
@@ -3227,10 +3257,6 @@ def _seg_30():
(0x3261, 'M', u'ᄂ'),
(0x3262, 'M', u'ᄃ'),
(0x3263, 'M', u'ᄅ'),
- ]
-
-def _seg_31():
- return [
(0x3264, 'M', u'ᄆ'),
(0x3265, 'M', u'ᄇ'),
(0x3266, 'M', u'ᄉ'),
@@ -3305,6 +3331,10 @@ def _seg_31():
(0x32AB, 'M', u'学'),
(0x32AC, 'M', u'監'),
(0x32AD, 'M', u'企'),
+ ]
+
+def _seg_32():
+ return [
(0x32AE, 'M', u'資'),
(0x32AF, 'M', u'協'),
(0x32B0, 'M', u'夜'),
@@ -3331,10 +3361,6 @@ def _seg_31():
(0x32C5, 'M', u'6月'),
(0x32C6, 'M', u'7月'),
(0x32C7, 'M', u'8月'),
- ]
-
-def _seg_32():
- return [
(0x32C8, 'M', u'9月'),
(0x32C9, 'M', u'10月'),
(0x32CA, 'M', u'11月'),
@@ -3390,7 +3416,7 @@ def _seg_32():
(0x32FC, 'M', u'ヰ'),
(0x32FD, 'M', u'ヱ'),
(0x32FE, 'M', u'ヲ'),
- (0x32FF, 'X'),
+ (0x32FF, 'M', u'令和'),
(0x3300, 'M', u'アパート'),
(0x3301, 'M', u'アルファ'),
(0x3302, 'M', u'アンペア'),
@@ -3409,6 +3435,10 @@ def _seg_32():
(0x330F, 'M', u'ガンマ'),
(0x3310, 'M', u'ギガ'),
(0x3311, 'M', u'ギニー'),
+ ]
+
+def _seg_33():
+ return [
(0x3312, 'M', u'キュリー'),
(0x3313, 'M', u'ギルダー'),
(0x3314, 'M', u'キロ'),
@@ -3435,10 +3465,6 @@ def _seg_32():
(0x3329, 'M', u'ノット'),
(0x332A, 'M', u'ハイツ'),
(0x332B, 'M', u'パーセント'),
- ]
-
-def _seg_33():
- return [
(0x332C, 'M', u'パーツ'),
(0x332D, 'M', u'バーレル'),
(0x332E, 'M', u'ピアストル'),
@@ -3513,6 +3539,10 @@ def _seg_33():
(0x3373, 'M', u'au'),
(0x3374, 'M', u'bar'),
(0x3375, 'M', u'ov'),
+ ]
+
+def _seg_34():
+ return [
(0x3376, 'M', u'pc'),
(0x3377, 'M', u'dm'),
(0x3378, 'M', u'dm2'),
@@ -3539,10 +3569,6 @@ def _seg_33():
(0x338D, 'M', u'μg'),
(0x338E, 'M', u'mg'),
(0x338F, 'M', u'kg'),
- ]
-
-def _seg_34():
- return [
(0x3390, 'M', u'hz'),
(0x3391, 'M', u'khz'),
(0x3392, 'M', u'mhz'),
@@ -3617,6 +3643,10 @@ def _seg_34():
(0x33D7, 'M', u'ph'),
(0x33D8, 'X'),
(0x33D9, 'M', u'ppm'),
+ ]
+
+def _seg_35():
+ return [
(0x33DA, 'M', u'pr'),
(0x33DB, 'M', u'sr'),
(0x33DC, 'M', u'sv'),
@@ -3643,10 +3673,6 @@ def _seg_34():
(0x33F1, 'M', u'18日'),
(0x33F2, 'M', u'19日'),
(0x33F3, 'M', u'20日'),
- ]
-
-def _seg_35():
- return [
(0x33F4, 'M', u'21日'),
(0x33F5, 'M', u'22日'),
(0x33F6, 'M', u'23日'),
@@ -3660,9 +3686,7 @@ def _seg_35():
(0x33FE, 'M', u'31日'),
(0x33FF, 'M', u'gal'),
(0x3400, 'V'),
- (0x4DB6, 'X'),
- (0x4DC0, 'V'),
- (0x9FF0, 'X'),
+ (0x9FFD, 'X'),
(0xA000, 'V'),
(0xA48D, 'X'),
(0xA490, 'V'),
@@ -3723,6 +3747,10 @@ def _seg_35():
(0xA685, 'V'),
(0xA686, 'M', u'ꚇ'),
(0xA687, 'V'),
+ ]
+
+def _seg_36():
+ return [
(0xA688, 'M', u'ꚉ'),
(0xA689, 'V'),
(0xA68A, 'M', u'ꚋ'),
@@ -3747,10 +3775,6 @@ def _seg_35():
(0xA69D, 'M', u'ь'),
(0xA69E, 'V'),
(0xA6F8, 'X'),
- ]
-
-def _seg_36():
- return [
(0xA700, 'V'),
(0xA722, 'M', u'ꜣ'),
(0xA723, 'V'),
@@ -3827,6 +3851,10 @@ def _seg_36():
(0xA76C, 'M', u'ꝭ'),
(0xA76D, 'V'),
(0xA76E, 'M', u'ꝯ'),
+ ]
+
+def _seg_37():
+ return [
(0xA76F, 'V'),
(0xA770, 'M', u'ꝯ'),
(0xA771, 'V'),
@@ -3851,10 +3879,6 @@ def _seg_36():
(0xA78E, 'V'),
(0xA790, 'M', u'ꞑ'),
(0xA791, 'V'),
- ]
-
-def _seg_37():
- return [
(0xA792, 'M', u'ꞓ'),
(0xA793, 'V'),
(0xA796, 'M', u'ꞗ'),
@@ -3891,14 +3915,31 @@ def _seg_37():
(0xA7B5, 'V'),
(0xA7B6, 'M', u'ꞷ'),
(0xA7B7, 'V'),
- (0xA7B8, 'X'),
+ (0xA7B8, 'M', u'ꞹ'),
(0xA7B9, 'V'),
- (0xA7BA, 'X'),
- (0xA7F7, 'V'),
+ (0xA7BA, 'M', u'ꞻ'),
+ (0xA7BB, 'V'),
+ (0xA7BC, 'M', u'ꞽ'),
+ (0xA7BD, 'V'),
+ (0xA7BE, 'M', u'ꞿ'),
+ (0xA7BF, 'V'),
+ (0xA7C0, 'X'),
+ (0xA7C2, 'M', u'ꟃ'),
+ (0xA7C3, 'V'),
+ (0xA7C4, 'M', u'ꞔ'),
+ (0xA7C5, 'M', u'ʂ'),
+ (0xA7C6, 'M', u'ᶎ'),
+ (0xA7C7, 'M', u'ꟈ'),
+ (0xA7C8, 'V'),
+ (0xA7C9, 'M', u'ꟊ'),
+ (0xA7CA, 'V'),
+ (0xA7CB, 'X'),
+ (0xA7F5, 'M', u'ꟶ'),
+ (0xA7F6, 'V'),
(0xA7F8, 'M', u'ħ'),
(0xA7F9, 'M', u'œ'),
(0xA7FA, 'V'),
- (0xA82C, 'X'),
+ (0xA82D, 'X'),
(0xA830, 'V'),
(0xA83A, 'X'),
(0xA840, 'V'),
@@ -3914,6 +3955,10 @@ def _seg_37():
(0xA980, 'V'),
(0xA9CE, 'X'),
(0xA9CF, 'V'),
+ ]
+
+def _seg_38():
+ return [
(0xA9DA, 'X'),
(0xA9DE, 'V'),
(0xA9FF, 'X'),
@@ -3943,7 +3988,9 @@ def _seg_37():
(0xAB5E, 'M', u'ɫ'),
(0xAB5F, 'M', u'ꭒ'),
(0xAB60, 'V'),
- (0xAB66, 'X'),
+ (0xAB69, 'M', u'ʍ'),
+ (0xAB6A, 'V'),
+ (0xAB6C, 'X'),
(0xAB70, 'M', u'Ꭰ'),
(0xAB71, 'M', u'Ꭱ'),
(0xAB72, 'M', u'Ꭲ'),
@@ -3955,10 +4002,6 @@ def _seg_37():
(0xAB78, 'M', u'Ꭸ'),
(0xAB79, 'M', u'Ꭹ'),
(0xAB7A, 'M', u'Ꭺ'),
- ]
-
-def _seg_38():
- return [
(0xAB7B, 'M', u'Ꭻ'),
(0xAB7C, 'M', u'Ꭼ'),
(0xAB7D, 'M', u'Ꭽ'),
@@ -4016,6 +4059,10 @@ def _seg_38():
(0xABB1, 'M', u'Ꮱ'),
(0xABB2, 'M', u'Ꮲ'),
(0xABB3, 'M', u'Ꮳ'),
+ ]
+
+def _seg_39():
+ return [
(0xABB4, 'M', u'Ꮴ'),
(0xABB5, 'M', u'Ꮵ'),
(0xABB6, 'M', u'Ꮶ'),
@@ -4059,10 +4106,6 @@ def _seg_38():
(0xF913, 'M', u'邏'),
(0xF914, 'M', u'樂'),
(0xF915, 'M', u'洛'),
- ]
-
-def _seg_39():
- return [
(0xF916, 'M', u'烙'),
(0xF917, 'M', u'珞'),
(0xF918, 'M', u'落'),
@@ -4120,6 +4163,10 @@ def _seg_39():
(0xF94C, 'M', u'樓'),
(0xF94D, 'M', u'淚'),
(0xF94E, 'M', u'漏'),
+ ]
+
+def _seg_40():
+ return [
(0xF94F, 'M', u'累'),
(0xF950, 'M', u'縷'),
(0xF951, 'M', u'陋'),
@@ -4163,10 +4210,6 @@ def _seg_39():
(0xF977, 'M', u'亮'),
(0xF978, 'M', u'兩'),
(0xF979, 'M', u'凉'),
- ]
-
-def _seg_40():
- return [
(0xF97A, 'M', u'梁'),
(0xF97B, 'M', u'糧'),
(0xF97C, 'M', u'良'),
@@ -4224,6 +4267,10 @@ def _seg_40():
(0xF9B0, 'M', u'聆'),
(0xF9B1, 'M', u'鈴'),
(0xF9B2, 'M', u'零'),
+ ]
+
+def _seg_41():
+ return [
(0xF9B3, 'M', u'靈'),
(0xF9B4, 'M', u'領'),
(0xF9B5, 'M', u'例'),
@@ -4267,10 +4314,6 @@ def _seg_40():
(0xF9DB, 'M', u'率'),
(0xF9DC, 'M', u'隆'),
(0xF9DD, 'M', u'利'),
- ]
-
-def _seg_41():
- return [
(0xF9DE, 'M', u'吏'),
(0xF9DF, 'M', u'履'),
(0xF9E0, 'M', u'易'),
@@ -4328,6 +4371,10 @@ def _seg_41():
(0xFA16, 'M', u'猪'),
(0xFA17, 'M', u'益'),
(0xFA18, 'M', u'礼'),
+ ]
+
+def _seg_42():
+ return [
(0xFA19, 'M', u'神'),
(0xFA1A, 'M', u'祥'),
(0xFA1B, 'M', u'福'),
@@ -4371,10 +4418,6 @@ def _seg_41():
(0xFA44, 'M', u'梅'),
(0xFA45, 'M', u'海'),
(0xFA46, 'M', u'渚'),
- ]
-
-def _seg_42():
- return [
(0xFA47, 'M', u'漢'),
(0xFA48, 'M', u'煮'),
(0xFA49, 'M', u'爫'),
@@ -4432,6 +4475,10 @@ def _seg_42():
(0xFA7F, 'M', u'奔'),
(0xFA80, 'M', u'婢'),
(0xFA81, 'M', u'嬨'),
+ ]
+
+def _seg_43():
+ return [
(0xFA82, 'M', u'廒'),
(0xFA83, 'M', u'廙'),
(0xFA84, 'M', u'彩'),
@@ -4475,10 +4522,6 @@ def _seg_42():
(0xFAAA, 'M', u'着'),
(0xFAAB, 'M', u'磌'),
(0xFAAC, 'M', u'窱'),
- ]
-
-def _seg_43():
- return [
(0xFAAD, 'M', u'節'),
(0xFAAE, 'M', u'类'),
(0xFAAF, 'M', u'絛'),
@@ -4536,6 +4579,10 @@ def _seg_43():
(0xFB14, 'M', u'մե'),
(0xFB15, 'M', u'մի'),
(0xFB16, 'M', u'վն'),
+ ]
+
+def _seg_44():
+ return [
(0xFB17, 'M', u'մխ'),
(0xFB18, 'X'),
(0xFB1D, 'M', u'יִ'),
@@ -4579,10 +4626,6 @@ def _seg_43():
(0xFB43, 'M', u'ףּ'),
(0xFB44, 'M', u'פּ'),
(0xFB45, 'X'),
- ]
-
-def _seg_44():
- return [
(0xFB46, 'M', u'צּ'),
(0xFB47, 'M', u'קּ'),
(0xFB48, 'M', u'רּ'),
@@ -4640,6 +4683,10 @@ def _seg_44():
(0xFBEE, 'M', u'ئو'),
(0xFBF0, 'M', u'ئۇ'),
(0xFBF2, 'M', u'ئۆ'),
+ ]
+
+def _seg_45():
+ return [
(0xFBF4, 'M', u'ئۈ'),
(0xFBF6, 'M', u'ئې'),
(0xFBF9, 'M', u'ئى'),
@@ -4683,10 +4730,6 @@ def _seg_44():
(0xFC24, 'M', u'ضخ'),
(0xFC25, 'M', u'ضم'),
(0xFC26, 'M', u'طح'),
- ]
-
-def _seg_45():
- return [
(0xFC27, 'M', u'طم'),
(0xFC28, 'M', u'ظم'),
(0xFC29, 'M', u'عج'),
@@ -4744,6 +4787,10 @@ def _seg_45():
(0xFC5D, 'M', u'ىٰ'),
(0xFC5E, '3', u' ٌّ'),
(0xFC5F, '3', u' ٍّ'),
+ ]
+
+def _seg_46():
+ return [
(0xFC60, '3', u' َّ'),
(0xFC61, '3', u' ُّ'),
(0xFC62, '3', u' ِّ'),
@@ -4787,10 +4834,6 @@ def _seg_45():
(0xFC88, 'M', u'ما'),
(0xFC89, 'M', u'مم'),
(0xFC8A, 'M', u'نر'),
- ]
-
-def _seg_46():
- return [
(0xFC8B, 'M', u'نز'),
(0xFC8C, 'M', u'نم'),
(0xFC8D, 'M', u'نن'),
@@ -4848,6 +4891,10 @@ def _seg_46():
(0xFCC1, 'M', u'فم'),
(0xFCC2, 'M', u'قح'),
(0xFCC3, 'M', u'قم'),
+ ]
+
+def _seg_47():
+ return [
(0xFCC4, 'M', u'كج'),
(0xFCC5, 'M', u'كح'),
(0xFCC6, 'M', u'كخ'),
@@ -4891,10 +4938,6 @@ def _seg_46():
(0xFCEC, 'M', u'كم'),
(0xFCED, 'M', u'لم'),
(0xFCEE, 'M', u'نم'),
- ]
-
-def _seg_47():
- return [
(0xFCEF, 'M', u'نه'),
(0xFCF0, 'M', u'يم'),
(0xFCF1, 'M', u'يه'),
@@ -4952,6 +4995,10 @@ def _seg_47():
(0xFD25, 'M', u'شج'),
(0xFD26, 'M', u'شح'),
(0xFD27, 'M', u'شخ'),
+ ]
+
+def _seg_48():
+ return [
(0xFD28, 'M', u'شم'),
(0xFD29, 'M', u'شر'),
(0xFD2A, 'M', u'سر'),
@@ -4995,10 +5042,6 @@ def _seg_47():
(0xFD66, 'M', u'صمم'),
(0xFD67, 'M', u'شحم'),
(0xFD69, 'M', u'شجي'),
- ]
-
-def _seg_48():
- return [
(0xFD6A, 'M', u'شمخ'),
(0xFD6C, 'M', u'شمم'),
(0xFD6E, 'M', u'ضحى'),
@@ -5056,6 +5099,10 @@ def _seg_48():
(0xFDAC, 'M', u'لجي'),
(0xFDAD, 'M', u'لمي'),
(0xFDAE, 'M', u'يحي'),
+ ]
+
+def _seg_49():
+ return [
(0xFDAF, 'M', u'يجي'),
(0xFDB0, 'M', u'يمي'),
(0xFDB1, 'M', u'ممي'),
@@ -5099,10 +5146,6 @@ def _seg_48():
(0xFDFE, 'X'),
(0xFE00, 'I'),
(0xFE10, '3', u','),
- ]
-
-def _seg_49():
- return [
(0xFE11, 'M', u'、'),
(0xFE12, 'X'),
(0xFE13, '3', u':'),
@@ -5160,6 +5203,10 @@ def _seg_49():
(0xFE64, '3', u'<'),
(0xFE65, '3', u'>'),
(0xFE66, '3', u'='),
+ ]
+
+def _seg_50():
+ return [
(0xFE67, 'X'),
(0xFE68, '3', u'\\'),
(0xFE69, '3', u'$'),
@@ -5203,10 +5250,6 @@ def _seg_49():
(0xFEB1, 'M', u'س'),
(0xFEB5, 'M', u'ش'),
(0xFEB9, 'M', u'ص'),
- ]
-
-def _seg_50():
- return [
(0xFEBD, 'M', u'ض'),
(0xFEC1, 'M', u'ط'),
(0xFEC5, 'M', u'ظ'),
@@ -5264,6 +5307,10 @@ def _seg_50():
(0xFF21, 'M', u'a'),
(0xFF22, 'M', u'b'),
(0xFF23, 'M', u'c'),
+ ]
+
+def _seg_51():
+ return [
(0xFF24, 'M', u'd'),
(0xFF25, 'M', u'e'),
(0xFF26, 'M', u'f'),
@@ -5307,10 +5354,6 @@ def _seg_50():
(0xFF4C, 'M', u'l'),
(0xFF4D, 'M', u'm'),
(0xFF4E, 'M', u'n'),
- ]
-
-def _seg_51():
- return [
(0xFF4F, 'M', u'o'),
(0xFF50, 'M', u'p'),
(0xFF51, 'M', u'q'),
@@ -5368,6 +5411,10 @@ def _seg_51():
(0xFF85, 'M', u'ナ'),
(0xFF86, 'M', u'ニ'),
(0xFF87, 'M', u'ヌ'),
+ ]
+
+def _seg_52():
+ return [
(0xFF88, 'M', u'ネ'),
(0xFF89, 'M', u'ノ'),
(0xFF8A, 'M', u'ハ'),
@@ -5411,10 +5458,6 @@ def _seg_51():
(0xFFB0, 'M', u'ᄚ'),
(0xFFB1, 'M', u'ᄆ'),
(0xFFB2, 'M', u'ᄇ'),
- ]
-
-def _seg_52():
- return [
(0xFFB3, 'M', u'ᄈ'),
(0xFFB4, 'M', u'ᄡ'),
(0xFFB5, 'M', u'ᄉ'),
@@ -5472,6 +5515,10 @@ def _seg_52():
(0x10000, 'V'),
(0x1000C, 'X'),
(0x1000D, 'V'),
+ ]
+
+def _seg_53():
+ return [
(0x10027, 'X'),
(0x10028, 'V'),
(0x1003B, 'X'),
@@ -5490,7 +5537,7 @@ def _seg_52():
(0x10137, 'V'),
(0x1018F, 'X'),
(0x10190, 'V'),
- (0x1019C, 'X'),
+ (0x1019D, 'X'),
(0x101A0, 'V'),
(0x101A1, 'X'),
(0x101D0, 'V'),
@@ -5515,10 +5562,6 @@ def _seg_52():
(0x103D6, 'X'),
(0x10400, 'M', u'𐐨'),
(0x10401, 'M', u'𐐩'),
- ]
-
-def _seg_53():
- return [
(0x10402, 'M', u'𐐪'),
(0x10403, 'M', u'𐐫'),
(0x10404, 'M', u'𐐬'),
@@ -5576,6 +5619,10 @@ def _seg_53():
(0x104BC, 'M', u'𐓤'),
(0x104BD, 'M', u'𐓥'),
(0x104BE, 'M', u'𐓦'),
+ ]
+
+def _seg_54():
+ return [
(0x104BF, 'M', u'𐓧'),
(0x104C0, 'M', u'𐓨'),
(0x104C1, 'M', u'𐓩'),
@@ -5619,10 +5666,6 @@ def _seg_53():
(0x1080A, 'V'),
(0x10836, 'X'),
(0x10837, 'V'),
- ]
-
-def _seg_54():
- return [
(0x10839, 'X'),
(0x1083C, 'V'),
(0x1083D, 'X'),
@@ -5680,6 +5723,10 @@ def _seg_54():
(0x10B9D, 'X'),
(0x10BA9, 'V'),
(0x10BB0, 'X'),
+ ]
+
+def _seg_55():
+ return [
(0x10C00, 'V'),
(0x10C49, 'X'),
(0x10C80, 'M', u'𐳀'),
@@ -5723,10 +5770,6 @@ def _seg_54():
(0x10CA6, 'M', u'𐳦'),
(0x10CA7, 'M', u'𐳧'),
(0x10CA8, 'M', u'𐳨'),
- ]
-
-def _seg_55():
- return [
(0x10CA9, 'M', u'𐳩'),
(0x10CAA, 'M', u'𐳪'),
(0x10CAB, 'M', u'𐳫'),
@@ -5746,10 +5789,20 @@ def _seg_55():
(0x10D3A, 'X'),
(0x10E60, 'V'),
(0x10E7F, 'X'),
+ (0x10E80, 'V'),
+ (0x10EAA, 'X'),
+ (0x10EAB, 'V'),
+ (0x10EAE, 'X'),
+ (0x10EB0, 'V'),
+ (0x10EB2, 'X'),
(0x10F00, 'V'),
(0x10F28, 'X'),
(0x10F30, 'V'),
(0x10F5A, 'X'),
+ (0x10FB0, 'V'),
+ (0x10FCC, 'X'),
+ (0x10FE0, 'V'),
+ (0x10FF7, 'X'),
(0x11000, 'V'),
(0x1104E, 'X'),
(0x11052, 'V'),
@@ -5765,17 +5818,19 @@ def _seg_55():
(0x11100, 'V'),
(0x11135, 'X'),
(0x11136, 'V'),
- (0x11147, 'X'),
+ (0x11148, 'X'),
(0x11150, 'V'),
(0x11177, 'X'),
(0x11180, 'V'),
- (0x111CE, 'X'),
- (0x111D0, 'V'),
(0x111E0, 'X'),
(0x111E1, 'V'),
(0x111F5, 'X'),
(0x11200, 'V'),
(0x11212, 'X'),
+ ]
+
+def _seg_56():
+ return [
(0x11213, 'V'),
(0x1123F, 'X'),
(0x11280, 'V'),
@@ -5823,15 +5878,9 @@ def _seg_55():
(0x11370, 'V'),
(0x11375, 'X'),
(0x11400, 'V'),
- (0x1145A, 'X'),
- (0x1145B, 'V'),
(0x1145C, 'X'),
(0x1145D, 'V'),
- ]
-
-def _seg_56():
- return [
- (0x1145F, 'X'),
+ (0x11462, 'X'),
(0x11480, 'V'),
(0x114C8, 'X'),
(0x114D0, 'V'),
@@ -5847,7 +5896,7 @@ def _seg_56():
(0x11660, 'V'),
(0x1166D, 'X'),
(0x11680, 'V'),
- (0x116B8, 'X'),
+ (0x116B9, 'X'),
(0x116C0, 'V'),
(0x116CA, 'X'),
(0x11700, 'V'),
@@ -5882,6 +5931,10 @@ def _seg_56():
(0x118B5, 'M', u'𑣕'),
(0x118B6, 'M', u'𑣖'),
(0x118B7, 'M', u'𑣗'),
+ ]
+
+def _seg_57():
+ return [
(0x118B8, 'M', u'𑣘'),
(0x118B9, 'M', u'𑣙'),
(0x118BA, 'M', u'𑣚'),
@@ -5893,12 +5946,30 @@ def _seg_56():
(0x118C0, 'V'),
(0x118F3, 'X'),
(0x118FF, 'V'),
- (0x11900, 'X'),
+ (0x11907, 'X'),
+ (0x11909, 'V'),
+ (0x1190A, 'X'),
+ (0x1190C, 'V'),
+ (0x11914, 'X'),
+ (0x11915, 'V'),
+ (0x11917, 'X'),
+ (0x11918, 'V'),
+ (0x11936, 'X'),
+ (0x11937, 'V'),
+ (0x11939, 'X'),
+ (0x1193B, 'V'),
+ (0x11947, 'X'),
+ (0x11950, 'V'),
+ (0x1195A, 'X'),
+ (0x119A0, 'V'),
+ (0x119A8, 'X'),
+ (0x119AA, 'V'),
+ (0x119D8, 'X'),
+ (0x119DA, 'V'),
+ (0x119E5, 'X'),
(0x11A00, 'V'),
(0x11A48, 'X'),
(0x11A50, 'V'),
- (0x11A84, 'X'),
- (0x11A86, 'V'),
(0x11AA3, 'X'),
(0x11AC0, 'V'),
(0x11AF9, 'X'),
@@ -5931,10 +6002,6 @@ def _seg_56():
(0x11D50, 'V'),
(0x11D5A, 'X'),
(0x11D60, 'V'),
- ]
-
-def _seg_57():
- return [
(0x11D66, 'X'),
(0x11D67, 'V'),
(0x11D69, 'X'),
@@ -5948,7 +6015,11 @@ def _seg_57():
(0x11DAA, 'X'),
(0x11EE0, 'V'),
(0x11EF9, 'X'),
- (0x12000, 'V'),
+ (0x11FB0, 'V'),
+ (0x11FB1, 'X'),
+ (0x11FC0, 'V'),
+ (0x11FF2, 'X'),
+ (0x11FFF, 'V'),
(0x1239A, 'X'),
(0x12400, 'V'),
(0x1246F, 'X'),
@@ -5964,6 +6035,10 @@ def _seg_57():
(0x16A39, 'X'),
(0x16A40, 'V'),
(0x16A5F, 'X'),
+ ]
+
+def _seg_58():
+ return [
(0x16A60, 'V'),
(0x16A6A, 'X'),
(0x16A6E, 'V'),
@@ -5982,22 +6057,62 @@ def _seg_57():
(0x16B78, 'X'),
(0x16B7D, 'V'),
(0x16B90, 'X'),
+ (0x16E40, 'M', u'𖹠'),
+ (0x16E41, 'M', u'𖹡'),
+ (0x16E42, 'M', u'𖹢'),
+ (0x16E43, 'M', u'𖹣'),
+ (0x16E44, 'M', u'𖹤'),
+ (0x16E45, 'M', u'𖹥'),
+ (0x16E46, 'M', u'𖹦'),
+ (0x16E47, 'M', u'𖹧'),
+ (0x16E48, 'M', u'𖹨'),
+ (0x16E49, 'M', u'𖹩'),
+ (0x16E4A, 'M', u'𖹪'),
+ (0x16E4B, 'M', u'𖹫'),
+ (0x16E4C, 'M', u'𖹬'),
+ (0x16E4D, 'M', u'𖹭'),
+ (0x16E4E, 'M', u'𖹮'),
+ (0x16E4F, 'M', u'𖹯'),
+ (0x16E50, 'M', u'𖹰'),
+ (0x16E51, 'M', u'𖹱'),
+ (0x16E52, 'M', u'𖹲'),
+ (0x16E53, 'M', u'𖹳'),
+ (0x16E54, 'M', u'𖹴'),
+ (0x16E55, 'M', u'𖹵'),
+ (0x16E56, 'M', u'𖹶'),
+ (0x16E57, 'M', u'𖹷'),
+ (0x16E58, 'M', u'𖹸'),
+ (0x16E59, 'M', u'𖹹'),
+ (0x16E5A, 'M', u'𖹺'),
+ (0x16E5B, 'M', u'𖹻'),
+ (0x16E5C, 'M', u'𖹼'),
+ (0x16E5D, 'M', u'𖹽'),
+ (0x16E5E, 'M', u'𖹾'),
+ (0x16E5F, 'M', u'𖹿'),
(0x16E60, 'V'),
(0x16E9B, 'X'),
(0x16F00, 'V'),
- (0x16F45, 'X'),
- (0x16F50, 'V'),
- (0x16F7F, 'X'),
+ (0x16F4B, 'X'),
+ (0x16F4F, 'V'),
+ (0x16F88, 'X'),
(0x16F8F, 'V'),
(0x16FA0, 'X'),
(0x16FE0, 'V'),
- (0x16FE2, 'X'),
+ (0x16FE5, 'X'),
+ (0x16FF0, 'V'),
+ (0x16FF2, 'X'),
(0x17000, 'V'),
- (0x187F2, 'X'),
+ (0x187F8, 'X'),
(0x18800, 'V'),
- (0x18AF3, 'X'),
+ (0x18CD6, 'X'),
+ (0x18D00, 'V'),
+ (0x18D09, 'X'),
(0x1B000, 'V'),
(0x1B11F, 'X'),
+ (0x1B150, 'V'),
+ (0x1B153, 'X'),
+ (0x1B164, 'V'),
+ (0x1B168, 'X'),
(0x1B170, 'V'),
(0x1B2FC, 'X'),
(0x1BC00, 'V'),
@@ -6024,6 +6139,10 @@ def _seg_57():
(0x1D163, 'M', u'𝅘𝅥𝅱'),
(0x1D164, 'M', u'𝅘𝅥𝅲'),
(0x1D165, 'V'),
+ ]
+
+def _seg_59():
+ return [
(0x1D173, 'X'),
(0x1D17B, 'V'),
(0x1D1BB, 'M', u'𝆹𝅥'),
@@ -6035,10 +6154,6 @@ def _seg_57():
(0x1D1C1, 'V'),
(0x1D1E9, 'X'),
(0x1D200, 'V'),
- ]
-
-def _seg_58():
- return [
(0x1D246, 'X'),
(0x1D2E0, 'V'),
(0x1D2F4, 'X'),
@@ -6128,6 +6243,10 @@ def _seg_58():
(0x1D44F, 'M', u'b'),
(0x1D450, 'M', u'c'),
(0x1D451, 'M', u'd'),
+ ]
+
+def _seg_60():
+ return [
(0x1D452, 'M', u'e'),
(0x1D453, 'M', u'f'),
(0x1D454, 'M', u'g'),
@@ -6139,10 +6258,6 @@ def _seg_58():
(0x1D45A, 'M', u'm'),
(0x1D45B, 'M', u'n'),
(0x1D45C, 'M', u'o'),
- ]
-
-def _seg_59():
- return [
(0x1D45D, 'M', u'p'),
(0x1D45E, 'M', u'q'),
(0x1D45F, 'M', u'r'),
@@ -6232,6 +6347,10 @@ def _seg_59():
(0x1D4B6, 'M', u'a'),
(0x1D4B7, 'M', u'b'),
(0x1D4B8, 'M', u'c'),
+ ]
+
+def _seg_61():
+ return [
(0x1D4B9, 'M', u'd'),
(0x1D4BA, 'X'),
(0x1D4BB, 'M', u'f'),
@@ -6243,10 +6362,6 @@ def _seg_59():
(0x1D4C1, 'M', u'l'),
(0x1D4C2, 'M', u'm'),
(0x1D4C3, 'M', u'n'),
- ]
-
-def _seg_60():
- return [
(0x1D4C4, 'X'),
(0x1D4C5, 'M', u'p'),
(0x1D4C6, 'M', u'q'),
@@ -6336,6 +6451,10 @@ def _seg_60():
(0x1D51B, 'M', u'x'),
(0x1D51C, 'M', u'y'),
(0x1D51D, 'X'),
+ ]
+
+def _seg_62():
+ return [
(0x1D51E, 'M', u'a'),
(0x1D51F, 'M', u'b'),
(0x1D520, 'M', u'c'),
@@ -6347,10 +6466,6 @@ def _seg_60():
(0x1D526, 'M', u'i'),
(0x1D527, 'M', u'j'),
(0x1D528, 'M', u'k'),
- ]
-
-def _seg_61():
- return [
(0x1D529, 'M', u'l'),
(0x1D52A, 'M', u'm'),
(0x1D52B, 'M', u'n'),
@@ -6440,6 +6555,10 @@ def _seg_61():
(0x1D581, 'M', u'v'),
(0x1D582, 'M', u'w'),
(0x1D583, 'M', u'x'),
+ ]
+
+def _seg_63():
+ return [
(0x1D584, 'M', u'y'),
(0x1D585, 'M', u'z'),
(0x1D586, 'M', u'a'),
@@ -6451,10 +6570,6 @@ def _seg_61():
(0x1D58C, 'M', u'g'),
(0x1D58D, 'M', u'h'),
(0x1D58E, 'M', u'i'),
- ]
-
-def _seg_62():
- return [
(0x1D58F, 'M', u'j'),
(0x1D590, 'M', u'k'),
(0x1D591, 'M', u'l'),
@@ -6544,6 +6659,10 @@ def _seg_62():
(0x1D5E5, 'M', u'r'),
(0x1D5E6, 'M', u's'),
(0x1D5E7, 'M', u't'),
+ ]
+
+def _seg_64():
+ return [
(0x1D5E8, 'M', u'u'),
(0x1D5E9, 'M', u'v'),
(0x1D5EA, 'M', u'w'),
@@ -6555,10 +6674,6 @@ def _seg_62():
(0x1D5F0, 'M', u'c'),
(0x1D5F1, 'M', u'd'),
(0x1D5F2, 'M', u'e'),
- ]
-
-def _seg_63():
- return [
(0x1D5F3, 'M', u'f'),
(0x1D5F4, 'M', u'g'),
(0x1D5F5, 'M', u'h'),
@@ -6648,6 +6763,10 @@ def _seg_63():
(0x1D649, 'M', u'n'),
(0x1D64A, 'M', u'o'),
(0x1D64B, 'M', u'p'),
+ ]
+
+def _seg_65():
+ return [
(0x1D64C, 'M', u'q'),
(0x1D64D, 'M', u'r'),
(0x1D64E, 'M', u's'),
@@ -6659,10 +6778,6 @@ def _seg_63():
(0x1D654, 'M', u'y'),
(0x1D655, 'M', u'z'),
(0x1D656, 'M', u'a'),
- ]
-
-def _seg_64():
- return [
(0x1D657, 'M', u'b'),
(0x1D658, 'M', u'c'),
(0x1D659, 'M', u'd'),
@@ -6752,6 +6867,10 @@ def _seg_64():
(0x1D6AE, 'M', u'η'),
(0x1D6AF, 'M', u'θ'),
(0x1D6B0, 'M', u'ι'),
+ ]
+
+def _seg_66():
+ return [
(0x1D6B1, 'M', u'κ'),
(0x1D6B2, 'M', u'λ'),
(0x1D6B3, 'M', u'μ'),
@@ -6763,10 +6882,6 @@ def _seg_64():
(0x1D6B9, 'M', u'θ'),
(0x1D6BA, 'M', u'σ'),
(0x1D6BB, 'M', u'τ'),
- ]
-
-def _seg_65():
- return [
(0x1D6BC, 'M', u'υ'),
(0x1D6BD, 'M', u'φ'),
(0x1D6BE, 'M', u'χ'),
@@ -6856,6 +6971,10 @@ def _seg_65():
(0x1D714, 'M', u'ω'),
(0x1D715, 'M', u'∂'),
(0x1D716, 'M', u'ε'),
+ ]
+
+def _seg_67():
+ return [
(0x1D717, 'M', u'θ'),
(0x1D718, 'M', u'κ'),
(0x1D719, 'M', u'φ'),
@@ -6867,10 +6986,6 @@ def _seg_65():
(0x1D71F, 'M', u'δ'),
(0x1D720, 'M', u'ε'),
(0x1D721, 'M', u'ζ'),
- ]
-
-def _seg_66():
- return [
(0x1D722, 'M', u'η'),
(0x1D723, 'M', u'θ'),
(0x1D724, 'M', u'ι'),
@@ -6960,6 +7075,10 @@ def _seg_66():
(0x1D779, 'M', u'κ'),
(0x1D77A, 'M', u'λ'),
(0x1D77B, 'M', u'μ'),
+ ]
+
+def _seg_68():
+ return [
(0x1D77C, 'M', u'ν'),
(0x1D77D, 'M', u'ξ'),
(0x1D77E, 'M', u'ο'),
@@ -6971,10 +7090,6 @@ def _seg_66():
(0x1D785, 'M', u'φ'),
(0x1D786, 'M', u'χ'),
(0x1D787, 'M', u'ψ'),
- ]
-
-def _seg_67():
- return [
(0x1D788, 'M', u'ω'),
(0x1D789, 'M', u'∂'),
(0x1D78A, 'M', u'ε'),
@@ -7064,6 +7179,10 @@ def _seg_67():
(0x1D7E1, 'M', u'9'),
(0x1D7E2, 'M', u'0'),
(0x1D7E3, 'M', u'1'),
+ ]
+
+def _seg_69():
+ return [
(0x1D7E4, 'M', u'2'),
(0x1D7E5, 'M', u'3'),
(0x1D7E6, 'M', u'4'),
@@ -7075,10 +7194,6 @@ def _seg_67():
(0x1D7EC, 'M', u'0'),
(0x1D7ED, 'M', u'1'),
(0x1D7EE, 'M', u'2'),
- ]
-
-def _seg_68():
- return [
(0x1D7EF, 'M', u'3'),
(0x1D7F0, 'M', u'4'),
(0x1D7F1, 'M', u'5'),
@@ -7112,6 +7227,18 @@ def _seg_68():
(0x1E025, 'X'),
(0x1E026, 'V'),
(0x1E02B, 'X'),
+ (0x1E100, 'V'),
+ (0x1E12D, 'X'),
+ (0x1E130, 'V'),
+ (0x1E13E, 'X'),
+ (0x1E140, 'V'),
+ (0x1E14A, 'X'),
+ (0x1E14E, 'V'),
+ (0x1E150, 'X'),
+ (0x1E2C0, 'V'),
+ (0x1E2FA, 'X'),
+ (0x1E2FF, 'V'),
+ (0x1E300, 'X'),
(0x1E800, 'V'),
(0x1E8C5, 'X'),
(0x1E8C7, 'V'),
@@ -7151,13 +7278,19 @@ def _seg_68():
(0x1E920, 'M', u'𞥂'),
(0x1E921, 'M', u'𞥃'),
(0x1E922, 'V'),
- (0x1E94B, 'X'),
+ (0x1E94C, 'X'),
(0x1E950, 'V'),
(0x1E95A, 'X'),
(0x1E95E, 'V'),
(0x1E960, 'X'),
+ ]
+
+def _seg_70():
+ return [
(0x1EC71, 'V'),
(0x1ECB5, 'X'),
+ (0x1ED01, 'V'),
+ (0x1ED3E, 'X'),
(0x1EE00, 'M', u'ا'),
(0x1EE01, 'M', u'ب'),
(0x1EE02, 'M', u'ج'),
@@ -7179,10 +7312,6 @@ def _seg_68():
(0x1EE12, 'M', u'ق'),
(0x1EE13, 'M', u'ر'),
(0x1EE14, 'M', u'ش'),
- ]
-
-def _seg_69():
- return [
(0x1EE15, 'M', u'ت'),
(0x1EE16, 'M', u'ث'),
(0x1EE17, 'M', u'خ'),
@@ -7258,6 +7387,10 @@ def _seg_69():
(0x1EE68, 'M', u'ط'),
(0x1EE69, 'M', u'ي'),
(0x1EE6A, 'M', u'ك'),
+ ]
+
+def _seg_71():
+ return [
(0x1EE6B, 'X'),
(0x1EE6C, 'M', u'م'),
(0x1EE6D, 'M', u'ن'),
@@ -7283,10 +7416,6 @@ def _seg_69():
(0x1EE81, 'M', u'ب'),
(0x1EE82, 'M', u'ج'),
(0x1EE83, 'M', u'د'),
- ]
-
-def _seg_70():
- return [
(0x1EE84, 'M', u'ه'),
(0x1EE85, 'M', u'و'),
(0x1EE86, 'M', u'ز'),
@@ -7362,10 +7491,13 @@ def _seg_70():
(0x1F106, '3', u'5,'),
(0x1F107, '3', u'6,'),
(0x1F108, '3', u'7,'),
+ ]
+
+def _seg_72():
+ return [
(0x1F109, '3', u'8,'),
(0x1F10A, '3', u'9,'),
(0x1F10B, 'V'),
- (0x1F10D, 'X'),
(0x1F110, '3', u'(a)'),
(0x1F111, '3', u'(b)'),
(0x1F112, '3', u'(c)'),
@@ -7387,10 +7519,6 @@ def _seg_70():
(0x1F122, '3', u'(s)'),
(0x1F123, '3', u'(t)'),
(0x1F124, '3', u'(u)'),
- ]
-
-def _seg_71():
- return [
(0x1F125, '3', u'(v)'),
(0x1F126, '3', u'(w)'),
(0x1F127, '3', u'(x)'),
@@ -7437,11 +7565,11 @@ def _seg_71():
(0x1F150, 'V'),
(0x1F16A, 'M', u'mc'),
(0x1F16B, 'M', u'md'),
- (0x1F16C, 'X'),
- (0x1F170, 'V'),
+ (0x1F16C, 'M', u'mr'),
+ (0x1F16D, 'V'),
(0x1F190, 'M', u'dj'),
(0x1F191, 'V'),
- (0x1F1AD, 'X'),
+ (0x1F1AE, 'X'),
(0x1F1E6, 'V'),
(0x1F200, 'M', u'ほか'),
(0x1F201, 'M', u'ココ'),
@@ -7467,6 +7595,10 @@ def _seg_71():
(0x1F221, 'M', u'終'),
(0x1F222, 'M', u'生'),
(0x1F223, 'M', u'販'),
+ ]
+
+def _seg_73():
+ return [
(0x1F224, 'M', u'声'),
(0x1F225, 'M', u'吹'),
(0x1F226, 'M', u'演'),
@@ -7491,10 +7623,6 @@ def _seg_71():
(0x1F239, 'M', u'割'),
(0x1F23A, 'M', u'営'),
(0x1F23B, 'M', u'配'),
- ]
-
-def _seg_72():
- return [
(0x1F23C, 'X'),
(0x1F240, 'M', u'〔本〕'),
(0x1F241, 'M', u'〔三〕'),
@@ -7512,15 +7640,17 @@ def _seg_72():
(0x1F260, 'V'),
(0x1F266, 'X'),
(0x1F300, 'V'),
- (0x1F6D5, 'X'),
+ (0x1F6D8, 'X'),
(0x1F6E0, 'V'),
(0x1F6ED, 'X'),
(0x1F6F0, 'V'),
- (0x1F6FA, 'X'),
+ (0x1F6FD, 'X'),
(0x1F700, 'V'),
(0x1F774, 'X'),
(0x1F780, 'V'),
(0x1F7D9, 'X'),
+ (0x1F7E0, 'V'),
+ (0x1F7EC, 'X'),
(0x1F800, 'V'),
(0x1F80C, 'X'),
(0x1F810, 'V'),
@@ -7531,28 +7661,51 @@ def _seg_72():
(0x1F888, 'X'),
(0x1F890, 'V'),
(0x1F8AE, 'X'),
+ (0x1F8B0, 'V'),
+ (0x1F8B2, 'X'),
(0x1F900, 'V'),
- (0x1F90C, 'X'),
- (0x1F910, 'V'),
- (0x1F93F, 'X'),
- (0x1F940, 'V'),
- (0x1F971, 'X'),
- (0x1F973, 'V'),
- (0x1F977, 'X'),
+ (0x1F979, 'X'),
(0x1F97A, 'V'),
- (0x1F97B, 'X'),
- (0x1F97C, 'V'),
- (0x1F9A3, 'X'),
- (0x1F9B0, 'V'),
- (0x1F9BA, 'X'),
- (0x1F9C0, 'V'),
- (0x1F9C3, 'X'),
- (0x1F9D0, 'V'),
- (0x1FA00, 'X'),
+ (0x1F9CC, 'X'),
+ (0x1F9CD, 'V'),
+ (0x1FA54, 'X'),
(0x1FA60, 'V'),
(0x1FA6E, 'X'),
+ (0x1FA70, 'V'),
+ (0x1FA75, 'X'),
+ (0x1FA78, 'V'),
+ (0x1FA7B, 'X'),
+ (0x1FA80, 'V'),
+ (0x1FA87, 'X'),
+ (0x1FA90, 'V'),
+ (0x1FAA9, 'X'),
+ (0x1FAB0, 'V'),
+ (0x1FAB7, 'X'),
+ (0x1FAC0, 'V'),
+ (0x1FAC3, 'X'),
+ (0x1FAD0, 'V'),
+ (0x1FAD7, 'X'),
+ (0x1FB00, 'V'),
+ (0x1FB93, 'X'),
+ (0x1FB94, 'V'),
+ (0x1FBCB, 'X'),
+ (0x1FBF0, 'M', u'0'),
+ (0x1FBF1, 'M', u'1'),
+ (0x1FBF2, 'M', u'2'),
+ (0x1FBF3, 'M', u'3'),
+ (0x1FBF4, 'M', u'4'),
+ (0x1FBF5, 'M', u'5'),
+ (0x1FBF6, 'M', u'6'),
+ (0x1FBF7, 'M', u'7'),
+ (0x1FBF8, 'M', u'8'),
+ (0x1FBF9, 'M', u'9'),
+ ]
+
+def _seg_74():
+ return [
+ (0x1FBFA, 'X'),
(0x20000, 'V'),
- (0x2A6D7, 'X'),
+ (0x2A6DE, 'X'),
(0x2A700, 'V'),
(0x2B735, 'X'),
(0x2B740, 'V'),
@@ -7595,10 +7748,6 @@ def _seg_72():
(0x2F81F, 'M', u'㓟'),
(0x2F820, 'M', u'刻'),
(0x2F821, 'M', u'剆'),
- ]
-
-def _seg_73():
- return [
(0x2F822, 'M', u'割'),
(0x2F823, 'M', u'剷'),
(0x2F824, 'M', u'㔕'),
@@ -7654,6 +7803,10 @@ def _seg_73():
(0x2F859, 'M', u'𡓤'),
(0x2F85A, 'M', u'売'),
(0x2F85B, 'M', u'壷'),
+ ]
+
+def _seg_75():
+ return [
(0x2F85C, 'M', u'夆'),
(0x2F85D, 'M', u'多'),
(0x2F85E, 'M', u'夢'),
@@ -7699,10 +7852,6 @@ def _seg_73():
(0x2F887, 'M', u'幩'),
(0x2F888, 'M', u'㡢'),
(0x2F889, 'M', u'𢆃'),
- ]
-
-def _seg_74():
- return [
(0x2F88A, 'M', u'㡼'),
(0x2F88B, 'M', u'庰'),
(0x2F88C, 'M', u'庳'),
@@ -7758,6 +7907,10 @@ def _seg_74():
(0x2F8C0, 'M', u'揅'),
(0x2F8C1, 'M', u'掩'),
(0x2F8C2, 'M', u'㨮'),
+ ]
+
+def _seg_76():
+ return [
(0x2F8C3, 'M', u'摩'),
(0x2F8C4, 'M', u'摾'),
(0x2F8C5, 'M', u'撝'),
@@ -7803,10 +7956,6 @@ def _seg_74():
(0x2F8ED, 'M', u'櫛'),
(0x2F8EE, 'M', u'㰘'),
(0x2F8EF, 'M', u'次'),
- ]
-
-def _seg_75():
- return [
(0x2F8F0, 'M', u'𣢧'),
(0x2F8F1, 'M', u'歔'),
(0x2F8F2, 'M', u'㱎'),
@@ -7862,6 +8011,10 @@ def _seg_75():
(0x2F924, 'M', u'犀'),
(0x2F925, 'M', u'犕'),
(0x2F926, 'M', u'𤜵'),
+ ]
+
+def _seg_77():
+ return [
(0x2F927, 'M', u'𤠔'),
(0x2F928, 'M', u'獺'),
(0x2F929, 'M', u'王'),
@@ -7907,10 +8060,6 @@ def _seg_75():
(0x2F953, 'M', u'祖'),
(0x2F954, 'M', u'𥚚'),
(0x2F955, 'M', u'𥛅'),
- ]
-
-def _seg_76():
- return [
(0x2F956, 'M', u'福'),
(0x2F957, 'M', u'秫'),
(0x2F958, 'M', u'䄯'),
@@ -7966,6 +8115,10 @@ def _seg_76():
(0x2F98B, 'M', u'舁'),
(0x2F98C, 'M', u'舄'),
(0x2F98D, 'M', u'辞'),
+ ]
+
+def _seg_78():
+ return [
(0x2F98E, 'M', u'䑫'),
(0x2F98F, 'M', u'芑'),
(0x2F990, 'M', u'芋'),
@@ -8011,10 +8164,6 @@ def _seg_76():
(0x2F9B8, 'M', u'蚈'),
(0x2F9B9, 'M', u'蜎'),
(0x2F9BA, 'M', u'蛢'),
- ]
-
-def _seg_77():
- return [
(0x2F9BB, 'M', u'蝹'),
(0x2F9BC, 'M', u'蜨'),
(0x2F9BD, 'M', u'蝫'),
@@ -8070,6 +8219,10 @@ def _seg_77():
(0x2F9EF, 'M', u'䦕'),
(0x2F9F0, 'M', u'閷'),
(0x2F9F1, 'M', u'𨵷'),
+ ]
+
+def _seg_79():
+ return [
(0x2F9F2, 'M', u'䧦'),
(0x2F9F3, 'M', u'雃'),
(0x2F9F4, 'M', u'嶲'),
@@ -8114,11 +8267,9 @@ def _seg_77():
(0x2FA1C, 'M', u'鼻'),
(0x2FA1D, 'M', u'𪘀'),
(0x2FA1E, 'X'),
+ (0x30000, 'V'),
+ (0x3134B, 'X'),
(0xE0100, 'I'),
- ]
-
-def _seg_78():
- return [
(0xE01F0, 'X'),
]
@@ -8202,4 +8353,5 @@ uts46data = tuple(
+ _seg_76()
+ _seg_77()
+ _seg_78()
+ + _seg_79()
)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/ipaddress.py b/venv/lib/python3.8/site-packages/pip/_vendor/ipaddress.py
index f2d0766..3e6f9e4 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/ipaddress.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/ipaddress.py
@@ -14,7 +14,7 @@ from __future__ import unicode_literals
import itertools
import struct
-__version__ = '1.0.22'
+__version__ = '1.0.23'
# Compatibility functions
_compat_int_types = (int,)
@@ -1103,7 +1103,8 @@ class _BaseNetwork(_IPAddressBase):
try:
# Always false if one is v4 and the other is v6.
if a._version != b._version:
- raise TypeError("%s and %s are not of the same version" (a, b))
+ raise TypeError(
+ "%s and %s are not of the same version" % (a, b))
return (b.network_address <= a.network_address and
b.broadcast_address >= a.broadcast_address)
except AttributeError:
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__init__.py
deleted file mode 100644
index a6f44a5..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__init__.py
+++ /dev/null
@@ -1,347 +0,0 @@
-# -*- coding: utf-8 -*-
-
-"""
-lockfile.py - Platform-independent advisory file locks.
-
-Requires Python 2.5 unless you apply 2.4.diff
-Locking is done on a per-thread basis instead of a per-process basis.
-
-Usage:
-
->>> lock = LockFile('somefile')
->>> try:
-... lock.acquire()
-... except AlreadyLocked:
-... print 'somefile', 'is locked already.'
-... except LockFailed:
-... print 'somefile', 'can\\'t be locked.'
-... else:
-... print 'got lock'
-got lock
->>> print lock.is_locked()
-True
->>> lock.release()
-
->>> lock = LockFile('somefile')
->>> print lock.is_locked()
-False
->>> with lock:
-... print lock.is_locked()
-True
->>> print lock.is_locked()
-False
-
->>> lock = LockFile('somefile')
->>> # It is okay to lock twice from the same thread...
->>> with lock:
-... lock.acquire()
-...
->>> # Though no counter is kept, so you can't unlock multiple times...
->>> print lock.is_locked()
-False
-
-Exceptions:
-
- Error - base class for other exceptions
- LockError - base class for all locking exceptions
- AlreadyLocked - Another thread or process already holds the lock
- LockFailed - Lock failed for some other reason
- UnlockError - base class for all unlocking exceptions
- AlreadyUnlocked - File was not locked.
- NotMyLock - File was locked but not by the current thread/process
-"""
-
-from __future__ import absolute_import
-
-import functools
-import os
-import socket
-import threading
-import warnings
-
-# Work with PEP8 and non-PEP8 versions of threading module.
-if not hasattr(threading, "current_thread"):
- threading.current_thread = threading.currentThread
-if not hasattr(threading.Thread, "get_name"):
- threading.Thread.get_name = threading.Thread.getName
-
-__all__ = ['Error', 'LockError', 'LockTimeout', 'AlreadyLocked',
- 'LockFailed', 'UnlockError', 'NotLocked', 'NotMyLock',
- 'LinkFileLock', 'MkdirFileLock', 'SQLiteFileLock',
- 'LockBase', 'locked']
-
-
-class Error(Exception):
- """
- Base class for other exceptions.
-
- >>> try:
- ... raise Error
- ... except Exception:
- ... pass
- """
- pass
-
-
-class LockError(Error):
- """
- Base class for error arising from attempts to acquire the lock.
-
- >>> try:
- ... raise LockError
- ... except Error:
- ... pass
- """
- pass
-
-
-class LockTimeout(LockError):
- """Raised when lock creation fails within a user-defined period of time.
-
- >>> try:
- ... raise LockTimeout
- ... except LockError:
- ... pass
- """
- pass
-
-
-class AlreadyLocked(LockError):
- """Some other thread/process is locking the file.
-
- >>> try:
- ... raise AlreadyLocked
- ... except LockError:
- ... pass
- """
- pass
-
-
-class LockFailed(LockError):
- """Lock file creation failed for some other reason.
-
- >>> try:
- ... raise LockFailed
- ... except LockError:
- ... pass
- """
- pass
-
-
-class UnlockError(Error):
- """
- Base class for errors arising from attempts to release the lock.
-
- >>> try:
- ... raise UnlockError
- ... except Error:
- ... pass
- """
- pass
-
-
-class NotLocked(UnlockError):
- """Raised when an attempt is made to unlock an unlocked file.
-
- >>> try:
- ... raise NotLocked
- ... except UnlockError:
- ... pass
- """
- pass
-
-
-class NotMyLock(UnlockError):
- """Raised when an attempt is made to unlock a file someone else locked.
-
- >>> try:
- ... raise NotMyLock
- ... except UnlockError:
- ... pass
- """
- pass
-
-
-class _SharedBase(object):
- def __init__(self, path):
- self.path = path
-
- def acquire(self, timeout=None):
- """
- Acquire the lock.
-
- * If timeout is omitted (or None), wait forever trying to lock the
- file.
-
- * If timeout > 0, try to acquire the lock for that many seconds. If
- the lock period expires and the file is still locked, raise
- LockTimeout.
-
- * If timeout <= 0, raise AlreadyLocked immediately if the file is
- already locked.
- """
- raise NotImplemented("implement in subclass")
-
- def release(self):
- """
- Release the lock.
-
- If the file is not locked, raise NotLocked.
- """
- raise NotImplemented("implement in subclass")
-
- def __enter__(self):
- """
- Context manager support.
- """
- self.acquire()
- return self
-
- def __exit__(self, *_exc):
- """
- Context manager support.
- """
- self.release()
-
- def __repr__(self):
- return "<%s: %r>" % (self.__class__.__name__, self.path)
-
-
-class LockBase(_SharedBase):
- """Base class for platform-specific lock classes."""
- def __init__(self, path, threaded=True, timeout=None):
- """
- >>> lock = LockBase('somefile')
- >>> lock = LockBase('somefile', threaded=False)
- """
- super(LockBase, self).__init__(path)
- self.lock_file = os.path.abspath(path) + ".lock"
- self.hostname = socket.gethostname()
- self.pid = os.getpid()
- if threaded:
- t = threading.current_thread()
- # Thread objects in Python 2.4 and earlier do not have ident
- # attrs. Worm around that.
- ident = getattr(t, "ident", hash(t))
- self.tname = "-%x" % (ident & 0xffffffff)
- else:
- self.tname = ""
- dirname = os.path.dirname(self.lock_file)
-
- # unique name is mostly about the current process, but must
- # also contain the path -- otherwise, two adjacent locked
- # files conflict (one file gets locked, creating lock-file and
- # unique file, the other one gets locked, creating lock-file
- # and overwriting the already existing lock-file, then one
- # gets unlocked, deleting both lock-file and unique file,
- # finally the last lock errors out upon releasing.
- self.unique_name = os.path.join(dirname,
- "%s%s.%s%s" % (self.hostname,
- self.tname,
- self.pid,
- hash(self.path)))
- self.timeout = timeout
-
- def is_locked(self):
- """
- Tell whether or not the file is locked.
- """
- raise NotImplemented("implement in subclass")
-
- def i_am_locking(self):
- """
- Return True if this object is locking the file.
- """
- raise NotImplemented("implement in subclass")
-
- def break_lock(self):
- """
- Remove a lock. Useful if a locking thread failed to unlock.
- """
- raise NotImplemented("implement in subclass")
-
- def __repr__(self):
- return "<%s: %r -- %r>" % (self.__class__.__name__, self.unique_name,
- self.path)
-
-
-def _fl_helper(cls, mod, *args, **kwds):
- warnings.warn("Import from %s module instead of lockfile package" % mod,
- DeprecationWarning, stacklevel=2)
- # This is a bit funky, but it's only for awhile. The way the unit tests
- # are constructed this function winds up as an unbound method, so it
- # actually takes three args, not two. We want to toss out self.
- if not isinstance(args[0], str):
- # We are testing, avoid the first arg
- args = args[1:]
- if len(args) == 1 and not kwds:
- kwds["threaded"] = True
- return cls(*args, **kwds)
-
-
-def LinkFileLock(*args, **kwds):
- """Factory function provided for backwards compatibility.
-
- Do not use in new code. Instead, import LinkLockFile from the
- lockfile.linklockfile module.
- """
- from . import linklockfile
- return _fl_helper(linklockfile.LinkLockFile, "lockfile.linklockfile",
- *args, **kwds)
-
-
-def MkdirFileLock(*args, **kwds):
- """Factory function provided for backwards compatibility.
-
- Do not use in new code. Instead, import MkdirLockFile from the
- lockfile.mkdirlockfile module.
- """
- from . import mkdirlockfile
- return _fl_helper(mkdirlockfile.MkdirLockFile, "lockfile.mkdirlockfile",
- *args, **kwds)
-
-
-def SQLiteFileLock(*args, **kwds):
- """Factory function provided for backwards compatibility.
-
- Do not use in new code. Instead, import SQLiteLockFile from the
- lockfile.mkdirlockfile module.
- """
- from . import sqlitelockfile
- return _fl_helper(sqlitelockfile.SQLiteLockFile, "lockfile.sqlitelockfile",
- *args, **kwds)
-
-
-def locked(path, timeout=None):
- """Decorator which enables locks for decorated function.
-
- Arguments:
- - path: path for lockfile.
- - timeout (optional): Timeout for acquiring lock.
-
- Usage:
- @locked('/var/run/myname', timeout=0)
- def myname(...):
- ...
- """
- def decor(func):
- @functools.wraps(func)
- def wrapper(*args, **kwargs):
- lock = FileLock(path, timeout=timeout)
- lock.acquire()
- try:
- return func(*args, **kwargs)
- finally:
- lock.release()
- return wrapper
- return decor
-
-
-if hasattr(os, "link"):
- from . import linklockfile as _llf
- LockFile = _llf.LinkLockFile
-else:
- from . import mkdirlockfile as _mlf
- LockFile = _mlf.MkdirLockFile
-
-FileLock = LockFile
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__pycache__/__init__.cpython-38.pyc
deleted file mode 100644
index 4b051b5..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__pycache__/__init__.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__pycache__/linklockfile.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__pycache__/linklockfile.cpython-38.pyc
deleted file mode 100644
index 74ccf11..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__pycache__/linklockfile.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__pycache__/mkdirlockfile.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__pycache__/mkdirlockfile.cpython-38.pyc
deleted file mode 100644
index d3a110e..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__pycache__/mkdirlockfile.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__pycache__/pidlockfile.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__pycache__/pidlockfile.cpython-38.pyc
deleted file mode 100644
index 42efb16..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__pycache__/pidlockfile.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__pycache__/sqlitelockfile.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__pycache__/sqlitelockfile.cpython-38.pyc
deleted file mode 100644
index 1e38b76..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__pycache__/sqlitelockfile.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__pycache__/symlinklockfile.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__pycache__/symlinklockfile.cpython-38.pyc
deleted file mode 100644
index f756204..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/__pycache__/symlinklockfile.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/linklockfile.py b/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/linklockfile.py
deleted file mode 100644
index 2ca9be0..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/linklockfile.py
+++ /dev/null
@@ -1,73 +0,0 @@
-from __future__ import absolute_import
-
-import time
-import os
-
-from . import (LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout,
- AlreadyLocked)
-
-
-class LinkLockFile(LockBase):
- """Lock access to a file using atomic property of link(2).
-
- >>> lock = LinkLockFile('somefile')
- >>> lock = LinkLockFile('somefile', threaded=False)
- """
-
- def acquire(self, timeout=None):
- try:
- open(self.unique_name, "wb").close()
- except IOError:
- raise LockFailed("failed to create %s" % self.unique_name)
-
- timeout = timeout if timeout is not None else self.timeout
- end_time = time.time()
- if timeout is not None and timeout > 0:
- end_time += timeout
-
- while True:
- # Try and create a hard link to it.
- try:
- os.link(self.unique_name, self.lock_file)
- except OSError:
- # Link creation failed. Maybe we've double-locked?
- nlinks = os.stat(self.unique_name).st_nlink
- if nlinks == 2:
- # The original link plus the one I created == 2. We're
- # good to go.
- return
- else:
- # Otherwise the lock creation failed.
- if timeout is not None and time.time() > end_time:
- os.unlink(self.unique_name)
- if timeout > 0:
- raise LockTimeout("Timeout waiting to acquire"
- " lock for %s" %
- self.path)
- else:
- raise AlreadyLocked("%s is already locked" %
- self.path)
- time.sleep(timeout is not None and timeout / 10 or 0.1)
- else:
- # Link creation succeeded. We're good to go.
- return
-
- def release(self):
- if not self.is_locked():
- raise NotLocked("%s is not locked" % self.path)
- elif not os.path.exists(self.unique_name):
- raise NotMyLock("%s is locked, but not by me" % self.path)
- os.unlink(self.unique_name)
- os.unlink(self.lock_file)
-
- def is_locked(self):
- return os.path.exists(self.lock_file)
-
- def i_am_locking(self):
- return (self.is_locked() and
- os.path.exists(self.unique_name) and
- os.stat(self.unique_name).st_nlink == 2)
-
- def break_lock(self):
- if os.path.exists(self.lock_file):
- os.unlink(self.lock_file)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/mkdirlockfile.py b/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/mkdirlockfile.py
deleted file mode 100644
index 05a8c96..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/mkdirlockfile.py
+++ /dev/null
@@ -1,84 +0,0 @@
-from __future__ import absolute_import, division
-
-import time
-import os
-import sys
-import errno
-
-from . import (LockBase, LockFailed, NotLocked, NotMyLock, LockTimeout,
- AlreadyLocked)
-
-
-class MkdirLockFile(LockBase):
- """Lock file by creating a directory."""
- def __init__(self, path, threaded=True, timeout=None):
- """
- >>> lock = MkdirLockFile('somefile')
- >>> lock = MkdirLockFile('somefile', threaded=False)
- """
- LockBase.__init__(self, path, threaded, timeout)
- # Lock file itself is a directory. Place the unique file name into
- # it.
- self.unique_name = os.path.join(self.lock_file,
- "%s.%s%s" % (self.hostname,
- self.tname,
- self.pid))
-
- def acquire(self, timeout=None):
- timeout = timeout if timeout is not None else self.timeout
- end_time = time.time()
- if timeout is not None and timeout > 0:
- end_time += timeout
-
- if timeout is None:
- wait = 0.1
- else:
- wait = max(0, timeout / 10)
-
- while True:
- try:
- os.mkdir(self.lock_file)
- except OSError:
- err = sys.exc_info()[1]
- if err.errno == errno.EEXIST:
- # Already locked.
- if os.path.exists(self.unique_name):
- # Already locked by me.
- return
- if timeout is not None and time.time() > end_time:
- if timeout > 0:
- raise LockTimeout("Timeout waiting to acquire"
- " lock for %s" %
- self.path)
- else:
- # Someone else has the lock.
- raise AlreadyLocked("%s is already locked" %
- self.path)
- time.sleep(wait)
- else:
- # Couldn't create the lock for some other reason
- raise LockFailed("failed to create %s" % self.lock_file)
- else:
- open(self.unique_name, "wb").close()
- return
-
- def release(self):
- if not self.is_locked():
- raise NotLocked("%s is not locked" % self.path)
- elif not os.path.exists(self.unique_name):
- raise NotMyLock("%s is locked, but not by me" % self.path)
- os.unlink(self.unique_name)
- os.rmdir(self.lock_file)
-
- def is_locked(self):
- return os.path.exists(self.lock_file)
-
- def i_am_locking(self):
- return (self.is_locked() and
- os.path.exists(self.unique_name))
-
- def break_lock(self):
- if os.path.exists(self.lock_file):
- for name in os.listdir(self.lock_file):
- os.unlink(os.path.join(self.lock_file, name))
- os.rmdir(self.lock_file)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/pidlockfile.py b/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/pidlockfile.py
deleted file mode 100644
index 069e85b..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/pidlockfile.py
+++ /dev/null
@@ -1,190 +0,0 @@
-# -*- coding: utf-8 -*-
-
-# pidlockfile.py
-#
-# Copyright © 2008–2009 Ben Finney
-#
-# This is free software: you may copy, modify, and/or distribute this work
-# under the terms of the Python Software Foundation License, version 2 or
-# later as published by the Python Software Foundation.
-# No warranty expressed or implied. See the file LICENSE.PSF-2 for details.
-
-""" Lockfile behaviour implemented via Unix PID files.
- """
-
-from __future__ import absolute_import
-
-import errno
-import os
-import time
-
-from . import (LockBase, AlreadyLocked, LockFailed, NotLocked, NotMyLock,
- LockTimeout)
-
-
-class PIDLockFile(LockBase):
- """ Lockfile implemented as a Unix PID file.
-
- The lock file is a normal file named by the attribute `path`.
- A lock's PID file contains a single line of text, containing
- the process ID (PID) of the process that acquired the lock.
-
- >>> lock = PIDLockFile('somefile')
- >>> lock = PIDLockFile('somefile')
- """
-
- def __init__(self, path, threaded=False, timeout=None):
- # pid lockfiles don't support threaded operation, so always force
- # False as the threaded arg.
- LockBase.__init__(self, path, False, timeout)
- self.unique_name = self.path
-
- def read_pid(self):
- """ Get the PID from the lock file.
- """
- return read_pid_from_pidfile(self.path)
-
- def is_locked(self):
- """ Test if the lock is currently held.
-
- The lock is held if the PID file for this lock exists.
-
- """
- return os.path.exists(self.path)
-
- def i_am_locking(self):
- """ Test if the lock is held by the current process.
-
- Returns ``True`` if the current process ID matches the
- number stored in the PID file.
- """
- return self.is_locked() and os.getpid() == self.read_pid()
-
- def acquire(self, timeout=None):
- """ Acquire the lock.
-
- Creates the PID file for this lock, or raises an error if
- the lock could not be acquired.
- """
-
- timeout = timeout if timeout is not None else self.timeout
- end_time = time.time()
- if timeout is not None and timeout > 0:
- end_time += timeout
-
- while True:
- try:
- write_pid_to_pidfile(self.path)
- except OSError as exc:
- if exc.errno == errno.EEXIST:
- # The lock creation failed. Maybe sleep a bit.
- if time.time() > end_time:
- if timeout is not None and timeout > 0:
- raise LockTimeout("Timeout waiting to acquire"
- " lock for %s" %
- self.path)
- else:
- raise AlreadyLocked("%s is already locked" %
- self.path)
- time.sleep(timeout is not None and timeout / 10 or 0.1)
- else:
- raise LockFailed("failed to create %s" % self.path)
- else:
- return
-
- def release(self):
- """ Release the lock.
-
- Removes the PID file to release the lock, or raises an
- error if the current process does not hold the lock.
-
- """
- if not self.is_locked():
- raise NotLocked("%s is not locked" % self.path)
- if not self.i_am_locking():
- raise NotMyLock("%s is locked, but not by me" % self.path)
- remove_existing_pidfile(self.path)
-
- def break_lock(self):
- """ Break an existing lock.
-
- Removes the PID file if it already exists, otherwise does
- nothing.
-
- """
- remove_existing_pidfile(self.path)
-
-
-def read_pid_from_pidfile(pidfile_path):
- """ Read the PID recorded in the named PID file.
-
- Read and return the numeric PID recorded as text in the named
- PID file. If the PID file cannot be read, or if the content is
- not a valid PID, return ``None``.
-
- """
- pid = None
- try:
- pidfile = open(pidfile_path, 'r')
- except IOError:
- pass
- else:
- # According to the FHS 2.3 section on PID files in /var/run:
- #
- # The file must consist of the process identifier in
- # ASCII-encoded decimal, followed by a newline character.
- #
- # Programs that read PID files should be somewhat flexible
- # in what they accept; i.e., they should ignore extra
- # whitespace, leading zeroes, absence of the trailing
- # newline, or additional lines in the PID file.
-
- line = pidfile.readline().strip()
- try:
- pid = int(line)
- except ValueError:
- pass
- pidfile.close()
-
- return pid
-
-
-def write_pid_to_pidfile(pidfile_path):
- """ Write the PID in the named PID file.
-
- Get the numeric process ID (“PID”) of the current process
- and write it to the named file as a line of text.
-
- """
- open_flags = (os.O_CREAT | os.O_EXCL | os.O_WRONLY)
- open_mode = 0o644
- pidfile_fd = os.open(pidfile_path, open_flags, open_mode)
- pidfile = os.fdopen(pidfile_fd, 'w')
-
- # According to the FHS 2.3 section on PID files in /var/run:
- #
- # The file must consist of the process identifier in
- # ASCII-encoded decimal, followed by a newline character. For
- # example, if crond was process number 25, /var/run/crond.pid
- # would contain three characters: two, five, and newline.
-
- pid = os.getpid()
- pidfile.write("%s\n" % pid)
- pidfile.close()
-
-
-def remove_existing_pidfile(pidfile_path):
- """ Remove the named PID file if it exists.
-
- Removing a PID file that doesn't already exist puts us in the
- desired state, so we ignore the condition if the file does not
- exist.
-
- """
- try:
- os.remove(pidfile_path)
- except OSError as exc:
- if exc.errno == errno.ENOENT:
- pass
- else:
- raise
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/sqlitelockfile.py b/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/sqlitelockfile.py
deleted file mode 100644
index f997e24..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/sqlitelockfile.py
+++ /dev/null
@@ -1,156 +0,0 @@
-from __future__ import absolute_import, division
-
-import time
-import os
-
-try:
- unicode
-except NameError:
- unicode = str
-
-from . import LockBase, NotLocked, NotMyLock, LockTimeout, AlreadyLocked
-
-
-class SQLiteLockFile(LockBase):
- "Demonstrate SQL-based locking."
-
- testdb = None
-
- def __init__(self, path, threaded=True, timeout=None):
- """
- >>> lock = SQLiteLockFile('somefile')
- >>> lock = SQLiteLockFile('somefile', threaded=False)
- """
- LockBase.__init__(self, path, threaded, timeout)
- self.lock_file = unicode(self.lock_file)
- self.unique_name = unicode(self.unique_name)
-
- if SQLiteLockFile.testdb is None:
- import tempfile
- _fd, testdb = tempfile.mkstemp()
- os.close(_fd)
- os.unlink(testdb)
- del _fd, tempfile
- SQLiteLockFile.testdb = testdb
-
- import sqlite3
- self.connection = sqlite3.connect(SQLiteLockFile.testdb)
-
- c = self.connection.cursor()
- try:
- c.execute("create table locks"
- "("
- " lock_file varchar(32),"
- " unique_name varchar(32)"
- ")")
- except sqlite3.OperationalError:
- pass
- else:
- self.connection.commit()
- import atexit
- atexit.register(os.unlink, SQLiteLockFile.testdb)
-
- def acquire(self, timeout=None):
- timeout = timeout if timeout is not None else self.timeout
- end_time = time.time()
- if timeout is not None and timeout > 0:
- end_time += timeout
-
- if timeout is None:
- wait = 0.1
- elif timeout <= 0:
- wait = 0
- else:
- wait = timeout / 10
-
- cursor = self.connection.cursor()
-
- while True:
- if not self.is_locked():
- # Not locked. Try to lock it.
- cursor.execute("insert into locks"
- " (lock_file, unique_name)"
- " values"
- " (?, ?)",
- (self.lock_file, self.unique_name))
- self.connection.commit()
-
- # Check to see if we are the only lock holder.
- cursor.execute("select * from locks"
- " where unique_name = ?",
- (self.unique_name,))
- rows = cursor.fetchall()
- if len(rows) > 1:
- # Nope. Someone else got there. Remove our lock.
- cursor.execute("delete from locks"
- " where unique_name = ?",
- (self.unique_name,))
- self.connection.commit()
- else:
- # Yup. We're done, so go home.
- return
- else:
- # Check to see if we are the only lock holder.
- cursor.execute("select * from locks"
- " where unique_name = ?",
- (self.unique_name,))
- rows = cursor.fetchall()
- if len(rows) == 1:
- # We're the locker, so go home.
- return
-
- # Maybe we should wait a bit longer.
- if timeout is not None and time.time() > end_time:
- if timeout > 0:
- # No more waiting.
- raise LockTimeout("Timeout waiting to acquire"
- " lock for %s" %
- self.path)
- else:
- # Someone else has the lock and we are impatient..
- raise AlreadyLocked("%s is already locked" % self.path)
-
- # Well, okay. We'll give it a bit longer.
- time.sleep(wait)
-
- def release(self):
- if not self.is_locked():
- raise NotLocked("%s is not locked" % self.path)
- if not self.i_am_locking():
- raise NotMyLock("%s is locked, but not by me (by %s)" %
- (self.unique_name, self._who_is_locking()))
- cursor = self.connection.cursor()
- cursor.execute("delete from locks"
- " where unique_name = ?",
- (self.unique_name,))
- self.connection.commit()
-
- def _who_is_locking(self):
- cursor = self.connection.cursor()
- cursor.execute("select unique_name from locks"
- " where lock_file = ?",
- (self.lock_file,))
- return cursor.fetchone()[0]
-
- def is_locked(self):
- cursor = self.connection.cursor()
- cursor.execute("select * from locks"
- " where lock_file = ?",
- (self.lock_file,))
- rows = cursor.fetchall()
- return not not rows
-
- def i_am_locking(self):
- cursor = self.connection.cursor()
- cursor.execute("select * from locks"
- " where lock_file = ?"
- " and unique_name = ?",
- (self.lock_file, self.unique_name))
- return not not cursor.fetchall()
-
- def break_lock(self):
- cursor = self.connection.cursor()
- cursor.execute("delete from locks"
- " where lock_file = ?",
- (self.lock_file,))
- self.connection.commit()
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/symlinklockfile.py b/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/symlinklockfile.py
deleted file mode 100644
index 23b41f5..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/lockfile/symlinklockfile.py
+++ /dev/null
@@ -1,70 +0,0 @@
-from __future__ import absolute_import
-
-import os
-import time
-
-from . import (LockBase, NotLocked, NotMyLock, LockTimeout,
- AlreadyLocked)
-
-
-class SymlinkLockFile(LockBase):
- """Lock access to a file using symlink(2)."""
-
- def __init__(self, path, threaded=True, timeout=None):
- # super(SymlinkLockFile).__init(...)
- LockBase.__init__(self, path, threaded, timeout)
- # split it back!
- self.unique_name = os.path.split(self.unique_name)[1]
-
- def acquire(self, timeout=None):
- # Hopefully unnecessary for symlink.
- # try:
- # open(self.unique_name, "wb").close()
- # except IOError:
- # raise LockFailed("failed to create %s" % self.unique_name)
- timeout = timeout if timeout is not None else self.timeout
- end_time = time.time()
- if timeout is not None and timeout > 0:
- end_time += timeout
-
- while True:
- # Try and create a symbolic link to it.
- try:
- os.symlink(self.unique_name, self.lock_file)
- except OSError:
- # Link creation failed. Maybe we've double-locked?
- if self.i_am_locking():
- # Linked to out unique name. Proceed.
- return
- else:
- # Otherwise the lock creation failed.
- if timeout is not None and time.time() > end_time:
- if timeout > 0:
- raise LockTimeout("Timeout waiting to acquire"
- " lock for %s" %
- self.path)
- else:
- raise AlreadyLocked("%s is already locked" %
- self.path)
- time.sleep(timeout / 10 if timeout is not None else 0.1)
- else:
- # Link creation succeeded. We're good to go.
- return
-
- def release(self):
- if not self.is_locked():
- raise NotLocked("%s is not locked" % self.path)
- elif not self.i_am_locking():
- raise NotMyLock("%s is locked, but not by me" % self.path)
- os.unlink(self.lock_file)
-
- def is_locked(self):
- return os.path.islink(self.lock_file)
-
- def i_am_locking(self):
- return (os.path.islink(self.lock_file)
- and os.readlink(self.lock_file) == self.unique_name)
-
- def break_lock(self):
- if os.path.islink(self.lock_file): # exists && link
- os.unlink(self.lock_file)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__init__.py
index b326507..d6705e2 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__init__.py
@@ -1,30 +1,19 @@
# coding: utf-8
-from pip._vendor.msgpack._version import version
-from pip._vendor.msgpack.exceptions import *
-
-from collections import namedtuple
-
-
-class ExtType(namedtuple('ExtType', 'code data')):
- """ExtType represents ext type in msgpack."""
- def __new__(cls, code, data):
- if not isinstance(code, int):
- raise TypeError("code must be int")
- if not isinstance(data, bytes):
- raise TypeError("data must be bytes")
- if not 0 <= code <= 127:
- raise ValueError("code must be 0~127")
- return super(ExtType, cls).__new__(cls, code, data)
-
+from ._version import version
+from .exceptions import *
+from .ext import ExtType, Timestamp
import os
-if os.environ.get('MSGPACK_PUREPYTHON'):
- from pip._vendor.msgpack.fallback import Packer, unpackb, Unpacker
+import sys
+
+
+if os.environ.get("MSGPACK_PUREPYTHON") or sys.version_info[0] == 2:
+ from .fallback import Packer, unpackb, Unpacker
else:
try:
- from pip._vendor.msgpack._cmsgpack import Packer, unpackb, Unpacker
+ from ._cmsgpack import Packer, unpackb, Unpacker
except ImportError:
- from pip._vendor.msgpack.fallback import Packer, unpackb, Unpacker
+ from .fallback import Packer, unpackb, Unpacker
def pack(o, stream, **kwargs):
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-38.pyc
index edf9028..83b4e7f 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__pycache__/_version.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__pycache__/_version.cpython-38.pyc
index 6add40b..5770999 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__pycache__/_version.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__pycache__/_version.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-38.pyc
index f06c8a4..707f3f4 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-38.pyc
index dbc4adc..219d73f 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/_version.py b/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/_version.py
index 926c5e7..9f55cf5 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/_version.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/_version.py
@@ -1 +1 @@
-version = (0, 6, 1)
+version = (1, 0, 0)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/fallback.py b/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/fallback.py
index 5b731dd..9f6665b 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/fallback.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/msgpack/fallback.py
@@ -1,86 +1,98 @@
"""Fallback pure Python implementation of msgpack"""
+from datetime import datetime as _DateTime
import sys
import struct
-import warnings
-if sys.version_info[0] == 2:
- PY2 = True
+PY2 = sys.version_info[0] == 2
+if PY2:
int_types = (int, long)
+
def dict_iteritems(d):
return d.iteritems()
+
+
else:
- PY2 = False
int_types = int
unicode = str
xrange = range
+
def dict_iteritems(d):
return d.items()
+
if sys.version_info < (3, 5):
# Ugly hack...
RecursionError = RuntimeError
def _is_recursionerror(e):
- return len(e.args) == 1 and isinstance(e.args[0], str) and \
- e.args[0].startswith('maximum recursion depth exceeded')
+ return (
+ len(e.args) == 1
+ and isinstance(e.args[0], str)
+ and e.args[0].startswith("maximum recursion depth exceeded")
+ )
+
+
else:
+
def _is_recursionerror(e):
return True
-if hasattr(sys, 'pypy_version_info'):
- # cStringIO is slow on PyPy, StringIO is faster. However: PyPy's own
+
+if hasattr(sys, "pypy_version_info"):
+ # StringIO is slow on PyPy, StringIO is faster. However: PyPy's own
# StringBuilder is fastest.
from __pypy__ import newlist_hint
+
try:
from __pypy__.builders import BytesBuilder as StringBuilder
except ImportError:
from __pypy__.builders import StringBuilder
USING_STRINGBUILDER = True
+
class StringIO(object):
- def __init__(self, s=b''):
+ def __init__(self, s=b""):
if s:
self.builder = StringBuilder(len(s))
self.builder.append(s)
else:
self.builder = StringBuilder()
+
def write(self, s):
if isinstance(s, memoryview):
s = s.tobytes()
elif isinstance(s, bytearray):
s = bytes(s)
self.builder.append(s)
+
def getvalue(self):
return self.builder.build()
+
+
else:
USING_STRINGBUILDER = False
from io import BytesIO as StringIO
+
newlist_hint = lambda size: []
-from pip._vendor.msgpack.exceptions import (
- BufferFull,
- OutOfData,
- ExtraData,
- FormatError,
- StackError,
-)
+from .exceptions import BufferFull, OutOfData, ExtraData, FormatError, StackError
-from pip._vendor.msgpack import ExtType
+from .ext import ExtType, Timestamp
-EX_SKIP = 0
-EX_CONSTRUCT = 1
-EX_READ_ARRAY_HEADER = 2
-EX_READ_MAP_HEADER = 3
+EX_SKIP = 0
+EX_CONSTRUCT = 1
+EX_READ_ARRAY_HEADER = 2
+EX_READ_MAP_HEADER = 3
-TYPE_IMMEDIATE = 0
-TYPE_ARRAY = 1
-TYPE_MAP = 2
-TYPE_RAW = 3
-TYPE_BIN = 4
-TYPE_EXT = 5
+TYPE_IMMEDIATE = 0
+TYPE_ARRAY = 1
+TYPE_MAP = 2
+TYPE_RAW = 3
+TYPE_BIN = 4
+TYPE_EXT = 5
DEFAULT_RECURSE_LIMIT = 511
@@ -93,31 +105,12 @@ def _check_type_strict(obj, t, type=type, tuple=tuple):
def _get_data_from_buffer(obj):
- try:
- view = memoryview(obj)
- except TypeError:
- # try to use legacy buffer protocol if 2.7, otherwise re-raise
- if PY2:
- view = memoryview(buffer(obj))
- warnings.warn("using old buffer interface to unpack %s; "
- "this leads to unpacking errors if slicing is used and "
- "will be removed in a future version" % type(obj),
- RuntimeWarning, stacklevel=3)
- else:
- raise
+ view = memoryview(obj)
if view.itemsize != 1:
raise ValueError("cannot unpack from multi-byte object")
return view
-def unpack(stream, **kwargs):
- warnings.warn(
- "Direct calling implementation's unpack() is deprecated, Use msgpack.unpack() or unpackb() instead.",
- DeprecationWarning, stacklevel=2)
- data = stream.read()
- return unpackb(data, **kwargs)
-
-
def unpackb(packed, **kwargs):
"""
Unpack an object from `packed`.
@@ -146,9 +139,12 @@ def unpackb(packed, **kwargs):
if sys.version_info < (2, 7, 6):
+
def _unpack_from(f, b, o=0):
- """Explicit typcast for legacy struct.unpack_from"""
+ """Explicit type cast for legacy struct.unpack_from"""
return struct.unpack_from(f, bytes(b), o)
+
+
else:
_unpack_from = struct.unpack_from
@@ -156,7 +152,7 @@ else:
class Unpacker(object):
"""Streaming unpacker.
- arguments:
+ Arguments:
:param file_like:
File-like object having `.read(n)` method.
@@ -170,19 +166,19 @@ class Unpacker(object):
Otherwise, unpack to Python tuple. (default: True)
:param bool raw:
- If true, unpack msgpack raw to Python bytes (default).
- Otherwise, unpack to Python str (or unicode on Python 2) by decoding
- with UTF-8 encoding (recommended).
- Currently, the default is true, but it will be changed to false in
- near future. So you must specify it explicitly for keeping backward
- compatibility.
+ If true, unpack msgpack raw to Python bytes.
+ Otherwise, unpack to Python str by decoding with UTF-8 encoding (default).
- *encoding* option which is deprecated overrides this option.
+ :param int timestamp:
+ Control how timestamp type is unpacked:
+
+ 0 - Timestamp
+ 1 - float (Seconds from the EPOCH)
+ 2 - int (Nanoseconds from the EPOCH)
+ 3 - datetime.datetime (UTC). Python 2 is not supported.
:param bool strict_map_key:
- If true, only str or bytes are accepted for map (dict) keys.
- It's False by default for backward-compatibility.
- But it will be True from msgpack 1.0.
+ If true (default), only str or bytes are accepted for map (dict) keys.
:param callable object_hook:
When specified, it should be callable.
@@ -194,48 +190,46 @@ class Unpacker(object):
Unpacker calls it with a list of key-value pairs after unpacking msgpack map.
(See also simplejson)
- :param str encoding:
- Encoding used for decoding msgpack raw.
- If it is None (default), msgpack raw is deserialized to Python bytes.
-
:param str unicode_errors:
- (deprecated) Used for decoding msgpack raw with *encoding*.
- (default: `'strict'`)
+ The error handler for decoding unicode. (default: 'strict')
+ This option should be used only when you have msgpack data which
+ contains invalid UTF-8 string.
:param int max_buffer_size:
- Limits size of data waiting unpacked. 0 means system's INT_MAX (default).
+ Limits size of data waiting unpacked. 0 means 2**32-1.
+ The default value is 100*1024*1024 (100MiB).
Raises `BufferFull` exception when it is insufficient.
You should set this parameter when unpacking data from untrusted source.
:param int max_str_len:
Deprecated, use *max_buffer_size* instead.
- Limits max length of str. (default: max_buffer_size or 1024*1024)
+ Limits max length of str. (default: max_buffer_size)
:param int max_bin_len:
Deprecated, use *max_buffer_size* instead.
- Limits max length of bin. (default: max_buffer_size or 1024*1024)
+ Limits max length of bin. (default: max_buffer_size)
:param int max_array_len:
Limits max length of array.
- (default: max_buffer_size or 128*1024)
+ (default: max_buffer_size)
:param int max_map_len:
Limits max length of map.
- (default: max_buffer_size//2 or 32*1024)
+ (default: max_buffer_size//2)
:param int max_ext_len:
Deprecated, use *max_buffer_size* instead.
- Limits max size of ext type. (default: max_buffer_size or 1024*1024)
+ Limits max size of ext type. (default: max_buffer_size)
Example of streaming deserialize from file-like object::
- unpacker = Unpacker(file_like, raw=False, max_buffer_size=10*1024*1024)
+ unpacker = Unpacker(file_like)
for o in unpacker:
process(o)
Example of streaming deserialize from socket::
- unpacker = Unpacker(raw=False, max_buffer_size=10*1024*1024)
+ unpacker = Unpacker(max_buffer_size)
while True:
buf = sock.recv(1024**2)
if not buf:
@@ -251,22 +245,28 @@ class Unpacker(object):
Other exceptions can be raised during unpacking.
"""
- def __init__(self, file_like=None, read_size=0, use_list=True, raw=True, strict_map_key=False,
- object_hook=None, object_pairs_hook=None, list_hook=None,
- encoding=None, unicode_errors=None, max_buffer_size=0,
- ext_hook=ExtType,
- max_str_len=-1,
- max_bin_len=-1,
- max_array_len=-1,
- max_map_len=-1,
- max_ext_len=-1):
- if encoding is not None:
- warnings.warn(
- "encoding is deprecated, Use raw=False instead.",
- DeprecationWarning, stacklevel=2)
-
+ def __init__(
+ self,
+ file_like=None,
+ read_size=0,
+ use_list=True,
+ raw=False,
+ timestamp=0,
+ strict_map_key=True,
+ object_hook=None,
+ object_pairs_hook=None,
+ list_hook=None,
+ unicode_errors=None,
+ max_buffer_size=100 * 1024 * 1024,
+ ext_hook=ExtType,
+ max_str_len=-1,
+ max_bin_len=-1,
+ max_array_len=-1,
+ max_map_len=-1,
+ max_ext_len=-1,
+ ):
if unicode_errors is None:
- unicode_errors = 'strict'
+ unicode_errors = "strict"
if file_like is None:
self._feeding = True
@@ -290,26 +290,30 @@ class Unpacker(object):
# state, which _buf_checkpoint records.
self._buf_checkpoint = 0
+ if not max_buffer_size:
+ max_buffer_size = 2 ** 31 - 1
if max_str_len == -1:
- max_str_len = max_buffer_size or 1024*1024
+ max_str_len = max_buffer_size
if max_bin_len == -1:
- max_bin_len = max_buffer_size or 1024*1024
+ max_bin_len = max_buffer_size
if max_array_len == -1:
- max_array_len = max_buffer_size or 128*1024
+ max_array_len = max_buffer_size
if max_map_len == -1:
- max_map_len = max_buffer_size//2 or 32*1024
+ max_map_len = max_buffer_size // 2
if max_ext_len == -1:
- max_ext_len = max_buffer_size or 1024*1024
+ max_ext_len = max_buffer_size
- self._max_buffer_size = max_buffer_size or 2**31-1
+ self._max_buffer_size = max_buffer_size
if read_size > self._max_buffer_size:
raise ValueError("read_size must be smaller than max_buffer_size")
- self._read_size = read_size or min(self._max_buffer_size, 16*1024)
+ self._read_size = read_size or min(self._max_buffer_size, 16 * 1024)
self._raw = bool(raw)
self._strict_map_key = bool(strict_map_key)
- self._encoding = encoding
self._unicode_errors = unicode_errors
self._use_list = use_list
+ if not (0 <= timestamp <= 3):
+ raise ValueError("timestamp must be 0..3")
+ self._timestamp = timestamp
self._list_hook = list_hook
self._object_hook = object_hook
self._object_pairs_hook = object_pairs_hook
@@ -322,26 +326,27 @@ class Unpacker(object):
self._stream_offset = 0
if list_hook is not None and not callable(list_hook):
- raise TypeError('`list_hook` is not callable')
+ raise TypeError("`list_hook` is not callable")
if object_hook is not None and not callable(object_hook):
- raise TypeError('`object_hook` is not callable')
+ raise TypeError("`object_hook` is not callable")
if object_pairs_hook is not None and not callable(object_pairs_hook):
- raise TypeError('`object_pairs_hook` is not callable')
+ raise TypeError("`object_pairs_hook` is not callable")
if object_hook is not None and object_pairs_hook is not None:
- raise TypeError("object_pairs_hook and object_hook are mutually "
- "exclusive")
+ raise TypeError(
+ "object_pairs_hook and object_hook are mutually " "exclusive"
+ )
if not callable(ext_hook):
raise TypeError("`ext_hook` is not callable")
def feed(self, next_bytes):
assert self._feeding
view = _get_data_from_buffer(next_bytes)
- if (len(self._buffer) - self._buff_i + len(view) > self._max_buffer_size):
+ if len(self._buffer) - self._buff_i + len(view) > self._max_buffer_size:
raise BufferFull
# Strip buffer before checkpoint before reading file.
if self._buf_checkpoint > 0:
- del self._buffer[:self._buf_checkpoint]
+ del self._buffer[: self._buf_checkpoint]
self._buff_i -= self._buf_checkpoint
self._buf_checkpoint = 0
@@ -357,17 +362,19 @@ class Unpacker(object):
return self._buff_i < len(self._buffer)
def _get_extradata(self):
- return self._buffer[self._buff_i:]
+ return self._buffer[self._buff_i :]
def read_bytes(self, n):
- return self._read(n)
+ ret = self._read(n)
+ self._consume()
+ return ret
def _read(self, n):
# (int) -> bytearray
self._reserve(n)
i = self._buff_i
- self._buff_i = i+n
- return self._buffer[i:i+n]
+ self._buff_i = i + n
+ return self._buffer[i : i + n]
def _reserve(self, n):
remain_bytes = len(self._buffer) - self._buff_i - n
@@ -382,7 +389,7 @@ class Unpacker(object):
# Strip buffer before checkpoint before reading file.
if self._buf_checkpoint > 0:
- del self._buffer[:self._buf_checkpoint]
+ del self._buffer[: self._buf_checkpoint]
self._buff_i -= self._buf_checkpoint
self._buf_checkpoint = 0
@@ -411,7 +418,7 @@ class Unpacker(object):
if b & 0b10000000 == 0:
obj = b
elif b & 0b11100000 == 0b11100000:
- obj = -1 - (b ^ 0xff)
+ obj = -1 - (b ^ 0xFF)
elif b & 0b11100000 == 0b10100000:
n = b & 0b00011111
typ = TYPE_RAW
@@ -428,13 +435,13 @@ class Unpacker(object):
typ = TYPE_MAP
if n > self._max_map_len:
raise ValueError("%s exceeds max_map_len(%s)", n, self._max_map_len)
- elif b == 0xc0:
+ elif b == 0xC0:
obj = None
- elif b == 0xc2:
+ elif b == 0xC2:
obj = False
- elif b == 0xc3:
+ elif b == 0xC3:
obj = True
- elif b == 0xc4:
+ elif b == 0xC4:
typ = TYPE_BIN
self._reserve(1)
n = self._buffer[self._buff_i]
@@ -442,7 +449,7 @@ class Unpacker(object):
if n > self._max_bin_len:
raise ValueError("%s exceeds max_bin_len(%s)" % (n, self._max_bin_len))
obj = self._read(n)
- elif b == 0xc5:
+ elif b == 0xC5:
typ = TYPE_BIN
self._reserve(2)
n = _unpack_from(">H", self._buffer, self._buff_i)[0]
@@ -450,7 +457,7 @@ class Unpacker(object):
if n > self._max_bin_len:
raise ValueError("%s exceeds max_bin_len(%s)" % (n, self._max_bin_len))
obj = self._read(n)
- elif b == 0xc6:
+ elif b == 0xC6:
typ = TYPE_BIN
self._reserve(4)
n = _unpack_from(">I", self._buffer, self._buff_i)[0]
@@ -458,106 +465,106 @@ class Unpacker(object):
if n > self._max_bin_len:
raise ValueError("%s exceeds max_bin_len(%s)" % (n, self._max_bin_len))
obj = self._read(n)
- elif b == 0xc7: # ext 8
+ elif b == 0xC7: # ext 8
typ = TYPE_EXT
self._reserve(2)
- L, n = _unpack_from('Bb', self._buffer, self._buff_i)
+ L, n = _unpack_from("Bb", self._buffer, self._buff_i)
self._buff_i += 2
if L > self._max_ext_len:
raise ValueError("%s exceeds max_ext_len(%s)" % (L, self._max_ext_len))
obj = self._read(L)
- elif b == 0xc8: # ext 16
+ elif b == 0xC8: # ext 16
typ = TYPE_EXT
self._reserve(3)
- L, n = _unpack_from('>Hb', self._buffer, self._buff_i)
+ L, n = _unpack_from(">Hb", self._buffer, self._buff_i)
self._buff_i += 3
if L > self._max_ext_len:
raise ValueError("%s exceeds max_ext_len(%s)" % (L, self._max_ext_len))
obj = self._read(L)
- elif b == 0xc9: # ext 32
+ elif b == 0xC9: # ext 32
typ = TYPE_EXT
self._reserve(5)
- L, n = _unpack_from('>Ib', self._buffer, self._buff_i)
+ L, n = _unpack_from(">Ib", self._buffer, self._buff_i)
self._buff_i += 5
if L > self._max_ext_len:
raise ValueError("%s exceeds max_ext_len(%s)" % (L, self._max_ext_len))
obj = self._read(L)
- elif b == 0xca:
+ elif b == 0xCA:
self._reserve(4)
obj = _unpack_from(">f", self._buffer, self._buff_i)[0]
self._buff_i += 4
- elif b == 0xcb:
+ elif b == 0xCB:
self._reserve(8)
obj = _unpack_from(">d", self._buffer, self._buff_i)[0]
self._buff_i += 8
- elif b == 0xcc:
+ elif b == 0xCC:
self._reserve(1)
obj = self._buffer[self._buff_i]
self._buff_i += 1
- elif b == 0xcd:
+ elif b == 0xCD:
self._reserve(2)
obj = _unpack_from(">H", self._buffer, self._buff_i)[0]
self._buff_i += 2
- elif b == 0xce:
+ elif b == 0xCE:
self._reserve(4)
obj = _unpack_from(">I", self._buffer, self._buff_i)[0]
self._buff_i += 4
- elif b == 0xcf:
+ elif b == 0xCF:
self._reserve(8)
obj = _unpack_from(">Q", self._buffer, self._buff_i)[0]
self._buff_i += 8
- elif b == 0xd0:
+ elif b == 0xD0:
self._reserve(1)
obj = _unpack_from("b", self._buffer, self._buff_i)[0]
self._buff_i += 1
- elif b == 0xd1:
+ elif b == 0xD1:
self._reserve(2)
obj = _unpack_from(">h", self._buffer, self._buff_i)[0]
self._buff_i += 2
- elif b == 0xd2:
+ elif b == 0xD2:
self._reserve(4)
obj = _unpack_from(">i", self._buffer, self._buff_i)[0]
self._buff_i += 4
- elif b == 0xd3:
+ elif b == 0xD3:
self._reserve(8)
obj = _unpack_from(">q", self._buffer, self._buff_i)[0]
self._buff_i += 8
- elif b == 0xd4: # fixext 1
+ elif b == 0xD4: # fixext 1
typ = TYPE_EXT
if self._max_ext_len < 1:
raise ValueError("%s exceeds max_ext_len(%s)" % (1, self._max_ext_len))
self._reserve(2)
n, obj = _unpack_from("b1s", self._buffer, self._buff_i)
self._buff_i += 2
- elif b == 0xd5: # fixext 2
+ elif b == 0xD5: # fixext 2
typ = TYPE_EXT
if self._max_ext_len < 2:
raise ValueError("%s exceeds max_ext_len(%s)" % (2, self._max_ext_len))
self._reserve(3)
n, obj = _unpack_from("b2s", self._buffer, self._buff_i)
self._buff_i += 3
- elif b == 0xd6: # fixext 4
+ elif b == 0xD6: # fixext 4
typ = TYPE_EXT
if self._max_ext_len < 4:
raise ValueError("%s exceeds max_ext_len(%s)" % (4, self._max_ext_len))
self._reserve(5)
n, obj = _unpack_from("b4s", self._buffer, self._buff_i)
self._buff_i += 5
- elif b == 0xd7: # fixext 8
+ elif b == 0xD7: # fixext 8
typ = TYPE_EXT
if self._max_ext_len < 8:
raise ValueError("%s exceeds max_ext_len(%s)" % (8, self._max_ext_len))
self._reserve(9)
n, obj = _unpack_from("b8s", self._buffer, self._buff_i)
self._buff_i += 9
- elif b == 0xd8: # fixext 16
+ elif b == 0xD8: # fixext 16
typ = TYPE_EXT
if self._max_ext_len < 16:
raise ValueError("%s exceeds max_ext_len(%s)" % (16, self._max_ext_len))
self._reserve(17)
n, obj = _unpack_from("b16s", self._buffer, self._buff_i)
self._buff_i += 17
- elif b == 0xd9:
+ elif b == 0xD9:
typ = TYPE_RAW
self._reserve(1)
n = self._buffer[self._buff_i]
@@ -565,46 +572,46 @@ class Unpacker(object):
if n > self._max_str_len:
raise ValueError("%s exceeds max_str_len(%s)", n, self._max_str_len)
obj = self._read(n)
- elif b == 0xda:
+ elif b == 0xDA:
typ = TYPE_RAW
self._reserve(2)
- n, = _unpack_from(">H", self._buffer, self._buff_i)
+ (n,) = _unpack_from(">H", self._buffer, self._buff_i)
self._buff_i += 2
if n > self._max_str_len:
raise ValueError("%s exceeds max_str_len(%s)", n, self._max_str_len)
obj = self._read(n)
- elif b == 0xdb:
+ elif b == 0xDB:
typ = TYPE_RAW
self._reserve(4)
- n, = _unpack_from(">I", self._buffer, self._buff_i)
+ (n,) = _unpack_from(">I", self._buffer, self._buff_i)
self._buff_i += 4
if n > self._max_str_len:
raise ValueError("%s exceeds max_str_len(%s)", n, self._max_str_len)
obj = self._read(n)
- elif b == 0xdc:
+ elif b == 0xDC:
typ = TYPE_ARRAY
self._reserve(2)
- n, = _unpack_from(">H", self._buffer, self._buff_i)
+ (n,) = _unpack_from(">H", self._buffer, self._buff_i)
self._buff_i += 2
if n > self._max_array_len:
raise ValueError("%s exceeds max_array_len(%s)", n, self._max_array_len)
- elif b == 0xdd:
+ elif b == 0xDD:
typ = TYPE_ARRAY
self._reserve(4)
- n, = _unpack_from(">I", self._buffer, self._buff_i)
+ (n,) = _unpack_from(">I", self._buffer, self._buff_i)
self._buff_i += 4
if n > self._max_array_len:
raise ValueError("%s exceeds max_array_len(%s)", n, self._max_array_len)
- elif b == 0xde:
+ elif b == 0xDE:
self._reserve(2)
- n, = _unpack_from(">H", self._buffer, self._buff_i)
+ (n,) = _unpack_from(">H", self._buffer, self._buff_i)
self._buff_i += 2
if n > self._max_map_len:
raise ValueError("%s exceeds max_map_len(%s)", n, self._max_map_len)
typ = TYPE_MAP
- elif b == 0xdf:
+ elif b == 0xDF:
self._reserve(4)
- n, = _unpack_from(">I", self._buffer, self._buff_i)
+ (n,) = _unpack_from(">I", self._buffer, self._buff_i)
self._buff_i += 4
if n > self._max_map_len:
raise ValueError("%s exceeds max_map_len(%s)", n, self._max_map_len)
@@ -647,15 +654,19 @@ class Unpacker(object):
return
if self._object_pairs_hook is not None:
ret = self._object_pairs_hook(
- (self._unpack(EX_CONSTRUCT),
- self._unpack(EX_CONSTRUCT))
- for _ in xrange(n))
+ (self._unpack(EX_CONSTRUCT), self._unpack(EX_CONSTRUCT))
+ for _ in xrange(n)
+ )
else:
ret = {}
for _ in xrange(n):
key = self._unpack(EX_CONSTRUCT)
if self._strict_map_key and type(key) not in (unicode, bytes):
- raise ValueError("%s is not allowed for map key" % str(type(key)))
+ raise ValueError(
+ "%s is not allowed for map key" % str(type(key))
+ )
+ if not PY2 and type(key) is str:
+ key = sys.intern(key)
ret[key] = self._unpack(EX_CONSTRUCT)
if self._object_hook is not None:
ret = self._object_hook(ret)
@@ -663,17 +674,26 @@ class Unpacker(object):
if execute == EX_SKIP:
return
if typ == TYPE_RAW:
- if self._encoding is not None:
- obj = obj.decode(self._encoding, self._unicode_errors)
- elif self._raw:
+ if self._raw:
obj = bytes(obj)
else:
- obj = obj.decode('utf_8')
+ obj = obj.decode("utf_8", self._unicode_errors)
return obj
- if typ == TYPE_EXT:
- return self._ext_hook(n, bytes(obj))
if typ == TYPE_BIN:
return bytes(obj)
+ if typ == TYPE_EXT:
+ if n == -1: # timestamp
+ ts = Timestamp.from_bytes(bytes(obj))
+ if self._timestamp == 1:
+ return ts.to_unix()
+ elif self._timestamp == 2:
+ return ts.to_unix_nano()
+ elif self._timestamp == 3:
+ return ts.to_datetime()
+ else:
+ return ts
+ else:
+ return self._ext_hook(n, bytes(obj))
assert typ == TYPE_IMMEDIATE
return obj
@@ -723,7 +743,7 @@ class Packer(object):
"""
MessagePack Packer
- usage:
+ Usage:
packer = Packer()
astream.write(packer.pack(a))
@@ -744,49 +764,58 @@ class Packer(object):
:param bool use_bin_type:
Use bin type introduced in msgpack spec 2.0 for bytes.
- It also enables str8 type for unicode.
+ It also enables str8 type for unicode. (default: True)
:param bool strict_types:
If set to true, types will be checked to be exact. Derived classes
- from serializeable types will not be serialized and will be
+ from serializable types will not be serialized and will be
treated as unsupported type and forwarded to default.
Additionally tuples will not be serialized as lists.
This is useful when trying to implement accurate serialization
for python types.
- :param str encoding:
- (deprecated) Convert unicode to bytes with this encoding. (default: 'utf-8')
+ :param bool datetime:
+ If set to true, datetime with tzinfo is packed into Timestamp type.
+ Note that the tzinfo is stripped in the timestamp.
+ You can get UTC datetime with `timestamp=3` option of the Unpacker.
+ (Python 2 is not supported).
:param str unicode_errors:
- Error handler for encoding unicode. (default: 'strict')
+ The error handler for encoding unicode. (default: 'strict')
+ DO NOT USE THIS!! This option is kept for very specific usage.
"""
- def __init__(self, default=None, encoding=None, unicode_errors=None,
- use_single_float=False, autoreset=True, use_bin_type=False,
- strict_types=False):
- if encoding is None:
- encoding = 'utf_8'
- else:
- warnings.warn(
- "encoding is deprecated, Use raw=False instead.",
- DeprecationWarning, stacklevel=2)
-
- if unicode_errors is None:
- unicode_errors = 'strict'
+ def __init__(
+ self,
+ default=None,
+ use_single_float=False,
+ autoreset=True,
+ use_bin_type=True,
+ strict_types=False,
+ datetime=False,
+ unicode_errors=None,
+ ):
self._strict_types = strict_types
self._use_float = use_single_float
self._autoreset = autoreset
self._use_bin_type = use_bin_type
- self._encoding = encoding
- self._unicode_errors = unicode_errors
self._buffer = StringIO()
+ if PY2 and datetime:
+ raise ValueError("datetime is not supported in Python 2")
+ self._datetime = bool(datetime)
+ self._unicode_errors = unicode_errors or "strict"
if default is not None:
if not callable(default):
raise TypeError("default must be callable")
self._default = default
- def _pack(self, obj, nest_limit=DEFAULT_RECURSE_LIMIT,
- check=isinstance, check_type_strict=_check_type_strict):
+ def _pack(
+ self,
+ obj,
+ nest_limit=DEFAULT_RECURSE_LIMIT,
+ check=isinstance,
+ check_type_strict=_check_type_strict,
+ ):
default_used = False
if self._strict_types:
check = check_type_strict
@@ -807,22 +836,22 @@ class Packer(object):
return self._buffer.write(struct.pack("B", obj))
if -0x20 <= obj < 0:
return self._buffer.write(struct.pack("b", obj))
- if 0x80 <= obj <= 0xff:
- return self._buffer.write(struct.pack("BB", 0xcc, obj))
+ if 0x80 <= obj <= 0xFF:
+ return self._buffer.write(struct.pack("BB", 0xCC, obj))
if -0x80 <= obj < 0:
- return self._buffer.write(struct.pack(">Bb", 0xd0, obj))
- if 0xff < obj <= 0xffff:
- return self._buffer.write(struct.pack(">BH", 0xcd, obj))
+ return self._buffer.write(struct.pack(">Bb", 0xD0, obj))
+ if 0xFF < obj <= 0xFFFF:
+ return self._buffer.write(struct.pack(">BH", 0xCD, obj))
if -0x8000 <= obj < -0x80:
- return self._buffer.write(struct.pack(">Bh", 0xd1, obj))
- if 0xffff < obj <= 0xffffffff:
- return self._buffer.write(struct.pack(">BI", 0xce, obj))
+ return self._buffer.write(struct.pack(">Bh", 0xD1, obj))
+ if 0xFFFF < obj <= 0xFFFFFFFF:
+ return self._buffer.write(struct.pack(">BI", 0xCE, obj))
if -0x80000000 <= obj < -0x8000:
- return self._buffer.write(struct.pack(">Bi", 0xd2, obj))
- if 0xffffffff < obj <= 0xffffffffffffffff:
- return self._buffer.write(struct.pack(">BQ", 0xcf, obj))
+ return self._buffer.write(struct.pack(">Bi", 0xD2, obj))
+ if 0xFFFFFFFF < obj <= 0xFFFFFFFFFFFFFFFF:
+ return self._buffer.write(struct.pack(">BQ", 0xCF, obj))
if -0x8000000000000000 <= obj < -0x80000000:
- return self._buffer.write(struct.pack(">Bq", 0xd3, obj))
+ return self._buffer.write(struct.pack(">Bq", 0xD3, obj))
if not default_used and self._default is not None:
obj = self._default(obj)
default_used = True
@@ -830,53 +859,53 @@ class Packer(object):
raise OverflowError("Integer value out of range")
if check(obj, (bytes, bytearray)):
n = len(obj)
- if n >= 2**32:
+ if n >= 2 ** 32:
raise ValueError("%s is too large" % type(obj).__name__)
self._pack_bin_header(n)
return self._buffer.write(obj)
if check(obj, unicode):
- if self._encoding is None:
- raise TypeError(
- "Can't encode unicode string: "
- "no encoding is specified")
- obj = obj.encode(self._encoding, self._unicode_errors)
+ obj = obj.encode("utf-8", self._unicode_errors)
n = len(obj)
- if n >= 2**32:
+ if n >= 2 ** 32:
raise ValueError("String is too large")
self._pack_raw_header(n)
return self._buffer.write(obj)
if check(obj, memoryview):
n = len(obj) * obj.itemsize
- if n >= 2**32:
+ if n >= 2 ** 32:
raise ValueError("Memoryview is too large")
self._pack_bin_header(n)
return self._buffer.write(obj)
if check(obj, float):
if self._use_float:
- return self._buffer.write(struct.pack(">Bf", 0xca, obj))
- return self._buffer.write(struct.pack(">Bd", 0xcb, obj))
- if check(obj, ExtType):
- code = obj.code
- data = obj.data
+ return self._buffer.write(struct.pack(">Bf", 0xCA, obj))
+ return self._buffer.write(struct.pack(">Bd", 0xCB, obj))
+ if check(obj, (ExtType, Timestamp)):
+ if check(obj, Timestamp):
+ code = -1
+ data = obj.to_bytes()
+ else:
+ code = obj.code
+ data = obj.data
assert isinstance(code, int)
assert isinstance(data, bytes)
L = len(data)
if L == 1:
- self._buffer.write(b'\xd4')
+ self._buffer.write(b"\xd4")
elif L == 2:
- self._buffer.write(b'\xd5')
+ self._buffer.write(b"\xd5")
elif L == 4:
- self._buffer.write(b'\xd6')
+ self._buffer.write(b"\xd6")
elif L == 8:
- self._buffer.write(b'\xd7')
+ self._buffer.write(b"\xd7")
elif L == 16:
- self._buffer.write(b'\xd8')
- elif L <= 0xff:
- self._buffer.write(struct.pack(">BB", 0xc7, L))
- elif L <= 0xffff:
- self._buffer.write(struct.pack(">BH", 0xc8, L))
+ self._buffer.write(b"\xd8")
+ elif L <= 0xFF:
+ self._buffer.write(struct.pack(">BB", 0xC7, L))
+ elif L <= 0xFFFF:
+ self._buffer.write(struct.pack(">BH", 0xC8, L))
else:
- self._buffer.write(struct.pack(">BI", 0xc9, L))
+ self._buffer.write(struct.pack(">BI", 0xC9, L))
self._buffer.write(struct.pack("b", code))
self._buffer.write(data)
return
@@ -887,13 +916,20 @@ class Packer(object):
self._pack(obj[i], nest_limit - 1)
return
if check(obj, dict):
- return self._pack_map_pairs(len(obj), dict_iteritems(obj),
- nest_limit - 1)
+ return self._pack_map_pairs(
+ len(obj), dict_iteritems(obj), nest_limit - 1
+ )
+
+ if self._datetime and check(obj, _DateTime):
+ obj = Timestamp.from_datetime(obj)
+ default_used = 1
+ continue
+
if not default_used and self._default is not None:
obj = self._default(obj)
default_used = 1
continue
- raise TypeError("Cannot serialize %r" % (obj, ))
+ raise TypeError("Cannot serialize %r" % (obj,))
def pack(self, obj):
try:
@@ -914,7 +950,7 @@ class Packer(object):
return ret
def pack_array_header(self, n):
- if n >= 2**32:
+ if n >= 2 ** 32:
raise ValueError
self._pack_array_header(n)
if self._autoreset:
@@ -923,7 +959,7 @@ class Packer(object):
return ret
def pack_map_header(self, n):
- if n >= 2**32:
+ if n >= 2 ** 32:
raise ValueError
self._pack_map_header(n)
if self._autoreset:
@@ -939,43 +975,43 @@ class Packer(object):
if not isinstance(data, bytes):
raise TypeError("data must have bytes type")
L = len(data)
- if L > 0xffffffff:
+ if L > 0xFFFFFFFF:
raise ValueError("Too large data")
if L == 1:
- self._buffer.write(b'\xd4')
+ self._buffer.write(b"\xd4")
elif L == 2:
- self._buffer.write(b'\xd5')
+ self._buffer.write(b"\xd5")
elif L == 4:
- self._buffer.write(b'\xd6')
+ self._buffer.write(b"\xd6")
elif L == 8:
- self._buffer.write(b'\xd7')
+ self._buffer.write(b"\xd7")
elif L == 16:
- self._buffer.write(b'\xd8')
- elif L <= 0xff:
- self._buffer.write(b'\xc7' + struct.pack('B', L))
- elif L <= 0xffff:
- self._buffer.write(b'\xc8' + struct.pack('>H', L))
+ self._buffer.write(b"\xd8")
+ elif L <= 0xFF:
+ self._buffer.write(b"\xc7" + struct.pack("B", L))
+ elif L <= 0xFFFF:
+ self._buffer.write(b"\xc8" + struct.pack(">H", L))
else:
- self._buffer.write(b'\xc9' + struct.pack('>I', L))
- self._buffer.write(struct.pack('B', typecode))
+ self._buffer.write(b"\xc9" + struct.pack(">I", L))
+ self._buffer.write(struct.pack("B", typecode))
self._buffer.write(data)
def _pack_array_header(self, n):
- if n <= 0x0f:
- return self._buffer.write(struct.pack('B', 0x90 + n))
- if n <= 0xffff:
- return self._buffer.write(struct.pack(">BH", 0xdc, n))
- if n <= 0xffffffff:
- return self._buffer.write(struct.pack(">BI", 0xdd, n))
+ if n <= 0x0F:
+ return self._buffer.write(struct.pack("B", 0x90 + n))
+ if n <= 0xFFFF:
+ return self._buffer.write(struct.pack(">BH", 0xDC, n))
+ if n <= 0xFFFFFFFF:
+ return self._buffer.write(struct.pack(">BI", 0xDD, n))
raise ValueError("Array is too large")
def _pack_map_header(self, n):
- if n <= 0x0f:
- return self._buffer.write(struct.pack('B', 0x80 + n))
- if n <= 0xffff:
- return self._buffer.write(struct.pack(">BH", 0xde, n))
- if n <= 0xffffffff:
- return self._buffer.write(struct.pack(">BI", 0xdf, n))
+ if n <= 0x0F:
+ return self._buffer.write(struct.pack("B", 0x80 + n))
+ if n <= 0xFFFF:
+ return self._buffer.write(struct.pack(">BH", 0xDE, n))
+ if n <= 0xFFFFFFFF:
+ return self._buffer.write(struct.pack(">BI", 0xDF, n))
raise ValueError("Dict is too large")
def _pack_map_pairs(self, n, pairs, nest_limit=DEFAULT_RECURSE_LIMIT):
@@ -985,28 +1021,28 @@ class Packer(object):
self._pack(v, nest_limit - 1)
def _pack_raw_header(self, n):
- if n <= 0x1f:
- self._buffer.write(struct.pack('B', 0xa0 + n))
- elif self._use_bin_type and n <= 0xff:
- self._buffer.write(struct.pack('>BB', 0xd9, n))
- elif n <= 0xffff:
- self._buffer.write(struct.pack(">BH", 0xda, n))
- elif n <= 0xffffffff:
- self._buffer.write(struct.pack(">BI", 0xdb, n))
+ if n <= 0x1F:
+ self._buffer.write(struct.pack("B", 0xA0 + n))
+ elif self._use_bin_type and n <= 0xFF:
+ self._buffer.write(struct.pack(">BB", 0xD9, n))
+ elif n <= 0xFFFF:
+ self._buffer.write(struct.pack(">BH", 0xDA, n))
+ elif n <= 0xFFFFFFFF:
+ self._buffer.write(struct.pack(">BI", 0xDB, n))
else:
- raise ValueError('Raw is too large')
+ raise ValueError("Raw is too large")
def _pack_bin_header(self, n):
if not self._use_bin_type:
return self._pack_raw_header(n)
- elif n <= 0xff:
- return self._buffer.write(struct.pack('>BB', 0xc4, n))
- elif n <= 0xffff:
- return self._buffer.write(struct.pack(">BH", 0xc5, n))
- elif n <= 0xffffffff:
- return self._buffer.write(struct.pack(">BI", 0xc6, n))
+ elif n <= 0xFF:
+ return self._buffer.write(struct.pack(">BB", 0xC4, n))
+ elif n <= 0xFFFF:
+ return self._buffer.write(struct.pack(">BH", 0xC5, n))
+ elif n <= 0xFFFFFFFF:
+ return self._buffer.write(struct.pack(">BI", 0xC6, n))
else:
- raise ValueError('Bin is too large')
+ raise ValueError("Bin is too large")
def bytes(self):
"""Return internal buffer contents as bytes object"""
@@ -1015,7 +1051,7 @@ class Packer(object):
def reset(self):
"""Reset internal buffer.
- This method is usaful only when autoreset=False.
+ This method is useful only when autoreset=False.
"""
self._buffer = StringIO()
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__about__.py b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__about__.py
index 7481c9e..4d99857 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__about__.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__about__.py
@@ -18,10 +18,10 @@ __title__ = "packaging"
__summary__ = "Core utilities for Python packages"
__uri__ = "https://github.com/pypa/packaging"
-__version__ = "19.0"
+__version__ = "20.4"
__author__ = "Donald Stufft and individual contributors"
__email__ = "donald@stufft.io"
-__license__ = "BSD or Apache License, Version 2.0"
+__license__ = "BSD-2-Clause or Apache-2.0"
__copyright__ = "Copyright 2014-2019 %s" % __author__
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/__about__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/__about__.cpython-38.pyc
index 87225df..03e2865 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/__about__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/__about__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-38.pyc
index ceaa799..e81da70 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/_compat.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/_compat.cpython-38.pyc
index 28ad4bc..9e2cd1f 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/_compat.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/_compat.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-38.pyc
index fae23c6..37f07a6 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-38.pyc
index aab7a27..ad440f7 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-38.pyc
index 8fc8c45..53bd01e 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc
index 30f1d84..23a4062 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-38.pyc
index ba6b090..3a8e20a 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-38.pyc
index 6f94549..ca99039 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/_compat.py b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/_compat.py
index 25da473..e54bd4e 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/_compat.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/_compat.py
@@ -5,6 +5,11 @@ from __future__ import absolute_import, division, print_function
import sys
+from ._typing import TYPE_CHECKING
+
+if TYPE_CHECKING: # pragma: no cover
+ from typing import Any, Dict, Tuple, Type
+
PY2 = sys.version_info[0] == 2
PY3 = sys.version_info[0] == 3
@@ -18,14 +23,16 @@ else:
def with_metaclass(meta, *bases):
+ # type: (Type[Any], Tuple[Type[Any], ...]) -> Any
"""
Create a base class with a metaclass.
"""
# This requires a bit of explanation: the basic idea is to make a dummy
# metaclass for one level of class instantiation that replaces itself with
# the actual metaclass.
- class metaclass(meta):
+ class metaclass(meta): # type: ignore
def __new__(cls, name, this_bases, d):
+ # type: (Type[Any], str, Tuple[Any], Dict[Any, Any]) -> Any
return meta(name, bases, d)
return type.__new__(metaclass, "temporary_class", (), {})
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/_structures.py b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/_structures.py
index 68dcca6..800d5c5 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/_structures.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/_structures.py
@@ -4,65 +4,83 @@
from __future__ import absolute_import, division, print_function
-class Infinity(object):
+class InfinityType(object):
def __repr__(self):
+ # type: () -> str
return "Infinity"
def __hash__(self):
+ # type: () -> int
return hash(repr(self))
def __lt__(self, other):
+ # type: (object) -> bool
return False
def __le__(self, other):
+ # type: (object) -> bool
return False
def __eq__(self, other):
+ # type: (object) -> bool
return isinstance(other, self.__class__)
def __ne__(self, other):
+ # type: (object) -> bool
return not isinstance(other, self.__class__)
def __gt__(self, other):
+ # type: (object) -> bool
return True
def __ge__(self, other):
+ # type: (object) -> bool
return True
def __neg__(self):
+ # type: (object) -> NegativeInfinityType
return NegativeInfinity
-Infinity = Infinity()
+Infinity = InfinityType()
-class NegativeInfinity(object):
+class NegativeInfinityType(object):
def __repr__(self):
+ # type: () -> str
return "-Infinity"
def __hash__(self):
+ # type: () -> int
return hash(repr(self))
def __lt__(self, other):
+ # type: (object) -> bool
return True
def __le__(self, other):
+ # type: (object) -> bool
return True
def __eq__(self, other):
+ # type: (object) -> bool
return isinstance(other, self.__class__)
def __ne__(self, other):
+ # type: (object) -> bool
return not isinstance(other, self.__class__)
def __gt__(self, other):
+ # type: (object) -> bool
return False
def __ge__(self, other):
+ # type: (object) -> bool
return False
def __neg__(self):
+ # type: (object) -> InfinityType
return Infinity
-NegativeInfinity = NegativeInfinity()
+NegativeInfinity = NegativeInfinityType()
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/markers.py b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/markers.py
index 5482476..ed642b0 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/markers.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/markers.py
@@ -13,8 +13,14 @@ from pip._vendor.pyparsing import ZeroOrMore, Group, Forward, QuotedString
from pip._vendor.pyparsing import Literal as L # noqa
from ._compat import string_types
+from ._typing import TYPE_CHECKING
from .specifiers import Specifier, InvalidSpecifier
+if TYPE_CHECKING: # pragma: no cover
+ from typing import Any, Callable, Dict, List, Optional, Tuple, Union
+
+ Operator = Callable[[str, str], bool]
+
__all__ = [
"InvalidMarker",
@@ -46,30 +52,37 @@ class UndefinedEnvironmentName(ValueError):
class Node(object):
def __init__(self, value):
+ # type: (Any) -> None
self.value = value
def __str__(self):
+ # type: () -> str
return str(self.value)
def __repr__(self):
+ # type: () -> str
return "<{0}({1!r})>".format(self.__class__.__name__, str(self))
def serialize(self):
+ # type: () -> str
raise NotImplementedError
class Variable(Node):
def serialize(self):
+ # type: () -> str
return str(self)
class Value(Node):
def serialize(self):
+ # type: () -> str
return '"{0}"'.format(self)
class Op(Node):
def serialize(self):
+ # type: () -> str
return str(self)
@@ -85,13 +98,13 @@ VARIABLE = (
| L("python_version")
| L("sys_platform")
| L("os_name")
- | L("os.name")
+ | L("os.name") # PEP-345
| L("sys.platform") # PEP-345
| L("platform.version") # PEP-345
| L("platform.machine") # PEP-345
| L("platform.python_implementation") # PEP-345
- | L("python_implementation") # PEP-345
- | L("extra") # undocumented setuptools legacy
+ | L("python_implementation") # undocumented setuptools legacy
+ | L("extra") # PEP-508
)
ALIASES = {
"os.name": "os_name",
@@ -131,6 +144,7 @@ MARKER = stringStart + MARKER_EXPR + stringEnd
def _coerce_parse_result(results):
+ # type: (Union[ParseResults, List[Any]]) -> List[Any]
if isinstance(results, ParseResults):
return [_coerce_parse_result(i) for i in results]
else:
@@ -138,6 +152,8 @@ def _coerce_parse_result(results):
def _format_marker(marker, first=True):
+ # type: (Union[List[str], Tuple[Node, ...], str], Optional[bool]) -> str
+
assert isinstance(marker, (list, tuple, string_types))
# Sometimes we have a structure like [[...]] which is a single item list
@@ -172,10 +188,11 @@ _operators = {
"!=": operator.ne,
">=": operator.ge,
">": operator.gt,
-}
+} # type: Dict[str, Operator]
def _eval_op(lhs, op, rhs):
+ # type: (str, Op, str) -> bool
try:
spec = Specifier("".join([op.serialize(), rhs]))
except InvalidSpecifier:
@@ -183,7 +200,7 @@ def _eval_op(lhs, op, rhs):
else:
return spec.contains(lhs)
- oper = _operators.get(op.serialize())
+ oper = _operators.get(op.serialize()) # type: Optional[Operator]
if oper is None:
raise UndefinedComparison(
"Undefined {0!r} on {1!r} and {2!r}.".format(op, lhs, rhs)
@@ -192,13 +209,18 @@ def _eval_op(lhs, op, rhs):
return oper(lhs, rhs)
-_undefined = object()
+class Undefined(object):
+ pass
+
+
+_undefined = Undefined()
def _get_env(environment, name):
- value = environment.get(name, _undefined)
+ # type: (Dict[str, str], str) -> str
+ value = environment.get(name, _undefined) # type: Union[str, Undefined]
- if value is _undefined:
+ if isinstance(value, Undefined):
raise UndefinedEnvironmentName(
"{0!r} does not exist in evaluation environment.".format(name)
)
@@ -207,7 +229,8 @@ def _get_env(environment, name):
def _evaluate_markers(markers, environment):
- groups = [[]]
+ # type: (List[Any], Dict[str, str]) -> bool
+ groups = [[]] # type: List[List[bool]]
for marker in markers:
assert isinstance(marker, (list, tuple, string_types))
@@ -234,6 +257,7 @@ def _evaluate_markers(markers, environment):
def format_full_version(info):
+ # type: (sys._version_info) -> str
version = "{0.major}.{0.minor}.{0.micro}".format(info)
kind = info.releaselevel
if kind != "final":
@@ -242,9 +266,13 @@ def format_full_version(info):
def default_environment():
+ # type: () -> Dict[str, str]
if hasattr(sys, "implementation"):
- iver = format_full_version(sys.implementation.version)
- implementation_name = sys.implementation.name
+ # Ignoring the `sys.implementation` reference for type checking due to
+ # mypy not liking that the attribute doesn't exist in Python 2.7 when
+ # run with the `--py27` flag.
+ iver = format_full_version(sys.implementation.version) # type: ignore
+ implementation_name = sys.implementation.name # type: ignore
else:
iver = "0"
implementation_name = ""
@@ -259,13 +287,14 @@ def default_environment():
"platform_version": platform.version(),
"python_full_version": platform.python_version(),
"platform_python_implementation": platform.python_implementation(),
- "python_version": platform.python_version()[:3],
+ "python_version": ".".join(platform.python_version_tuple()[:2]),
"sys_platform": sys.platform,
}
class Marker(object):
def __init__(self, marker):
+ # type: (str) -> None
try:
self._markers = _coerce_parse_result(MARKER.parseString(marker))
except ParseException as e:
@@ -275,12 +304,15 @@ class Marker(object):
raise InvalidMarker(err_str)
def __str__(self):
+ # type: () -> str
return _format_marker(self._markers)
def __repr__(self):
+ # type: () -> str
return "".format(str(self))
def evaluate(self, environment=None):
+ # type: (Optional[Dict[str, str]]) -> bool
"""Evaluate a marker.
Return the boolean from evaluating the given marker against the
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/requirements.py b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/requirements.py
index dbc5f11..5e64101 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/requirements.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/requirements.py
@@ -11,9 +11,13 @@ from pip._vendor.pyparsing import ZeroOrMore, Word, Optional, Regex, Combine
from pip._vendor.pyparsing import Literal as L # noqa
from pip._vendor.six.moves.urllib import parse as urlparse
+from ._typing import TYPE_CHECKING
from .markers import MARKER_EXPR, Marker
from .specifiers import LegacySpecifier, Specifier, SpecifierSet
+if TYPE_CHECKING: # pragma: no cover
+ from typing import List
+
class InvalidRequirement(ValueError):
"""
@@ -89,6 +93,7 @@ class Requirement(object):
# TODO: Can we normalize the name and extra name?
def __init__(self, requirement_string):
+ # type: (str) -> None
try:
req = REQUIREMENT.parseString(requirement_string)
except ParseException as e:
@@ -116,7 +121,8 @@ class Requirement(object):
self.marker = req.marker if req.marker else None
def __str__(self):
- parts = [self.name]
+ # type: () -> str
+ parts = [self.name] # type: List[str]
if self.extras:
parts.append("[{0}]".format(",".join(sorted(self.extras))))
@@ -135,4 +141,5 @@ class Requirement(object):
return "".join(parts)
def __repr__(self):
+ # type: () -> str
return "".format(str(self))
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/specifiers.py b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/specifiers.py
index 743576a..fe09bb1 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/specifiers.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/specifiers.py
@@ -9,8 +9,27 @@ import itertools
import re
from ._compat import string_types, with_metaclass
+from ._typing import TYPE_CHECKING
+from .utils import canonicalize_version
from .version import Version, LegacyVersion, parse
+if TYPE_CHECKING: # pragma: no cover
+ from typing import (
+ List,
+ Dict,
+ Union,
+ Iterable,
+ Iterator,
+ Optional,
+ Callable,
+ Tuple,
+ FrozenSet,
+ )
+
+ ParsedVersion = Union[Version, LegacyVersion]
+ UnparsedVersion = Union[Version, LegacyVersion, str]
+ CallableOperator = Callable[[ParsedVersion, str], bool]
+
class InvalidSpecifier(ValueError):
"""
@@ -18,9 +37,10 @@ class InvalidSpecifier(ValueError):
"""
-class BaseSpecifier(with_metaclass(abc.ABCMeta, object)):
+class BaseSpecifier(with_metaclass(abc.ABCMeta, object)): # type: ignore
@abc.abstractmethod
def __str__(self):
+ # type: () -> str
"""
Returns the str representation of this Specifier like object. This
should be representative of the Specifier itself.
@@ -28,12 +48,14 @@ class BaseSpecifier(with_metaclass(abc.ABCMeta, object)):
@abc.abstractmethod
def __hash__(self):
+ # type: () -> int
"""
Returns a hash value for this Specifier like object.
"""
@abc.abstractmethod
def __eq__(self, other):
+ # type: (object) -> bool
"""
Returns a boolean representing whether or not the two Specifier like
objects are equal.
@@ -41,6 +63,7 @@ class BaseSpecifier(with_metaclass(abc.ABCMeta, object)):
@abc.abstractmethod
def __ne__(self, other):
+ # type: (object) -> bool
"""
Returns a boolean representing whether or not the two Specifier like
objects are not equal.
@@ -48,6 +71,7 @@ class BaseSpecifier(with_metaclass(abc.ABCMeta, object)):
@abc.abstractproperty
def prereleases(self):
+ # type: () -> Optional[bool]
"""
Returns whether or not pre-releases as a whole are allowed by this
specifier.
@@ -55,6 +79,7 @@ class BaseSpecifier(with_metaclass(abc.ABCMeta, object)):
@prereleases.setter
def prereleases(self, value):
+ # type: (bool) -> None
"""
Sets whether or not pre-releases as a whole are allowed by this
specifier.
@@ -62,12 +87,14 @@ class BaseSpecifier(with_metaclass(abc.ABCMeta, object)):
@abc.abstractmethod
def contains(self, item, prereleases=None):
+ # type: (str, Optional[bool]) -> bool
"""
Determines if the given item is contained within this specifier.
"""
@abc.abstractmethod
def filter(self, iterable, prereleases=None):
+ # type: (Iterable[UnparsedVersion], Optional[bool]) -> Iterable[UnparsedVersion]
"""
Takes an iterable of items and filters them so that only items which
are contained within this specifier are allowed in it.
@@ -76,19 +103,24 @@ class BaseSpecifier(with_metaclass(abc.ABCMeta, object)):
class _IndividualSpecifier(BaseSpecifier):
- _operators = {}
+ _operators = {} # type: Dict[str, str]
def __init__(self, spec="", prereleases=None):
+ # type: (str, Optional[bool]) -> None
match = self._regex.search(spec)
if not match:
raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec))
- self._spec = (match.group("operator").strip(), match.group("version").strip())
+ self._spec = (
+ match.group("operator").strip(),
+ match.group("version").strip(),
+ ) # type: Tuple[str, str]
# Store whether or not this Specifier should accept prereleases
self._prereleases = prereleases
def __repr__(self):
+ # type: () -> str
pre = (
", prereleases={0!r}".format(self.prereleases)
if self._prereleases is not None
@@ -98,26 +130,35 @@ class _IndividualSpecifier(BaseSpecifier):
return "<{0}({1!r}{2})>".format(self.__class__.__name__, str(self), pre)
def __str__(self):
+ # type: () -> str
return "{0}{1}".format(*self._spec)
+ @property
+ def _canonical_spec(self):
+ # type: () -> Tuple[str, Union[Version, str]]
+ return self._spec[0], canonicalize_version(self._spec[1])
+
def __hash__(self):
- return hash(self._spec)
+ # type: () -> int
+ return hash(self._canonical_spec)
def __eq__(self, other):
+ # type: (object) -> bool
if isinstance(other, string_types):
try:
- other = self.__class__(other)
+ other = self.__class__(str(other))
except InvalidSpecifier:
return NotImplemented
elif not isinstance(other, self.__class__):
return NotImplemented
- return self._spec == other._spec
+ return self._canonical_spec == other._canonical_spec
def __ne__(self, other):
+ # type: (object) -> bool
if isinstance(other, string_types):
try:
- other = self.__class__(other)
+ other = self.__class__(str(other))
except InvalidSpecifier:
return NotImplemented
elif not isinstance(other, self.__class__):
@@ -126,52 +167,67 @@ class _IndividualSpecifier(BaseSpecifier):
return self._spec != other._spec
def _get_operator(self, op):
- return getattr(self, "_compare_{0}".format(self._operators[op]))
+ # type: (str) -> CallableOperator
+ operator_callable = getattr(
+ self, "_compare_{0}".format(self._operators[op])
+ ) # type: CallableOperator
+ return operator_callable
def _coerce_version(self, version):
+ # type: (UnparsedVersion) -> ParsedVersion
if not isinstance(version, (LegacyVersion, Version)):
version = parse(version)
return version
@property
def operator(self):
+ # type: () -> str
return self._spec[0]
@property
def version(self):
+ # type: () -> str
return self._spec[1]
@property
def prereleases(self):
+ # type: () -> Optional[bool]
return self._prereleases
@prereleases.setter
def prereleases(self, value):
+ # type: (bool) -> None
self._prereleases = value
def __contains__(self, item):
+ # type: (str) -> bool
return self.contains(item)
def contains(self, item, prereleases=None):
+ # type: (UnparsedVersion, Optional[bool]) -> bool
+
# Determine if prereleases are to be allowed or not.
if prereleases is None:
prereleases = self.prereleases
# Normalize item to a Version or LegacyVersion, this allows us to have
# a shortcut for ``"2.0" in Specifier(">=2")
- item = self._coerce_version(item)
+ normalized_item = self._coerce_version(item)
# Determine if we should be supporting prereleases in this specifier
# or not, if we do not support prereleases than we can short circuit
# logic if this version is a prereleases.
- if item.is_prerelease and not prereleases:
+ if normalized_item.is_prerelease and not prereleases:
return False
# Actually do the comparison to determine if this item is contained
# within this Specifier or not.
- return self._get_operator(self.operator)(item, self.version)
+ operator_callable = self._get_operator(self.operator) # type: CallableOperator
+ return operator_callable(normalized_item, self.version)
def filter(self, iterable, prereleases=None):
+ # type: (Iterable[UnparsedVersion], Optional[bool]) -> Iterable[UnparsedVersion]
+
yielded = False
found_prereleases = []
@@ -230,32 +286,43 @@ class LegacySpecifier(_IndividualSpecifier):
}
def _coerce_version(self, version):
+ # type: (Union[ParsedVersion, str]) -> LegacyVersion
if not isinstance(version, LegacyVersion):
version = LegacyVersion(str(version))
return version
def _compare_equal(self, prospective, spec):
+ # type: (LegacyVersion, str) -> bool
return prospective == self._coerce_version(spec)
def _compare_not_equal(self, prospective, spec):
+ # type: (LegacyVersion, str) -> bool
return prospective != self._coerce_version(spec)
def _compare_less_than_equal(self, prospective, spec):
+ # type: (LegacyVersion, str) -> bool
return prospective <= self._coerce_version(spec)
def _compare_greater_than_equal(self, prospective, spec):
+ # type: (LegacyVersion, str) -> bool
return prospective >= self._coerce_version(spec)
def _compare_less_than(self, prospective, spec):
+ # type: (LegacyVersion, str) -> bool
return prospective < self._coerce_version(spec)
def _compare_greater_than(self, prospective, spec):
+ # type: (LegacyVersion, str) -> bool
return prospective > self._coerce_version(spec)
-def _require_version_compare(fn):
+def _require_version_compare(
+ fn # type: (Callable[[Specifier, ParsedVersion, str], bool])
+):
+ # type: (...) -> Callable[[Specifier, ParsedVersion, str], bool]
@functools.wraps(fn)
def wrapped(self, prospective, spec):
+ # type: (Specifier, ParsedVersion, str) -> bool
if not isinstance(prospective, Version):
return False
return fn(self, prospective, spec)
@@ -373,6 +440,8 @@ class Specifier(_IndividualSpecifier):
@_require_version_compare
def _compare_compatible(self, prospective, spec):
+ # type: (ParsedVersion, str) -> bool
+
# Compatible releases have an equivalent combination of >= and ==. That
# is that ~=2.2 is equivalent to >=2.2,==2.*. This allows us to
# implement this in terms of the other specifiers instead of
@@ -400,56 +469,75 @@ class Specifier(_IndividualSpecifier):
@_require_version_compare
def _compare_equal(self, prospective, spec):
+ # type: (ParsedVersion, str) -> bool
+
# We need special logic to handle prefix matching
if spec.endswith(".*"):
# In the case of prefix matching we want to ignore local segment.
prospective = Version(prospective.public)
# Split the spec out by dots, and pretend that there is an implicit
# dot in between a release segment and a pre-release segment.
- spec = _version_split(spec[:-2]) # Remove the trailing .*
+ split_spec = _version_split(spec[:-2]) # Remove the trailing .*
# Split the prospective version out by dots, and pretend that there
# is an implicit dot in between a release segment and a pre-release
# segment.
- prospective = _version_split(str(prospective))
+ split_prospective = _version_split(str(prospective))
# Shorten the prospective version to be the same length as the spec
# so that we can determine if the specifier is a prefix of the
# prospective version or not.
- prospective = prospective[: len(spec)]
+ shortened_prospective = split_prospective[: len(split_spec)]
# Pad out our two sides with zeros so that they both equal the same
# length.
- spec, prospective = _pad_version(spec, prospective)
+ padded_spec, padded_prospective = _pad_version(
+ split_spec, shortened_prospective
+ )
+
+ return padded_prospective == padded_spec
else:
# Convert our spec string into a Version
- spec = Version(spec)
+ spec_version = Version(spec)
# If the specifier does not have a local segment, then we want to
# act as if the prospective version also does not have a local
# segment.
- if not spec.local:
+ if not spec_version.local:
prospective = Version(prospective.public)
- return prospective == spec
+ return prospective == spec_version
@_require_version_compare
def _compare_not_equal(self, prospective, spec):
+ # type: (ParsedVersion, str) -> bool
return not self._compare_equal(prospective, spec)
@_require_version_compare
def _compare_less_than_equal(self, prospective, spec):
- return prospective <= Version(spec)
+ # type: (ParsedVersion, str) -> bool
+
+ # NB: Local version identifiers are NOT permitted in the version
+ # specifier, so local version labels can be universally removed from
+ # the prospective version.
+ return Version(prospective.public) <= Version(spec)
@_require_version_compare
def _compare_greater_than_equal(self, prospective, spec):
- return prospective >= Version(spec)
+ # type: (ParsedVersion, str) -> bool
+
+ # NB: Local version identifiers are NOT permitted in the version
+ # specifier, so local version labels can be universally removed from
+ # the prospective version.
+ return Version(prospective.public) >= Version(spec)
@_require_version_compare
- def _compare_less_than(self, prospective, spec):
+ def _compare_less_than(self, prospective, spec_str):
+ # type: (ParsedVersion, str) -> bool
+
# Convert our spec to a Version instance, since we'll want to work with
# it as a version.
- spec = Version(spec)
+ spec = Version(spec_str)
# Check to see if the prospective version is less than the spec
# version. If it's not we can short circuit and just return False now
@@ -471,10 +559,12 @@ class Specifier(_IndividualSpecifier):
return True
@_require_version_compare
- def _compare_greater_than(self, prospective, spec):
+ def _compare_greater_than(self, prospective, spec_str):
+ # type: (ParsedVersion, str) -> bool
+
# Convert our spec to a Version instance, since we'll want to work with
# it as a version.
- spec = Version(spec)
+ spec = Version(spec_str)
# Check to see if the prospective version is greater than the spec
# version. If it's not we can short circuit and just return False now
@@ -502,10 +592,13 @@ class Specifier(_IndividualSpecifier):
return True
def _compare_arbitrary(self, prospective, spec):
+ # type: (Version, str) -> bool
return str(prospective).lower() == str(spec).lower()
@property
def prereleases(self):
+ # type: () -> bool
+
# If there is an explicit prereleases set for this, then we'll just
# blindly use that.
if self._prereleases is not None:
@@ -530,6 +623,7 @@ class Specifier(_IndividualSpecifier):
@prereleases.setter
def prereleases(self, value):
+ # type: (bool) -> None
self._prereleases = value
@@ -537,7 +631,8 @@ _prefix_regex = re.compile(r"^([0-9]+)((?:a|b|c|rc)[0-9]+)$")
def _version_split(version):
- result = []
+ # type: (str) -> List[str]
+ result = [] # type: List[str]
for item in version.split("."):
match = _prefix_regex.search(item)
if match:
@@ -548,6 +643,7 @@ def _version_split(version):
def _pad_version(left, right):
+ # type: (List[str], List[str]) -> Tuple[List[str], List[str]]
left_split, right_split = [], []
# Get the release segment of our versions
@@ -567,14 +663,16 @@ def _pad_version(left, right):
class SpecifierSet(BaseSpecifier):
def __init__(self, specifiers="", prereleases=None):
- # Split on , to break each indidivual specifier into it's own item, and
+ # type: (str, Optional[bool]) -> None
+
+ # Split on , to break each individual specifier into it's own item, and
# strip each item to remove leading/trailing whitespace.
- specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
+ split_specifiers = [s.strip() for s in specifiers.split(",") if s.strip()]
# Parsed each individual specifier, attempting first to make it a
# Specifier and falling back to a LegacySpecifier.
parsed = set()
- for specifier in specifiers:
+ for specifier in split_specifiers:
try:
parsed.add(Specifier(specifier))
except InvalidSpecifier:
@@ -588,6 +686,7 @@ class SpecifierSet(BaseSpecifier):
self._prereleases = prereleases
def __repr__(self):
+ # type: () -> str
pre = (
", prereleases={0!r}".format(self.prereleases)
if self._prereleases is not None
@@ -597,12 +696,15 @@ class SpecifierSet(BaseSpecifier):
return "".format(str(self), pre)
def __str__(self):
+ # type: () -> str
return ",".join(sorted(str(s) for s in self._specs))
def __hash__(self):
+ # type: () -> int
return hash(self._specs)
def __and__(self, other):
+ # type: (Union[SpecifierSet, str]) -> SpecifierSet
if isinstance(other, string_types):
other = SpecifierSet(other)
elif not isinstance(other, SpecifierSet):
@@ -626,9 +728,8 @@ class SpecifierSet(BaseSpecifier):
return specifier
def __eq__(self, other):
- if isinstance(other, string_types):
- other = SpecifierSet(other)
- elif isinstance(other, _IndividualSpecifier):
+ # type: (object) -> bool
+ if isinstance(other, (string_types, _IndividualSpecifier)):
other = SpecifierSet(str(other))
elif not isinstance(other, SpecifierSet):
return NotImplemented
@@ -636,9 +737,8 @@ class SpecifierSet(BaseSpecifier):
return self._specs == other._specs
def __ne__(self, other):
- if isinstance(other, string_types):
- other = SpecifierSet(other)
- elif isinstance(other, _IndividualSpecifier):
+ # type: (object) -> bool
+ if isinstance(other, (string_types, _IndividualSpecifier)):
other = SpecifierSet(str(other))
elif not isinstance(other, SpecifierSet):
return NotImplemented
@@ -646,13 +746,17 @@ class SpecifierSet(BaseSpecifier):
return self._specs != other._specs
def __len__(self):
+ # type: () -> int
return len(self._specs)
def __iter__(self):
+ # type: () -> Iterator[FrozenSet[_IndividualSpecifier]]
return iter(self._specs)
@property
def prereleases(self):
+ # type: () -> Optional[bool]
+
# If we have been given an explicit prerelease modifier, then we'll
# pass that through here.
if self._prereleases is not None:
@@ -670,12 +774,16 @@ class SpecifierSet(BaseSpecifier):
@prereleases.setter
def prereleases(self, value):
+ # type: (bool) -> None
self._prereleases = value
def __contains__(self, item):
+ # type: (Union[ParsedVersion, str]) -> bool
return self.contains(item)
def contains(self, item, prereleases=None):
+ # type: (Union[ParsedVersion, str], Optional[bool]) -> bool
+
# Ensure that our item is a Version or LegacyVersion instance.
if not isinstance(item, (LegacyVersion, Version)):
item = parse(item)
@@ -701,7 +809,13 @@ class SpecifierSet(BaseSpecifier):
# will always return True, this is an explicit design decision.
return all(s.contains(item, prereleases=prereleases) for s in self._specs)
- def filter(self, iterable, prereleases=None):
+ def filter(
+ self,
+ iterable, # type: Iterable[Union[ParsedVersion, str]]
+ prereleases=None, # type: Optional[bool]
+ ):
+ # type: (...) -> Iterable[Union[ParsedVersion, str]]
+
# Determine if we're forcing a prerelease or not, if we're not forcing
# one for this particular filter call, then we'll use whatever the
# SpecifierSet thinks for whether or not we should support prereleases.
@@ -719,8 +833,8 @@ class SpecifierSet(BaseSpecifier):
# which will filter out any pre-releases, unless there are no final
# releases, and which will filter out LegacyVersion in general.
else:
- filtered = []
- found_prereleases = []
+ filtered = [] # type: List[Union[ParsedVersion, str]]
+ found_prereleases = [] # type: List[Union[ParsedVersion, str]]
for item in iterable:
# Ensure that we some kind of Version class for this item.
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/utils.py b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/utils.py
index 8841878..19579c1 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/utils.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/utils.py
@@ -5,28 +5,36 @@ from __future__ import absolute_import, division, print_function
import re
+from ._typing import TYPE_CHECKING, cast
from .version import InvalidVersion, Version
+if TYPE_CHECKING: # pragma: no cover
+ from typing import NewType, Union
+
+ NormalizedName = NewType("NormalizedName", str)
_canonicalize_regex = re.compile(r"[-_.]+")
def canonicalize_name(name):
+ # type: (str) -> NormalizedName
# This is taken from PEP 503.
- return _canonicalize_regex.sub("-", name).lower()
+ value = _canonicalize_regex.sub("-", name).lower()
+ return cast("NormalizedName", value)
-def canonicalize_version(version):
+def canonicalize_version(_version):
+ # type: (str) -> Union[Version, str]
"""
- This is very similar to Version.__str__, but has one subtle differences
+ This is very similar to Version.__str__, but has one subtle difference
with the way it handles the release segment.
"""
try:
- version = Version(version)
+ version = Version(_version)
except InvalidVersion:
# Legacy versions cannot be normalized
- return version
+ return _version
parts = []
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/version.py b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/version.py
index 95157a1..00371e8 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/packaging/version.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/packaging/version.py
@@ -7,8 +7,35 @@ import collections
import itertools
import re
-from ._structures import Infinity
+from ._structures import Infinity, NegativeInfinity
+from ._typing import TYPE_CHECKING
+if TYPE_CHECKING: # pragma: no cover
+ from typing import Callable, Iterator, List, Optional, SupportsInt, Tuple, Union
+
+ from ._structures import InfinityType, NegativeInfinityType
+
+ InfiniteTypes = Union[InfinityType, NegativeInfinityType]
+ PrePostDevType = Union[InfiniteTypes, Tuple[str, int]]
+ SubLocalType = Union[InfiniteTypes, int, str]
+ LocalType = Union[
+ NegativeInfinityType,
+ Tuple[
+ Union[
+ SubLocalType,
+ Tuple[SubLocalType, str],
+ Tuple[NegativeInfinityType, SubLocalType],
+ ],
+ ...,
+ ],
+ ]
+ CmpKey = Tuple[
+ int, Tuple[int, ...], PrePostDevType, PrePostDevType, PrePostDevType, LocalType
+ ]
+ LegacyCmpKey = Tuple[int, Tuple[str, ...]]
+ VersionComparisonMethod = Callable[
+ [Union[CmpKey, LegacyCmpKey], Union[CmpKey, LegacyCmpKey]], bool
+ ]
__all__ = ["parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"]
@@ -19,6 +46,7 @@ _Version = collections.namedtuple(
def parse(version):
+ # type: (str) -> Union[LegacyVersion, Version]
"""
Parse the given version string and return either a :class:`Version` object
or a :class:`LegacyVersion` object depending on if the given version is
@@ -37,28 +65,38 @@ class InvalidVersion(ValueError):
class _BaseVersion(object):
+ _key = None # type: Union[CmpKey, LegacyCmpKey]
+
def __hash__(self):
+ # type: () -> int
return hash(self._key)
def __lt__(self, other):
+ # type: (_BaseVersion) -> bool
return self._compare(other, lambda s, o: s < o)
def __le__(self, other):
+ # type: (_BaseVersion) -> bool
return self._compare(other, lambda s, o: s <= o)
def __eq__(self, other):
+ # type: (object) -> bool
return self._compare(other, lambda s, o: s == o)
def __ge__(self, other):
+ # type: (_BaseVersion) -> bool
return self._compare(other, lambda s, o: s >= o)
def __gt__(self, other):
+ # type: (_BaseVersion) -> bool
return self._compare(other, lambda s, o: s > o)
def __ne__(self, other):
+ # type: (object) -> bool
return self._compare(other, lambda s, o: s != o)
def _compare(self, other, method):
+ # type: (object, VersionComparisonMethod) -> Union[bool, NotImplemented]
if not isinstance(other, _BaseVersion):
return NotImplemented
@@ -67,57 +105,71 @@ class _BaseVersion(object):
class LegacyVersion(_BaseVersion):
def __init__(self, version):
+ # type: (str) -> None
self._version = str(version)
self._key = _legacy_cmpkey(self._version)
def __str__(self):
+ # type: () -> str
return self._version
def __repr__(self):
+ # type: () -> str
return "".format(repr(str(self)))
@property
def public(self):
+ # type: () -> str
return self._version
@property
def base_version(self):
+ # type: () -> str
return self._version
@property
def epoch(self):
+ # type: () -> int
return -1
@property
def release(self):
+ # type: () -> None
return None
@property
def pre(self):
+ # type: () -> None
return None
@property
def post(self):
+ # type: () -> None
return None
@property
def dev(self):
+ # type: () -> None
return None
@property
def local(self):
+ # type: () -> None
return None
@property
def is_prerelease(self):
+ # type: () -> bool
return False
@property
def is_postrelease(self):
+ # type: () -> bool
return False
@property
def is_devrelease(self):
+ # type: () -> bool
return False
@@ -133,6 +185,7 @@ _legacy_version_replacement_map = {
def _parse_version_parts(s):
+ # type: (str) -> Iterator[str]
for part in _legacy_version_component_re.split(s):
part = _legacy_version_replacement_map.get(part, part)
@@ -150,6 +203,8 @@ def _parse_version_parts(s):
def _legacy_cmpkey(version):
+ # type: (str) -> LegacyCmpKey
+
# We hardcode an epoch of -1 here. A PEP 440 version can only have a epoch
# greater than or equal to 0. This will effectively put the LegacyVersion,
# which uses the defacto standard originally implemented by setuptools,
@@ -158,7 +213,7 @@ def _legacy_cmpkey(version):
# This scheme is taken from pkg_resources.parse_version setuptools prior to
# it's adoption of the packaging library.
- parts = []
+ parts = [] # type: List[str]
for part in _parse_version_parts(version.lower()):
if part.startswith("*"):
# remove "-" before a prerelease tag
@@ -171,9 +226,8 @@ def _legacy_cmpkey(version):
parts.pop()
parts.append(part)
- parts = tuple(parts)
- return epoch, parts
+ return epoch, tuple(parts)
# Deliberately not anchored to the start and end of the string, to make it
@@ -215,6 +269,8 @@ class Version(_BaseVersion):
_regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE)
def __init__(self, version):
+ # type: (str) -> None
+
# Validate the version and parse it into pieces
match = self._regex.search(version)
if not match:
@@ -243,9 +299,11 @@ class Version(_BaseVersion):
)
def __repr__(self):
+ # type: () -> str
return "".format(repr(str(self)))
def __str__(self):
+ # type: () -> str
parts = []
# Epoch
@@ -275,26 +333,35 @@ class Version(_BaseVersion):
@property
def epoch(self):
- return self._version.epoch
+ # type: () -> int
+ _epoch = self._version.epoch # type: int
+ return _epoch
@property
def release(self):
- return self._version.release
+ # type: () -> Tuple[int, ...]
+ _release = self._version.release # type: Tuple[int, ...]
+ return _release
@property
def pre(self):
- return self._version.pre
+ # type: () -> Optional[Tuple[str, int]]
+ _pre = self._version.pre # type: Optional[Tuple[str, int]]
+ return _pre
@property
def post(self):
+ # type: () -> Optional[Tuple[str, int]]
return self._version.post[1] if self._version.post else None
@property
def dev(self):
+ # type: () -> Optional[Tuple[str, int]]
return self._version.dev[1] if self._version.dev else None
@property
def local(self):
+ # type: () -> Optional[str]
if self._version.local:
return ".".join(str(x) for x in self._version.local)
else:
@@ -302,10 +369,12 @@ class Version(_BaseVersion):
@property
def public(self):
+ # type: () -> str
return str(self).split("+", 1)[0]
@property
def base_version(self):
+ # type: () -> str
parts = []
# Epoch
@@ -319,18 +388,41 @@ class Version(_BaseVersion):
@property
def is_prerelease(self):
+ # type: () -> bool
return self.dev is not None or self.pre is not None
@property
def is_postrelease(self):
+ # type: () -> bool
return self.post is not None
@property
def is_devrelease(self):
+ # type: () -> bool
return self.dev is not None
+ @property
+ def major(self):
+ # type: () -> int
+ return self.release[0] if len(self.release) >= 1 else 0
+
+ @property
+ def minor(self):
+ # type: () -> int
+ return self.release[1] if len(self.release) >= 2 else 0
+
+ @property
+ def micro(self):
+ # type: () -> int
+ return self.release[2] if len(self.release) >= 3 else 0
+
+
+def _parse_letter_version(
+ letter, # type: str
+ number, # type: Union[str, bytes, SupportsInt]
+):
+ # type: (...) -> Optional[Tuple[str, int]]
-def _parse_letter_version(letter, number):
if letter:
# We consider there to be an implicit 0 in a pre-release if there is
# not a numeral associated with it.
@@ -360,11 +452,14 @@ def _parse_letter_version(letter, number):
return letter, int(number)
+ return None
+
_local_version_separators = re.compile(r"[\._-]")
def _parse_local_version(local):
+ # type: (str) -> Optional[LocalType]
"""
Takes a string like abc.1.twelve and turns it into ("abc", 1, "twelve").
"""
@@ -373,15 +468,25 @@ def _parse_local_version(local):
part.lower() if not part.isdigit() else int(part)
for part in _local_version_separators.split(local)
)
+ return None
-def _cmpkey(epoch, release, pre, post, dev, local):
+def _cmpkey(
+ epoch, # type: int
+ release, # type: Tuple[int, ...]
+ pre, # type: Optional[Tuple[str, int]]
+ post, # type: Optional[Tuple[str, int]]
+ dev, # type: Optional[Tuple[str, int]]
+ local, # type: Optional[Tuple[SubLocalType]]
+):
+ # type: (...) -> CmpKey
+
# When we compare a release version, we want to compare it with all of the
# trailing zeros removed. So we'll use a reverse the list, drop all the now
# leading zeros until we come to something non zero, then take the rest
# re-reverse it back into the correct order and make it a tuple and use
# that for our sorting key.
- release = tuple(
+ _release = tuple(
reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release))))
)
@@ -390,23 +495,31 @@ def _cmpkey(epoch, release, pre, post, dev, local):
# if there is not a pre or a post segment. If we have one of those then
# the normal sorting rules will handle this case correctly.
if pre is None and post is None and dev is not None:
- pre = -Infinity
+ _pre = NegativeInfinity # type: PrePostDevType
# Versions without a pre-release (except as noted above) should sort after
# those with one.
elif pre is None:
- pre = Infinity
+ _pre = Infinity
+ else:
+ _pre = pre
# Versions without a post segment should sort before those with one.
if post is None:
- post = -Infinity
+ _post = NegativeInfinity # type: PrePostDevType
+
+ else:
+ _post = post
# Versions without a development segment should sort after those with one.
if dev is None:
- dev = Infinity
+ _dev = Infinity # type: PrePostDevType
+
+ else:
+ _dev = dev
if local is None:
# Versions without a local segment should sort before those with one.
- local = -Infinity
+ _local = NegativeInfinity # type: LocalType
else:
# Versions with a local segment need that segment parsed to implement
# the sorting rules in PEP440.
@@ -415,6 +528,8 @@ def _cmpkey(epoch, release, pre, post, dev, local):
# - Numeric segments sort numerically
# - Shorter versions sort before longer versions when the prefixes
# match exactly
- local = tuple((i, "") if isinstance(i, int) else (-Infinity, i) for i in local)
+ _local = tuple(
+ (i, "") if isinstance(i, int) else (NegativeInfinity, i) for i in local
+ )
- return epoch, release, pre, post, dev, local
+ return epoch, _release, _pre, _post, _dev, _local
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__init__.py
index 9c1a098..7355b68 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__init__.py
@@ -1,4 +1,4 @@
"""Wrappers to build Python packages using PEP 517 hooks
"""
-__version__ = '0.5.0'
+__version__ = '0.8.2'
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/__init__.cpython-38.pyc
index 10ef5b9..fa2ae9b 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/_in_process.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/_in_process.cpython-38.pyc
index e387822..f220f9f 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/_in_process.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/_in_process.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/build.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/build.cpython-38.pyc
index 6ca2abb..d03423c 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/build.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/build.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/check.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/check.cpython-38.pyc
index e50911e..9f1ffb2 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/check.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/check.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/colorlog.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/colorlog.cpython-38.pyc
index 1600f01..5411803 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/colorlog.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/colorlog.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/compat.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/compat.cpython-38.pyc
index 17eea03..b6bc587 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/compat.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/compat.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/envbuild.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/envbuild.cpython-38.pyc
index 67ade92..25e4aaf 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/envbuild.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/envbuild.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/wrappers.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/wrappers.cpython-38.pyc
index a6feb11..a5134dc 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/wrappers.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/__pycache__/wrappers.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/_in_process.py b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/_in_process.py
index d6524b6..a536b03 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/_in_process.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/_in_process.py
@@ -2,7 +2,9 @@
It expects:
- Command line args: hook_name, control_dir
-- Environment variable: PEP517_BUILD_BACKEND=entry.point:spec
+- Environment variables:
+ PEP517_BUILD_BACKEND=entry.point:spec
+ PEP517_BACKEND_PATH=paths (separated with os.pathsep)
- control_dir/input.json:
- {"kwargs": {...}}
@@ -12,28 +14,86 @@ Results:
"""
from glob import glob
from importlib import import_module
+import json
import os
+import os.path
from os.path import join as pjoin
import re
import shutil
import sys
+import traceback
-# This is run as a script, not a module, so it can't do a relative import
-import compat
+# This file is run as a script, and `import compat` is not zip-safe, so we
+# include write_json() and read_json() from compat.py.
+#
+# Handle reading and writing JSON in UTF-8, on Python 3 and 2.
+
+if sys.version_info[0] >= 3:
+ # Python 3
+ def write_json(obj, path, **kwargs):
+ with open(path, 'w', encoding='utf-8') as f:
+ json.dump(obj, f, **kwargs)
+
+ def read_json(path):
+ with open(path, 'r', encoding='utf-8') as f:
+ return json.load(f)
+
+else:
+ # Python 2
+ def write_json(obj, path, **kwargs):
+ with open(path, 'wb') as f:
+ json.dump(obj, f, encoding='utf-8', **kwargs)
+
+ def read_json(path):
+ with open(path, 'rb') as f:
+ return json.load(f)
class BackendUnavailable(Exception):
"""Raised if we cannot import the backend"""
+ def __init__(self, traceback):
+ self.traceback = traceback
+
+
+class BackendInvalid(Exception):
+ """Raised if the backend is invalid"""
+ def __init__(self, message):
+ self.message = message
+
+
+class HookMissing(Exception):
+ """Raised if a hook is missing and we are not executing the fallback"""
+
+
+def contained_in(filename, directory):
+ """Test if a file is located within the given directory."""
+ filename = os.path.normcase(os.path.abspath(filename))
+ directory = os.path.normcase(os.path.abspath(directory))
+ return os.path.commonprefix([filename, directory]) == directory
def _build_backend():
"""Find and load the build backend"""
+ # Add in-tree backend directories to the front of sys.path.
+ backend_path = os.environ.get('PEP517_BACKEND_PATH')
+ if backend_path:
+ extra_pathitems = backend_path.split(os.pathsep)
+ sys.path[:0] = extra_pathitems
+
ep = os.environ['PEP517_BUILD_BACKEND']
mod_path, _, obj_path = ep.partition(':')
try:
obj = import_module(mod_path)
except ImportError:
- raise BackendUnavailable
+ raise BackendUnavailable(traceback.format_exc())
+
+ if backend_path:
+ if not any(
+ contained_in(obj.__file__, path)
+ for path in extra_pathitems
+ ):
+ raise BackendInvalid("Backend was not loaded from backend-path")
+
if obj_path:
for path_part in obj_path.split('.'):
obj = getattr(obj, path_part)
@@ -54,15 +114,19 @@ def get_requires_for_build_wheel(config_settings):
return hook(config_settings)
-def prepare_metadata_for_build_wheel(metadata_directory, config_settings):
+def prepare_metadata_for_build_wheel(
+ metadata_directory, config_settings, _allow_fallback):
"""Invoke optional prepare_metadata_for_build_wheel
- Implements a fallback by building a wheel if the hook isn't defined.
+ Implements a fallback by building a wheel if the hook isn't defined,
+ unless _allow_fallback is False in which case HookMissing is raised.
"""
backend = _build_backend()
try:
hook = backend.prepare_metadata_for_build_wheel
except AttributeError:
+ if not _allow_fallback:
+ raise HookMissing()
return _get_wheel_metadata_from_wheel(backend, metadata_directory,
config_settings)
else:
@@ -161,6 +225,8 @@ class _DummyException(Exception):
class GotUnsupportedOperation(Exception):
"""For internal use when backend raises UnsupportedOperation"""
+ def __init__(self, traceback):
+ self.traceback = traceback
def build_sdist(sdist_directory, config_settings):
@@ -169,7 +235,7 @@ def build_sdist(sdist_directory, config_settings):
try:
return backend.build_sdist(sdist_directory, config_settings)
except getattr(backend, 'UnsupportedOperation', _DummyException):
- raise GotUnsupportedOperation
+ raise GotUnsupportedOperation(traceback.format_exc())
HOOK_NAMES = {
@@ -190,17 +256,24 @@ def main():
sys.exit("Unknown hook: %s" % hook_name)
hook = globals()[hook_name]
- hook_input = compat.read_json(pjoin(control_dir, 'input.json'))
+ hook_input = read_json(pjoin(control_dir, 'input.json'))
json_out = {'unsupported': False, 'return_val': None}
try:
json_out['return_val'] = hook(**hook_input['kwargs'])
- except BackendUnavailable:
+ except BackendUnavailable as e:
json_out['no_backend'] = True
- except GotUnsupportedOperation:
+ json_out['traceback'] = e.traceback
+ except BackendInvalid as e:
+ json_out['backend_invalid'] = True
+ json_out['backend_error'] = e.message
+ except GotUnsupportedOperation as e:
json_out['unsupported'] = True
+ json_out['traceback'] = e.traceback
+ except HookMissing:
+ json_out['hook_missing'] = True
- compat.write_json(json_out, pjoin(control_dir, 'output.json'), indent=2)
+ write_json(json_out, pjoin(control_dir, 'output.json'), indent=2)
if __name__ == '__main__':
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/build.py b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/build.py
index ac6c949..2643014 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/build.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/build.py
@@ -3,25 +3,56 @@
import argparse
import logging
import os
-import contextlib
-from pip._vendor import pytoml
+from pip._vendor import toml
import shutil
-import errno
-import tempfile
from .envbuild import BuildEnvironment
from .wrappers import Pep517HookCaller
+from .dirtools import tempdir, mkdir_p
+from .compat import FileNotFoundError
log = logging.getLogger(__name__)
-@contextlib.contextmanager
-def tempdir():
- td = tempfile.mkdtemp()
+def validate_system(system):
+ """
+ Ensure build system has the requisite fields.
+ """
+ required = {'requires', 'build-backend'}
+ if not (required <= set(system)):
+ message = "Missing required fields: {missing}".format(
+ missing=required-set(system),
+ )
+ raise ValueError(message)
+
+
+def load_system(source_dir):
+ """
+ Load the build system from a source dir (pyproject.toml).
+ """
+ pyproject = os.path.join(source_dir, 'pyproject.toml')
+ with open(pyproject) as f:
+ pyproject_data = toml.load(f)
+ return pyproject_data['build-system']
+
+
+def compat_system(source_dir):
+ """
+ Given a source dir, attempt to get a build system backend
+ and requirements from pyproject.toml. Fallback to
+ setuptools but only if the file was not found or a build
+ system was not indicated.
+ """
try:
- yield td
- finally:
- shutil.rmtree(td)
+ system = load_system(source_dir)
+ except (FileNotFoundError, KeyError):
+ system = {}
+ system.setdefault(
+ 'build-backend',
+ 'setuptools.build_meta:__legacy__',
+ )
+ system.setdefault('requires', ['setuptools', 'wheel'])
+ return system
def _do_build(hooks, env, dist, dest):
@@ -42,33 +73,18 @@ def _do_build(hooks, env, dist, dest):
shutil.move(source, os.path.join(dest, os.path.basename(filename)))
-def mkdir_p(*args, **kwargs):
- """Like `mkdir`, but does not raise an exception if the
- directory already exists.
- """
- try:
- return os.mkdir(*args, **kwargs)
- except OSError as exc:
- if exc.errno != errno.EEXIST:
- raise
-
-
-def build(source_dir, dist, dest=None):
- pyproject = os.path.join(source_dir, 'pyproject.toml')
+def build(source_dir, dist, dest=None, system=None):
+ system = system or load_system(source_dir)
dest = os.path.join(source_dir, dest or 'dist')
mkdir_p(dest)
- with open(pyproject) as f:
- pyproject_data = pytoml.load(f)
- # Ensure the mandatory data can be loaded
- buildsys = pyproject_data['build-system']
- requires = buildsys['requires']
- backend = buildsys['build-backend']
-
- hooks = Pep517HookCaller(source_dir, backend)
+ validate_system(system)
+ hooks = Pep517HookCaller(
+ source_dir, system['build-backend'], system.get('backend-path')
+ )
with BuildEnvironment() as env:
- env.pip_install(requires)
+ env.pip_install(system['requires'])
_do_build(hooks, env, dist, dest)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/check.py b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/check.py
index f4cdc6b..13e722a 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/check.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/check.py
@@ -4,7 +4,7 @@ import argparse
import logging
import os
from os.path import isfile, join as pjoin
-from pip._vendor.pytoml import TomlError, load as toml_load
+from pip._vendor.toml import TomlDecodeError, load as toml_load
import shutil
from subprocess import CalledProcessError
import sys
@@ -147,12 +147,13 @@ def check(source_dir):
buildsys = pyproject_data['build-system']
requires = buildsys['requires']
backend = buildsys['build-backend']
+ backend_path = buildsys.get('backend-path')
log.info('Loaded pyproject.toml')
- except (TomlError, KeyError):
+ except (TomlDecodeError, KeyError):
log.error("Invalid pyproject.toml", exc_info=True)
return False
- hooks = Pep517HookCaller(source_dir, backend)
+ hooks = Pep517HookCaller(source_dir, backend, backend_path)
sdist_ok = check_build_sdist(hooks, requires)
wheel_ok = check_build_wheel(hooks, requires)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/compat.py b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/compat.py
index 01c66fc..8432acb 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/compat.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/compat.py
@@ -1,7 +1,10 @@
-"""Handle reading and writing JSON in UTF-8, on Python 3 and 2."""
+"""Python 2/3 compatibility"""
import json
import sys
+
+# Handle reading and writing JSON in UTF-8, on Python 3 and 2.
+
if sys.version_info[0] >= 3:
# Python 3
def write_json(obj, path, **kwargs):
@@ -21,3 +24,11 @@ else:
def read_json(path):
with open(path, 'rb') as f:
return json.load(f)
+
+
+# FileNotFoundError
+
+try:
+ FileNotFoundError = FileNotFoundError
+except NameError:
+ FileNotFoundError = IOError
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/envbuild.py b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/envbuild.py
index f7ac5f4..4088dcd 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/envbuild.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/envbuild.py
@@ -3,23 +3,27 @@
import os
import logging
-from pip._vendor import pytoml
+from pip._vendor import toml
import shutil
from subprocess import check_call
import sys
from sysconfig import get_paths
from tempfile import mkdtemp
-from .wrappers import Pep517HookCaller
+from .wrappers import Pep517HookCaller, LoggerWrapper
log = logging.getLogger(__name__)
def _load_pyproject(source_dir):
with open(os.path.join(source_dir, 'pyproject.toml')) as f:
- pyproject_data = pytoml.load(f)
+ pyproject_data = toml.load(f)
buildsys = pyproject_data['build-system']
- return buildsys['requires'], buildsys['build-backend']
+ return (
+ buildsys['requires'],
+ buildsys['build-backend'],
+ buildsys.get('backend-path'),
+ )
class BuildEnvironment(object):
@@ -90,9 +94,14 @@ class BuildEnvironment(object):
if not reqs:
return
log.info('Calling pip to install %s', reqs)
- check_call([
+ cmd = [
sys.executable, '-m', 'pip', 'install', '--ignore-installed',
- '--prefix', self.path] + list(reqs))
+ '--prefix', self.path] + list(reqs)
+ check_call(
+ cmd,
+ stdout=LoggerWrapper(log, logging.INFO),
+ stderr=LoggerWrapper(log, logging.ERROR),
+ )
def __exit__(self, exc_type, exc_val, exc_tb):
needs_cleanup = (
@@ -126,8 +135,8 @@ def build_wheel(source_dir, wheel_dir, config_settings=None):
"""
if config_settings is None:
config_settings = {}
- requires, backend = _load_pyproject(source_dir)
- hooks = Pep517HookCaller(source_dir, backend)
+ requires, backend, backend_path = _load_pyproject(source_dir)
+ hooks = Pep517HookCaller(source_dir, backend, backend_path)
with BuildEnvironment() as env:
env.pip_install(requires)
@@ -148,8 +157,8 @@ def build_sdist(source_dir, sdist_dir, config_settings=None):
"""
if config_settings is None:
config_settings = {}
- requires, backend = _load_pyproject(source_dir)
- hooks = Pep517HookCaller(source_dir, backend)
+ requires, backend, backend_path = _load_pyproject(source_dir)
+ hooks = Pep517HookCaller(source_dir, backend, backend_path)
with BuildEnvironment() as env:
env.pip_install(requires)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/wrappers.py b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/wrappers.py
index b14b899..00a3d1a 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/pep517/wrappers.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/pep517/wrappers.py
@@ -1,14 +1,24 @@
+import threading
from contextlib import contextmanager
import os
from os.path import dirname, abspath, join as pjoin
import shutil
-from subprocess import check_call
+from subprocess import check_call, check_output, STDOUT
import sys
from tempfile import mkdtemp
from . import compat
-_in_proc_script = pjoin(dirname(abspath(__file__)), '_in_process.py')
+
+try:
+ import importlib.resources as resources
+
+ def _in_proc_script_path():
+ return resources.path(__package__, '_in_process.py')
+except ImportError:
+ @contextmanager
+ def _in_proc_script_path():
+ yield pjoin(dirname(abspath(__file__)), '_in_process.py')
@contextmanager
@@ -22,10 +32,29 @@ def tempdir():
class BackendUnavailable(Exception):
"""Will be raised if the backend cannot be imported in the hook process."""
+ def __init__(self, traceback):
+ self.traceback = traceback
+
+
+class BackendInvalid(Exception):
+ """Will be raised if the backend is invalid."""
+ def __init__(self, backend_name, backend_path, message):
+ self.backend_name = backend_name
+ self.backend_path = backend_path
+ self.message = message
+
+
+class HookMissing(Exception):
+ """Will be raised on missing hooks."""
+ def __init__(self, hook_name):
+ super(HookMissing, self).__init__(hook_name)
+ self.hook_name = hook_name
class UnsupportedOperation(Exception):
"""May be raised by build_sdist if the backend indicates that it can't."""
+ def __init__(self, traceback):
+ self.traceback = traceback
def default_subprocess_runner(cmd, cwd=None, extra_environ=None):
@@ -37,25 +66,86 @@ def default_subprocess_runner(cmd, cwd=None, extra_environ=None):
check_call(cmd, cwd=cwd, env=env)
+def quiet_subprocess_runner(cmd, cwd=None, extra_environ=None):
+ """A method of calling the wrapper subprocess while suppressing output."""
+ env = os.environ.copy()
+ if extra_environ:
+ env.update(extra_environ)
+
+ check_output(cmd, cwd=cwd, env=env, stderr=STDOUT)
+
+
+def norm_and_check(source_tree, requested):
+ """Normalise and check a backend path.
+
+ Ensure that the requested backend path is specified as a relative path,
+ and resolves to a location under the given source tree.
+
+ Return an absolute version of the requested path.
+ """
+ if os.path.isabs(requested):
+ raise ValueError("paths must be relative")
+
+ abs_source = os.path.abspath(source_tree)
+ abs_requested = os.path.normpath(os.path.join(abs_source, requested))
+ # We have to use commonprefix for Python 2.7 compatibility. So we
+ # normalise case to avoid problems because commonprefix is a character
+ # based comparison :-(
+ norm_source = os.path.normcase(abs_source)
+ norm_requested = os.path.normcase(abs_requested)
+ if os.path.commonprefix([norm_source, norm_requested]) != norm_source:
+ raise ValueError("paths must be inside source tree")
+
+ return abs_requested
+
+
class Pep517HookCaller(object):
"""A wrapper around a source directory to be built with a PEP 517 backend.
source_dir : The path to the source directory, containing pyproject.toml.
- backend : The build backend spec, as per PEP 517, from pyproject.toml.
+ build_backend : The build backend spec, as per PEP 517, from
+ pyproject.toml.
+ backend_path : The backend path, as per PEP 517, from pyproject.toml.
+ runner : A callable that invokes the wrapper subprocess.
+
+ The 'runner', if provided, must expect the following:
+ cmd : a list of strings representing the command and arguments to
+ execute, as would be passed to e.g. 'subprocess.check_call'.
+ cwd : a string representing the working directory that must be
+ used for the subprocess. Corresponds to the provided source_dir.
+ extra_environ : a dict mapping environment variable names to values
+ which must be set for the subprocess execution.
"""
- def __init__(self, source_dir, build_backend):
+ def __init__(
+ self,
+ source_dir,
+ build_backend,
+ backend_path=None,
+ runner=None,
+ ):
+ if runner is None:
+ runner = default_subprocess_runner
+
self.source_dir = abspath(source_dir)
self.build_backend = build_backend
- self._subprocess_runner = default_subprocess_runner
+ if backend_path:
+ backend_path = [
+ norm_and_check(self.source_dir, p) for p in backend_path
+ ]
+ self.backend_path = backend_path
+ self._subprocess_runner = runner
- # TODO: Is this over-engineered? Maybe frontends only need to
- # set this when creating the wrapper, not on every call.
@contextmanager
def subprocess_runner(self, runner):
+ """A context manager for temporarily overriding the default subprocess
+ runner.
+ """
prev = self._subprocess_runner
self._subprocess_runner = runner
- yield
- self._subprocess_runner = prev
+ try:
+ yield
+ finally:
+ self._subprocess_runner = prev
def get_requires_for_build_wheel(self, config_settings=None):
"""Identify packages required for building a wheel
@@ -72,18 +162,21 @@ class Pep517HookCaller(object):
})
def prepare_metadata_for_build_wheel(
- self, metadata_directory, config_settings=None):
+ self, metadata_directory, config_settings=None,
+ _allow_fallback=True):
"""Prepare a *.dist-info folder with metadata for this project.
Returns the name of the newly created folder.
If the build backend defines a hook with this name, it will be called
in a subprocess. If not, the backend will be asked to build a wheel,
- and the dist-info extracted from that.
+ and the dist-info extracted from that (unless _allow_fallback is
+ False).
"""
return self._call_hook('prepare_metadata_for_build_wheel', {
'metadata_directory': abspath(metadata_directory),
'config_settings': config_settings,
+ '_allow_fallback': _allow_fallback,
})
def build_wheel(
@@ -139,25 +232,77 @@ class Pep517HookCaller(object):
# letters, digits and _, . and : characters, and will be used as a
# Python identifier, so non-ASCII content is wrong on Python 2 in
# any case).
+ # For backend_path, we use sys.getfilesystemencoding.
if sys.version_info[0] == 2:
build_backend = self.build_backend.encode('ASCII')
else:
build_backend = self.build_backend
+ extra_environ = {'PEP517_BUILD_BACKEND': build_backend}
+
+ if self.backend_path:
+ backend_path = os.pathsep.join(self.backend_path)
+ if sys.version_info[0] == 2:
+ backend_path = backend_path.encode(sys.getfilesystemencoding())
+ extra_environ['PEP517_BACKEND_PATH'] = backend_path
with tempdir() as td:
- compat.write_json({'kwargs': kwargs}, pjoin(td, 'input.json'),
+ hook_input = {'kwargs': kwargs}
+ compat.write_json(hook_input, pjoin(td, 'input.json'),
indent=2)
# Run the hook in a subprocess
- self._subprocess_runner(
- [sys.executable, _in_proc_script, hook_name, td],
- cwd=self.source_dir,
- extra_environ={'PEP517_BUILD_BACKEND': build_backend}
- )
+ with _in_proc_script_path() as script:
+ self._subprocess_runner(
+ [sys.executable, str(script), hook_name, td],
+ cwd=self.source_dir,
+ extra_environ=extra_environ
+ )
data = compat.read_json(pjoin(td, 'output.json'))
if data.get('unsupported'):
- raise UnsupportedOperation
+ raise UnsupportedOperation(data.get('traceback', ''))
if data.get('no_backend'):
- raise BackendUnavailable
+ raise BackendUnavailable(data.get('traceback', ''))
+ if data.get('backend_invalid'):
+ raise BackendInvalid(
+ backend_name=self.build_backend,
+ backend_path=self.backend_path,
+ message=data.get('backend_error', '')
+ )
+ if data.get('hook_missing'):
+ raise HookMissing(hook_name)
return data['return_val']
+
+
+class LoggerWrapper(threading.Thread):
+ """
+ Read messages from a pipe and redirect them
+ to a logger (see python's logging module).
+ """
+
+ def __init__(self, logger, level):
+ threading.Thread.__init__(self)
+ self.daemon = True
+
+ self.logger = logger
+ self.level = level
+
+ # create the pipe and reader
+ self.fd_read, self.fd_write = os.pipe()
+ self.reader = os.fdopen(self.fd_read)
+
+ self.start()
+
+ def fileno(self):
+ return self.fd_write
+
+ @staticmethod
+ def remove_newline(msg):
+ return msg[:-1] if msg.endswith(os.linesep) else msg
+
+ def run(self):
+ for line in self.reader:
+ self._write(self.remove_newline(line))
+
+ def _write(self, message):
+ self.logger.log(self.level, message)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pkg_resources/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/pkg_resources/__init__.py
index fdd40de..a457ff2 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/pkg_resources/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/pkg_resources/__init__.py
@@ -88,8 +88,8 @@ __import__('pip._vendor.packaging.markers')
__metaclass__ = type
-if (3, 0) < sys.version_info < (3, 4):
- raise RuntimeError("Python 3.4 or later is required")
+if (3, 0) < sys.version_info < (3, 5):
+ raise RuntimeError("Python 3.5 or later is required")
if six.PY2:
# Those builtin exceptions are only defined in Python 3
@@ -333,7 +333,7 @@ class UnknownExtra(ResolutionError):
_provider_factories = {}
-PY_MAJOR = sys.version[:3]
+PY_MAJOR = '{}.{}'.format(*sys.version_info)
EGG_DIST = 3
BINARY_DIST = 2
SOURCE_DIST = 1
@@ -1416,8 +1416,17 @@ class NullProvider:
def get_metadata(self, name):
if not self.egg_info:
return ""
- value = self._get(self._fn(self.egg_info, name))
- return value.decode('utf-8') if six.PY3 else value
+ path = self._get_metadata_path(name)
+ value = self._get(path)
+ if six.PY2:
+ return value
+ try:
+ return value.decode('utf-8')
+ except UnicodeDecodeError as exc:
+ # Include the path in the error message to simplify
+ # troubleshooting, and without changing the exception type.
+ exc.reason += ' in {} file at path: {}'.format(name, path)
+ raise
def get_metadata_lines(self, name):
return yield_lines(self.get_metadata(name))
@@ -3100,6 +3109,7 @@ class Requirement(packaging.requirements.Requirement):
self.extras = tuple(map(safe_extra, self.extras))
self.hashCmp = (
self.key,
+ self.url,
self.specifier,
frozenset(self.extras),
str(self.marker) if self.marker else None,
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-38.pyc
index 1e98392..097cf44 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pkg_resources/__pycache__/py31compat.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/pkg_resources/__pycache__/py31compat.cpython-38.pyc
index 74cff63..9f2d5f3 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/pkg_resources/__pycache__/py31compat.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/pkg_resources/__pycache__/py31compat.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/progress/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/progress/__pycache__/__init__.cpython-38.pyc
index 5d9cf81..1956a2b 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/progress/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/progress/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/progress/__pycache__/bar.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/progress/__pycache__/bar.cpython-38.pyc
index 2b50ee5..b1f436b 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/progress/__pycache__/bar.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/progress/__pycache__/bar.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/progress/__pycache__/counter.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/progress/__pycache__/counter.cpython-38.pyc
index 15bc9cf..af018cd 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/progress/__pycache__/counter.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/progress/__pycache__/counter.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/progress/__pycache__/spinner.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/progress/__pycache__/spinner.cpython-38.pyc
index 975363c..b0ffcaf 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/progress/__pycache__/spinner.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/progress/__pycache__/spinner.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pyparsing.py b/venv/lib/python3.8/site-packages/pip/_vendor/pyparsing.py
index 9d6a01d..7ebc7eb 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/pyparsing.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/pyparsing.py
@@ -1,4 +1,4 @@
-#-*- coding: utf-8 -*-
+# -*- coding: utf-8 -*-
# module pyparsing.py
#
# Copyright (c) 2003-2019 Paul T. McGuire
@@ -87,14 +87,16 @@ classes inherit from. Use the docstrings for examples of how to:
more complex ones
- associate names with your parsed results using
:class:`ParserElement.setResultsName`
+ - access the parsed data, which is returned as a :class:`ParseResults`
+ object
- find some helpful expression short-cuts like :class:`delimitedList`
and :class:`oneOf`
- find more useful common expressions in the :class:`pyparsing_common`
namespace class
"""
-__version__ = "2.4.0"
-__versionTime__ = "07 Apr 2019 18:28 UTC"
+__version__ = "2.4.7"
+__versionTime__ = "30 Mar 2020 00:43 UTC"
__author__ = "Paul McGuire "
import string
@@ -109,6 +111,10 @@ import pprint
import traceback
import types
from datetime import datetime
+from operator import itemgetter
+import itertools
+from functools import wraps
+from contextlib import contextmanager
try:
# Python 3
@@ -124,11 +130,11 @@ except ImportError:
try:
# Python 3
from collections.abc import Iterable
- from collections.abc import MutableMapping
+ from collections.abc import MutableMapping, Mapping
except ImportError:
# Python 2.7
from collections import Iterable
- from collections import MutableMapping
+ from collections import MutableMapping, Mapping
try:
from collections import OrderedDict as _OrderedDict
@@ -146,40 +152,70 @@ except ImportError:
# version compatibility configuration
__compat__ = SimpleNamespace()
__compat__.__doc__ = """
- A cross-version compatibility configuration for pyparsing features that will be
- released in a future version. By setting values in this configuration to True,
- those features can be enabled in prior versions for compatibility development
+ A cross-version compatibility configuration for pyparsing features that will be
+ released in a future version. By setting values in this configuration to True,
+ those features can be enabled in prior versions for compatibility development
and testing.
-
+
- collect_all_And_tokens - flag to enable fix for Issue #63 that fixes erroneous grouping
- of results names when an And expression is nested within an Or or MatchFirst; set to
- True to enable bugfix to be released in pyparsing 2.4
+ of results names when an And expression is nested within an Or or MatchFirst; set to
+ True to enable bugfix released in pyparsing 2.3.0, or False to preserve
+ pre-2.3.0 handling of named results
"""
__compat__.collect_all_And_tokens = True
+__diag__ = SimpleNamespace()
+__diag__.__doc__ = """
+Diagnostic configuration (all default to False)
+ - warn_multiple_tokens_in_named_alternation - flag to enable warnings when a results
+ name is defined on a MatchFirst or Or expression with one or more And subexpressions
+ (only warns if __compat__.collect_all_And_tokens is False)
+ - warn_ungrouped_named_tokens_in_collection - flag to enable warnings when a results
+ name is defined on a containing expression with ungrouped subexpressions that also
+ have results names
+ - warn_name_set_on_empty_Forward - flag to enable warnings whan a Forward is defined
+ with a results name, but has no contents defined
+ - warn_on_multiple_string_args_to_oneof - flag to enable warnings whan oneOf is
+ incorrectly called with multiple str arguments
+ - enable_debug_on_named_expressions - flag to auto-enable debug on all subsequent
+ calls to ParserElement.setName()
+"""
+__diag__.warn_multiple_tokens_in_named_alternation = False
+__diag__.warn_ungrouped_named_tokens_in_collection = False
+__diag__.warn_name_set_on_empty_Forward = False
+__diag__.warn_on_multiple_string_args_to_oneof = False
+__diag__.enable_debug_on_named_expressions = False
+__diag__._all_names = [nm for nm in vars(__diag__) if nm.startswith("enable_") or nm.startswith("warn_")]
-#~ sys.stderr.write( "testing pyparsing module, version %s, %s\n" % (__version__,__versionTime__ ) )
+def _enable_all_warnings():
+ __diag__.warn_multiple_tokens_in_named_alternation = True
+ __diag__.warn_ungrouped_named_tokens_in_collection = True
+ __diag__.warn_name_set_on_empty_Forward = True
+ __diag__.warn_on_multiple_string_args_to_oneof = True
+__diag__.enable_all_warnings = _enable_all_warnings
-__all__ = [ '__version__', '__versionTime__', '__author__', '__compat__',
-'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty',
-'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal',
-'PrecededBy', 'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or',
-'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException',
-'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException',
-'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter',
-'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore', 'Char',
-'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col',
-'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString',
-'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'hexnums',
-'htmlComment', 'javaStyleComment', 'line', 'lineEnd', 'lineStart', 'lineno',
-'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral',
-'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables',
-'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity',
-'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd',
-'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute',
-'indentedBlock', 'originalTextFor', 'ungroup', 'infixNotation','locatedExpr', 'withClass',
-'CloseMatch', 'tokenMap', 'pyparsing_common', 'pyparsing_unicode', 'unicode_set',
-]
+
+__all__ = ['__version__', '__versionTime__', '__author__', '__compat__', '__diag__',
+ 'And', 'CaselessKeyword', 'CaselessLiteral', 'CharsNotIn', 'Combine', 'Dict', 'Each', 'Empty',
+ 'FollowedBy', 'Forward', 'GoToColumn', 'Group', 'Keyword', 'LineEnd', 'LineStart', 'Literal',
+ 'PrecededBy', 'MatchFirst', 'NoMatch', 'NotAny', 'OneOrMore', 'OnlyOnce', 'Optional', 'Or',
+ 'ParseBaseException', 'ParseElementEnhance', 'ParseException', 'ParseExpression', 'ParseFatalException',
+ 'ParseResults', 'ParseSyntaxException', 'ParserElement', 'QuotedString', 'RecursiveGrammarException',
+ 'Regex', 'SkipTo', 'StringEnd', 'StringStart', 'Suppress', 'Token', 'TokenConverter',
+ 'White', 'Word', 'WordEnd', 'WordStart', 'ZeroOrMore', 'Char',
+ 'alphanums', 'alphas', 'alphas8bit', 'anyCloseTag', 'anyOpenTag', 'cStyleComment', 'col',
+ 'commaSeparatedList', 'commonHTMLEntity', 'countedArray', 'cppStyleComment', 'dblQuotedString',
+ 'dblSlashComment', 'delimitedList', 'dictOf', 'downcaseTokens', 'empty', 'hexnums',
+ 'htmlComment', 'javaStyleComment', 'line', 'lineEnd', 'lineStart', 'lineno',
+ 'makeHTMLTags', 'makeXMLTags', 'matchOnlyAtCol', 'matchPreviousExpr', 'matchPreviousLiteral',
+ 'nestedExpr', 'nullDebugAction', 'nums', 'oneOf', 'opAssoc', 'operatorPrecedence', 'printables',
+ 'punc8bit', 'pythonStyleComment', 'quotedString', 'removeQuotes', 'replaceHTMLEntity',
+ 'replaceWith', 'restOfLine', 'sglQuotedString', 'srange', 'stringEnd',
+ 'stringStart', 'traceParseAction', 'unicodeString', 'upcaseTokens', 'withAttribute',
+ 'indentedBlock', 'originalTextFor', 'ungroup', 'infixNotation', 'locatedExpr', 'withClass',
+ 'CloseMatch', 'tokenMap', 'pyparsing_common', 'pyparsing_unicode', 'unicode_set',
+ 'conditionAsParseAction', 're',
+ ]
system_version = tuple(sys.version_info)[:3]
PY_3 = system_version[0] == 3
@@ -204,7 +240,7 @@ else:
< returns the unicode object | encodes it with the default
encoding | ... >.
"""
- if isinstance(obj,unicode):
+ if isinstance(obj, unicode):
return obj
try:
@@ -222,9 +258,10 @@ else:
# build list of single arg builtins, tolerant of Python version, that can be used as parse actions
singleArgBuiltins = []
import __builtin__
+
for fname in "sum len sorted reversed list tuple set any all min max".split():
try:
- singleArgBuiltins.append(getattr(__builtin__,fname))
+ singleArgBuiltins.append(getattr(__builtin__, fname))
except AttributeError:
continue
@@ -235,23 +272,36 @@ def _xml_escape(data):
# ampersand must be replaced first
from_symbols = '&><"\''
- to_symbols = ('&'+s+';' for s in "amp gt lt quot apos".split())
- for from_,to_ in zip(from_symbols, to_symbols):
+ to_symbols = ('&' + s + ';' for s in "amp gt lt quot apos".split())
+ for from_, to_ in zip(from_symbols, to_symbols):
data = data.replace(from_, to_)
return data
-alphas = string.ascii_uppercase + string.ascii_lowercase
-nums = "0123456789"
-hexnums = nums + "ABCDEFabcdef"
-alphanums = alphas + nums
-_bslash = chr(92)
+alphas = string.ascii_uppercase + string.ascii_lowercase
+nums = "0123456789"
+hexnums = nums + "ABCDEFabcdef"
+alphanums = alphas + nums
+_bslash = chr(92)
printables = "".join(c for c in string.printable if c not in string.whitespace)
+
+def conditionAsParseAction(fn, message=None, fatal=False):
+ msg = message if message is not None else "failed user-defined condition"
+ exc_type = ParseFatalException if fatal else ParseException
+ fn = _trim_arity(fn)
+
+ @wraps(fn)
+ def pa(s, l, t):
+ if not bool(fn(s, l, t)):
+ raise exc_type(s, l, msg)
+
+ return pa
+
class ParseBaseException(Exception):
"""base exception class for all parsing runtime exceptions"""
# Performance tuning: we construct a *lot* of these, so keep this
# constructor as small and fast as possible
- def __init__( self, pstr, loc=0, msg=None, elem=None ):
+ def __init__(self, pstr, loc=0, msg=None, elem=None):
self.loc = loc
if msg is None:
self.msg = pstr
@@ -270,27 +320,34 @@ class ParseBaseException(Exception):
"""
return cls(pe.pstr, pe.loc, pe.msg, pe.parserElement)
- def __getattr__( self, aname ):
+ def __getattr__(self, aname):
"""supported attributes by name are:
- lineno - returns the line number of the exception text
- col - returns the column number of the exception text
- line - returns the line containing the exception text
"""
- if( aname == "lineno" ):
- return lineno( self.loc, self.pstr )
- elif( aname in ("col", "column") ):
- return col( self.loc, self.pstr )
- elif( aname == "line" ):
- return line( self.loc, self.pstr )
+ if aname == "lineno":
+ return lineno(self.loc, self.pstr)
+ elif aname in ("col", "column"):
+ return col(self.loc, self.pstr)
+ elif aname == "line":
+ return line(self.loc, self.pstr)
else:
raise AttributeError(aname)
- def __str__( self ):
- return "%s (at char %d), (line:%d, col:%d)" % \
- ( self.msg, self.loc, self.lineno, self.column )
- def __repr__( self ):
+ def __str__(self):
+ if self.pstr:
+ if self.loc >= len(self.pstr):
+ foundstr = ', found end of text'
+ else:
+ foundstr = (', found %r' % self.pstr[self.loc:self.loc + 1]).replace(r'\\', '\\')
+ else:
+ foundstr = ''
+ return ("%s%s (at char %d), (line:%d, col:%d)" %
+ (self.msg, foundstr, self.loc, self.lineno, self.column))
+ def __repr__(self):
return _ustr(self)
- def markInputline( self, markerString = ">!<" ):
+ def markInputline(self, markerString=">!<"):
"""Extracts the exception line from the input string, and marks
the location of the exception with a special symbol.
"""
@@ -426,21 +483,21 @@ class RecursiveGrammarException(Exception):
"""exception thrown by :class:`ParserElement.validate` if the
grammar could be improperly recursive
"""
- def __init__( self, parseElementList ):
+ def __init__(self, parseElementList):
self.parseElementTrace = parseElementList
- def __str__( self ):
+ def __str__(self):
return "RecursiveGrammarException: %s" % self.parseElementTrace
class _ParseResultsWithOffset(object):
- def __init__(self,p1,p2):
- self.tup = (p1,p2)
- def __getitem__(self,i):
+ def __init__(self, p1, p2):
+ self.tup = (p1, p2)
+ def __getitem__(self, i):
return self.tup[i]
def __repr__(self):
return repr(self.tup[0])
- def setOffset(self,i):
- self.tup = (self.tup[0],i)
+ def setOffset(self, i):
+ self.tup = (self.tup[0], i)
class ParseResults(object):
"""Structured parse results, to provide multiple means of access to
@@ -485,7 +542,7 @@ class ParseResults(object):
- month: 12
- year: 1999
"""
- def __new__(cls, toklist=None, name=None, asList=True, modal=True ):
+ def __new__(cls, toklist=None, name=None, asList=True, modal=True):
if isinstance(toklist, cls):
return toklist
retobj = object.__new__(cls)
@@ -494,7 +551,7 @@ class ParseResults(object):
# Performance tuning: we construct a *lot* of these, so keep this
# constructor as small and fast as possible
- def __init__( self, toklist=None, name=None, asList=True, modal=True, isinstance=isinstance ):
+ def __init__(self, toklist=None, name=None, asList=True, modal=True, isinstance=isinstance):
if self.__doinit:
self.__doinit = False
self.__name = None
@@ -515,85 +572,93 @@ class ParseResults(object):
if name is not None and name:
if not modal:
self.__accumNames[name] = 0
- if isinstance(name,int):
- name = _ustr(name) # will always return a str, but use _ustr for consistency
+ if isinstance(name, int):
+ name = _ustr(name) # will always return a str, but use _ustr for consistency
self.__name = name
- if not (isinstance(toklist, (type(None), basestring, list)) and toklist in (None,'',[])):
- if isinstance(toklist,basestring):
- toklist = [ toklist ]
+ if not (isinstance(toklist, (type(None), basestring, list)) and toklist in (None, '', [])):
+ if isinstance(toklist, basestring):
+ toklist = [toklist]
if asList:
- if isinstance(toklist,ParseResults):
+ if isinstance(toklist, ParseResults):
self[name] = _ParseResultsWithOffset(ParseResults(toklist.__toklist), 0)
else:
- self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]),0)
+ self[name] = _ParseResultsWithOffset(ParseResults(toklist[0]), 0)
self[name].__name = name
else:
try:
self[name] = toklist[0]
- except (KeyError,TypeError,IndexError):
+ except (KeyError, TypeError, IndexError):
self[name] = toklist
- def __getitem__( self, i ):
- if isinstance( i, (int,slice) ):
+ def __getitem__(self, i):
+ if isinstance(i, (int, slice)):
return self.__toklist[i]
else:
if i not in self.__accumNames:
return self.__tokdict[i][-1][0]
else:
- return ParseResults([ v[0] for v in self.__tokdict[i] ])
+ return ParseResults([v[0] for v in self.__tokdict[i]])
- def __setitem__( self, k, v, isinstance=isinstance ):
- if isinstance(v,_ParseResultsWithOffset):
- self.__tokdict[k] = self.__tokdict.get(k,list()) + [v]
+ def __setitem__(self, k, v, isinstance=isinstance):
+ if isinstance(v, _ParseResultsWithOffset):
+ self.__tokdict[k] = self.__tokdict.get(k, list()) + [v]
sub = v[0]
- elif isinstance(k,(int,slice)):
+ elif isinstance(k, (int, slice)):
self.__toklist[k] = v
sub = v
else:
- self.__tokdict[k] = self.__tokdict.get(k,list()) + [_ParseResultsWithOffset(v,0)]
+ self.__tokdict[k] = self.__tokdict.get(k, list()) + [_ParseResultsWithOffset(v, 0)]
sub = v
- if isinstance(sub,ParseResults):
+ if isinstance(sub, ParseResults):
sub.__parent = wkref(self)
- def __delitem__( self, i ):
- if isinstance(i,(int,slice)):
- mylen = len( self.__toklist )
+ def __delitem__(self, i):
+ if isinstance(i, (int, slice)):
+ mylen = len(self.__toklist)
del self.__toklist[i]
# convert int to slice
if isinstance(i, int):
if i < 0:
i += mylen
- i = slice(i, i+1)
+ i = slice(i, i + 1)
# get removed indices
removed = list(range(*i.indices(mylen)))
removed.reverse()
# fixup indices in token dictionary
- for name,occurrences in self.__tokdict.items():
+ for name, occurrences in self.__tokdict.items():
for j in removed:
for k, (value, position) in enumerate(occurrences):
occurrences[k] = _ParseResultsWithOffset(value, position - (position > j))
else:
del self.__tokdict[i]
- def __contains__( self, k ):
+ def __contains__(self, k):
return k in self.__tokdict
- def __len__( self ): return len( self.__toklist )
- def __bool__(self): return ( not not self.__toklist )
+ def __len__(self):
+ return len(self.__toklist)
+
+ def __bool__(self):
+ return (not not self.__toklist)
__nonzero__ = __bool__
- def __iter__( self ): return iter( self.__toklist )
- def __reversed__( self ): return iter( self.__toklist[::-1] )
- def _iterkeys( self ):
+
+ def __iter__(self):
+ return iter(self.__toklist)
+
+ def __reversed__(self):
+ return iter(self.__toklist[::-1])
+
+ def _iterkeys(self):
if hasattr(self.__tokdict, "iterkeys"):
return self.__tokdict.iterkeys()
else:
return iter(self.__tokdict)
- def _itervalues( self ):
+ def _itervalues(self):
return (self[k] for k in self._iterkeys())
- def _iteritems( self ):
+ def _iteritems(self):
return ((k, self[k]) for k in self._iterkeys())
if PY_3:
@@ -616,24 +681,24 @@ class ParseResults(object):
iteritems = _iteritems
"""Returns an iterator of all named result key-value tuples (Python 2.x only)."""
- def keys( self ):
+ def keys(self):
"""Returns all named result keys (as a list in Python 2.x, as an iterator in Python 3.x)."""
return list(self.iterkeys())
- def values( self ):
+ def values(self):
"""Returns all named result values (as a list in Python 2.x, as an iterator in Python 3.x)."""
return list(self.itervalues())
- def items( self ):
+ def items(self):
"""Returns all named result key-values (as a list of tuples in Python 2.x, as an iterator in Python 3.x)."""
return list(self.iteritems())
- def haskeys( self ):
+ def haskeys(self):
"""Since keys() returns an iterator, this method is helpful in bypassing
code that looks for the existence of any defined results names."""
return bool(self.__tokdict)
- def pop( self, *args, **kwargs):
+ def pop(self, *args, **kwargs):
"""
Removes and returns item at specified index (default= ``last``).
Supports both ``list`` and ``dict`` semantics for ``pop()``. If
@@ -672,14 +737,14 @@ class ParseResults(object):
"""
if not args:
args = [-1]
- for k,v in kwargs.items():
+ for k, v in kwargs.items():
if k == 'default':
args = (args[0], v)
else:
raise TypeError("pop() got an unexpected keyword argument '%s'" % k)
- if (isinstance(args[0], int) or
- len(args) == 1 or
- args[0] in self):
+ if (isinstance(args[0], int)
+ or len(args) == 1
+ or args[0] in self):
index = args[0]
ret = self[index]
del self[index]
@@ -711,7 +776,7 @@ class ParseResults(object):
else:
return defaultValue
- def insert( self, index, insStr ):
+ def insert(self, index, insStr):
"""
Inserts new element at location index in the list of parsed tokens.
@@ -728,11 +793,11 @@ class ParseResults(object):
"""
self.__toklist.insert(index, insStr)
# fixup indices in token dictionary
- for name,occurrences in self.__tokdict.items():
+ for name, occurrences in self.__tokdict.items():
for k, (value, position) in enumerate(occurrences):
occurrences[k] = _ParseResultsWithOffset(value, position + (position > index))
- def append( self, item ):
+ def append(self, item):
"""
Add single element to end of ParseResults list of elements.
@@ -747,7 +812,7 @@ class ParseResults(object):
"""
self.__toklist.append(item)
- def extend( self, itemseq ):
+ def extend(self, itemseq):
"""
Add sequence of elements to end of ParseResults list of elements.
@@ -766,74 +831,66 @@ class ParseResults(object):
else:
self.__toklist.extend(itemseq)
- def clear( self ):
+ def clear(self):
"""
Clear all elements and results names.
"""
del self.__toklist[:]
self.__tokdict.clear()
- def __getattr__( self, name ):
+ def __getattr__(self, name):
try:
return self[name]
except KeyError:
return ""
- if name in self.__tokdict:
- if name not in self.__accumNames:
- return self.__tokdict[name][-1][0]
- else:
- return ParseResults([ v[0] for v in self.__tokdict[name] ])
- else:
- return ""
-
- def __add__( self, other ):
+ def __add__(self, other):
ret = self.copy()
ret += other
return ret
- def __iadd__( self, other ):
+ def __iadd__(self, other):
if other.__tokdict:
offset = len(self.__toklist)
- addoffset = lambda a: offset if a<0 else a+offset
+ addoffset = lambda a: offset if a < 0 else a + offset
otheritems = other.__tokdict.items()
- otherdictitems = [(k, _ParseResultsWithOffset(v[0],addoffset(v[1])) )
- for (k,vlist) in otheritems for v in vlist]
- for k,v in otherdictitems:
+ otherdictitems = [(k, _ParseResultsWithOffset(v[0], addoffset(v[1])))
+ for k, vlist in otheritems for v in vlist]
+ for k, v in otherdictitems:
self[k] = v
- if isinstance(v[0],ParseResults):
+ if isinstance(v[0], ParseResults):
v[0].__parent = wkref(self)
self.__toklist += other.__toklist
- self.__accumNames.update( other.__accumNames )
+ self.__accumNames.update(other.__accumNames)
return self
def __radd__(self, other):
- if isinstance(other,int) and other == 0:
+ if isinstance(other, int) and other == 0:
# useful for merging many ParseResults using sum() builtin
return self.copy()
else:
# this may raise a TypeError - so be it
return other + self
- def __repr__( self ):
- return "(%s, %s)" % ( repr( self.__toklist ), repr( self.__tokdict ) )
+ def __repr__(self):
+ return "(%s, %s)" % (repr(self.__toklist), repr(self.__tokdict))
- def __str__( self ):
+ def __str__(self):
return '[' + ', '.join(_ustr(i) if isinstance(i, ParseResults) else repr(i) for i in self.__toklist) + ']'
- def _asStringList( self, sep='' ):
+ def _asStringList(self, sep=''):
out = []
for item in self.__toklist:
if out and sep:
out.append(sep)
- if isinstance( item, ParseResults ):
+ if isinstance(item, ParseResults):
out += item._asStringList()
else:
- out.append( _ustr(item) )
+ out.append(_ustr(item))
return out
- def asList( self ):
+ def asList(self):
"""
Returns the parse results as a nested list of matching tokens, all converted to strings.
@@ -848,9 +905,9 @@ class ParseResults(object):
result_list = result.asList()
print(type(result_list), result_list) # -> ['sldkj', 'lsdkj', 'sldkj']
"""
- return [res.asList() if isinstance(res,ParseResults) else res for res in self.__toklist]
+ return [res.asList() if isinstance(res, ParseResults) else res for res in self.__toklist]
- def asDict( self ):
+ def asDict(self):
"""
Returns the named parse results as a nested dictionary.
@@ -884,27 +941,27 @@ class ParseResults(object):
else:
return obj
- return dict((k,toItem(v)) for k,v in item_fn())
+ return dict((k, toItem(v)) for k, v in item_fn())
- def copy( self ):
+ def copy(self):
"""
Returns a new copy of a :class:`ParseResults` object.
"""
- ret = ParseResults( self.__toklist )
+ ret = ParseResults(self.__toklist)
ret.__tokdict = dict(self.__tokdict.items())
ret.__parent = self.__parent
- ret.__accumNames.update( self.__accumNames )
+ ret.__accumNames.update(self.__accumNames)
ret.__name = self.__name
return ret
- def asXML( self, doctag=None, namedItemsOnly=False, indent="", formatted=True ):
+ def asXML(self, doctag=None, namedItemsOnly=False, indent="", formatted=True):
"""
(Deprecated) Returns the parse results as XML. Tags are created for tokens and lists that have defined results names.
"""
nl = "\n"
out = []
- namedItems = dict((v[1],k) for (k,vlist) in self.__tokdict.items()
- for v in vlist)
+ namedItems = dict((v[1], k) for (k, vlist) in self.__tokdict.items()
+ for v in vlist)
nextLevelIndent = indent + " "
# collapse out indents if formatting is not desired
@@ -926,20 +983,20 @@ class ParseResults(object):
else:
selfTag = "ITEM"
- out += [ nl, indent, "<", selfTag, ">" ]
+ out += [nl, indent, "<", selfTag, ">"]
- for i,res in enumerate(self.__toklist):
- if isinstance(res,ParseResults):
+ for i, res in enumerate(self.__toklist):
+ if isinstance(res, ParseResults):
if i in namedItems:
- out += [ res.asXML(namedItems[i],
- namedItemsOnly and doctag is None,
- nextLevelIndent,
- formatted)]
+ out += [res.asXML(namedItems[i],
+ namedItemsOnly and doctag is None,
+ nextLevelIndent,
+ formatted)]
else:
- out += [ res.asXML(None,
- namedItemsOnly and doctag is None,
- nextLevelIndent,
- formatted)]
+ out += [res.asXML(None,
+ namedItemsOnly and doctag is None,
+ nextLevelIndent,
+ formatted)]
else:
# individual token, see if there is a name for it
resTag = None
@@ -951,16 +1008,16 @@ class ParseResults(object):
else:
resTag = "ITEM"
xmlBodyText = _xml_escape(_ustr(res))
- out += [ nl, nextLevelIndent, "<", resTag, ">",
- xmlBodyText,
- "", resTag, ">" ]
+ out += [nl, nextLevelIndent, "<", resTag, ">",
+ xmlBodyText,
+ "", resTag, ">"]
- out += [ nl, indent, "", selfTag, ">" ]
+ out += [nl, indent, "", selfTag, ">"]
return "".join(out)
- def __lookup(self,sub):
- for k,vlist in self.__tokdict.items():
- for v,loc in vlist:
+ def __lookup(self, sub):
+ for k, vlist in self.__tokdict.items():
+ for v, loc in vlist:
if sub is v:
return k
return None
@@ -998,14 +1055,14 @@ class ParseResults(object):
return par.__lookup(self)
else:
return None
- elif (len(self) == 1 and
- len(self.__tokdict) == 1 and
- next(iter(self.__tokdict.values()))[0][1] in (0,-1)):
+ elif (len(self) == 1
+ and len(self.__tokdict) == 1
+ and next(iter(self.__tokdict.values()))[0][1] in (0, -1)):
return next(iter(self.__tokdict.keys()))
else:
return None
- def dump(self, indent='', depth=0, full=True):
+ def dump(self, indent='', full=True, include_list=True, _depth=0):
"""
Diagnostic method for listing out the contents of
a :class:`ParseResults`. Accepts an optional ``indent`` argument so
@@ -1028,28 +1085,45 @@ class ParseResults(object):
"""
out = []
NL = '\n'
- out.append( indent+_ustr(self.asList()) )
+ if include_list:
+ out.append(indent + _ustr(self.asList()))
+ else:
+ out.append('')
+
if full:
if self.haskeys():
- items = sorted((str(k), v) for k,v in self.items())
- for k,v in items:
+ items = sorted((str(k), v) for k, v in self.items())
+ for k, v in items:
if out:
out.append(NL)
- out.append( "%s%s- %s: " % (indent,(' '*depth), k) )
- if isinstance(v,ParseResults):
+ out.append("%s%s- %s: " % (indent, (' ' * _depth), k))
+ if isinstance(v, ParseResults):
if v:
- out.append( v.dump(indent,depth+1) )
+ out.append(v.dump(indent=indent, full=full, include_list=include_list, _depth=_depth + 1))
else:
out.append(_ustr(v))
else:
out.append(repr(v))
- elif any(isinstance(vv,ParseResults) for vv in self):
+ elif any(isinstance(vv, ParseResults) for vv in self):
v = self
- for i,vv in enumerate(v):
- if isinstance(vv,ParseResults):
- out.append("\n%s%s[%d]:\n%s%s%s" % (indent,(' '*(depth)),i,indent,(' '*(depth+1)),vv.dump(indent,depth+1) ))
+ for i, vv in enumerate(v):
+ if isinstance(vv, ParseResults):
+ out.append("\n%s%s[%d]:\n%s%s%s" % (indent,
+ (' ' * (_depth)),
+ i,
+ indent,
+ (' ' * (_depth + 1)),
+ vv.dump(indent=indent,
+ full=full,
+ include_list=include_list,
+ _depth=_depth + 1)))
else:
- out.append("\n%s%s[%d]:\n%s%s%s" % (indent,(' '*(depth)),i,indent,(' '*(depth+1)),_ustr(vv)))
+ out.append("\n%s%s[%d]:\n%s%s%s" % (indent,
+ (' ' * (_depth)),
+ i,
+ indent,
+ (' ' * (_depth + 1)),
+ _ustr(vv)))
return "".join(out)
@@ -1082,18 +1156,15 @@ class ParseResults(object):
# add support for pickle protocol
def __getstate__(self):
- return ( self.__toklist,
- ( self.__tokdict.copy(),
- self.__parent is not None and self.__parent() or None,
- self.__accumNames,
- self.__name ) )
+ return (self.__toklist,
+ (self.__tokdict.copy(),
+ self.__parent is not None and self.__parent() or None,
+ self.__accumNames,
+ self.__name))
- def __setstate__(self,state):
+ def __setstate__(self, state):
self.__toklist = state[0]
- (self.__tokdict,
- par,
- inAccumNames,
- self.__name) = state[1]
+ self.__tokdict, par, inAccumNames, self.__name = state[1]
self.__accumNames = {}
self.__accumNames.update(inAccumNames)
if par is not None:
@@ -1105,11 +1176,39 @@ class ParseResults(object):
return self.__toklist, self.__name, self.__asList, self.__modal
def __dir__(self):
- return (dir(type(self)) + list(self.keys()))
+ return dir(type(self)) + list(self.keys())
+
+ @classmethod
+ def from_dict(cls, other, name=None):
+ """
+ Helper classmethod to construct a ParseResults from a dict, preserving the
+ name-value relations as results names. If an optional 'name' argument is
+ given, a nested ParseResults will be returned
+ """
+ def is_iterable(obj):
+ try:
+ iter(obj)
+ except Exception:
+ return False
+ else:
+ if PY_3:
+ return not isinstance(obj, (str, bytes))
+ else:
+ return not isinstance(obj, basestring)
+
+ ret = cls([])
+ for k, v in other.items():
+ if isinstance(v, Mapping):
+ ret += cls.from_dict(v, name=k)
+ else:
+ ret += cls([v], name=k, asList=is_iterable(v))
+ if name is not None:
+ ret = cls([ret], name=name)
+ return ret
MutableMapping.register(ParseResults)
-def col (loc,strg):
+def col (loc, strg):
"""Returns current column within a string, counting newlines as line separators.
The first column is number 1.
@@ -1121,9 +1220,9 @@ def col (loc,strg):
location, and line and column positions within the parsed string.
"""
s = strg
- return 1 if 0= 0:
- return strg[lastCR+1:nextCR]
+ return strg[lastCR + 1:nextCR]
else:
- return strg[lastCR+1:]
+ return strg[lastCR + 1:]
-def _defaultStartDebugAction( instring, loc, expr ):
- print (("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % ( lineno(loc,instring), col(loc,instring) )))
+def _defaultStartDebugAction(instring, loc, expr):
+ print(("Match " + _ustr(expr) + " at loc " + _ustr(loc) + "(%d,%d)" % (lineno(loc, instring), col(loc, instring))))
-def _defaultSuccessDebugAction( instring, startloc, endloc, expr, toks ):
- print ("Matched " + _ustr(expr) + " -> " + str(toks.asList()))
+def _defaultSuccessDebugAction(instring, startloc, endloc, expr, toks):
+ print("Matched " + _ustr(expr) + " -> " + str(toks.asList()))
-def _defaultExceptionDebugAction( instring, loc, expr, exc ):
- print ("Exception raised:" + _ustr(exc))
+def _defaultExceptionDebugAction(instring, loc, expr, exc):
+ print("Exception raised:" + _ustr(exc))
def nullDebugAction(*args):
"""'Do-nothing' debug action, to suppress debugging output during parsing."""
@@ -1183,16 +1282,16 @@ def nullDebugAction(*args):
'decorator to trim function calls to match the arity of the target'
def _trim_arity(func, maxargs=2):
if func in singleArgBuiltins:
- return lambda s,l,t: func(t)
+ return lambda s, l, t: func(t)
limit = [0]
foundArity = [False]
# traceback return data structure changed in Py3.5 - normalize back to plain tuples
- if system_version[:2] >= (3,5):
+ if system_version[:2] >= (3, 5):
def extract_stack(limit=0):
# special handling for Python 3.5.0 - extra deep call stack by 1
- offset = -3 if system_version == (3,5,0) else -2
- frame_summary = traceback.extract_stack(limit=-offset+limit-1)[offset]
+ offset = -3 if system_version == (3, 5, 0) else -2
+ frame_summary = traceback.extract_stack(limit=-offset + limit - 1)[offset]
return [frame_summary[:2]]
def extract_tb(tb, limit=0):
frames = traceback.extract_tb(tb, limit=limit)
@@ -1209,7 +1308,7 @@ def _trim_arity(func, maxargs=2):
# IF ANY CODE CHANGES, EVEN JUST COMMENTS OR BLANK LINES, BETWEEN THE NEXT LINE AND
# THE CALL TO FUNC INSIDE WRAPPER, LINE_DIFF MUST BE MODIFIED!!!!
this_line = extract_stack(limit=2)[-1]
- pa_call_line_synth = (this_line[0], this_line[1]+LINE_DIFF)
+ pa_call_line_synth = (this_line[0], this_line[1] + LINE_DIFF)
def wrapper(*args):
while 1:
@@ -1227,7 +1326,10 @@ def _trim_arity(func, maxargs=2):
if not extract_tb(tb, limit=2)[-1][:2] == pa_call_line_synth:
raise
finally:
- del tb
+ try:
+ del tb
+ except NameError:
+ pass
if limit[0] <= maxargs:
limit[0] += 1
@@ -1245,13 +1347,14 @@ def _trim_arity(func, maxargs=2):
return wrapper
+
class ParserElement(object):
"""Abstract base level parser element class."""
DEFAULT_WHITE_CHARS = " \n\t\r"
verbose_stacktrace = False
@staticmethod
- def setDefaultWhitespaceChars( chars ):
+ def setDefaultWhitespaceChars(chars):
r"""
Overrides the default whitespace chars
@@ -1288,10 +1391,16 @@ class ParserElement(object):
"""
ParserElement._literalStringClass = cls
- def __init__( self, savelist=False ):
+ @classmethod
+ def _trim_traceback(cls, tb):
+ while tb.tb_next:
+ tb = tb.tb_next
+ return tb
+
+ def __init__(self, savelist=False):
self.parseAction = list()
self.failAction = None
- #~ self.name = "" # don't define self.name, let subclasses try/except upcall
+ # ~ self.name = "" # don't define self.name, let subclasses try/except upcall
self.strRepr = None
self.resultsName = None
self.saveAsList = savelist
@@ -1306,12 +1415,12 @@ class ParserElement(object):
self.mayIndexError = True # used to optimize exception handling for subclasses that don't advance parse index
self.errmsg = ""
self.modalResults = True # used to mark results names as modal (report only last) or cumulative (list all)
- self.debugActions = ( None, None, None ) #custom debug actions
+ self.debugActions = (None, None, None) # custom debug actions
self.re = None
self.callPreparse = True # used to avoid redundant calls to preParse
self.callDuringTry = False
- def copy( self ):
+ def copy(self):
"""
Make a copy of this :class:`ParserElement`. Useful for defining
different parse actions for the same parsing pattern, using copies of
@@ -1320,8 +1429,8 @@ class ParserElement(object):
Example::
integer = Word(nums).setParseAction(lambda toks: int(toks[0]))
- integerK = integer.copy().addParseAction(lambda toks: toks[0]*1024) + Suppress("K")
- integerM = integer.copy().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M")
+ integerK = integer.copy().addParseAction(lambda toks: toks[0] * 1024) + Suppress("K")
+ integerM = integer.copy().addParseAction(lambda toks: toks[0] * 1024 * 1024) + Suppress("M")
print(OneOrMore(integerK | integerM | integer).parseString("5K 100 640K 256M"))
@@ -1331,16 +1440,16 @@ class ParserElement(object):
Equivalent form of ``expr.copy()`` is just ``expr()``::
- integerM = integer().addParseAction(lambda toks: toks[0]*1024*1024) + Suppress("M")
+ integerM = integer().addParseAction(lambda toks: toks[0] * 1024 * 1024) + Suppress("M")
"""
- cpy = copy.copy( self )
+ cpy = copy.copy(self)
cpy.parseAction = self.parseAction[:]
cpy.ignoreExprs = self.ignoreExprs[:]
if self.copyDefaultWhiteChars:
cpy.whiteChars = ParserElement.DEFAULT_WHITE_CHARS
return cpy
- def setName( self, name ):
+ def setName(self, name):
"""
Define name for this expression, makes debugging and exception messages clearer.
@@ -1351,11 +1460,11 @@ class ParserElement(object):
"""
self.name = name
self.errmsg = "Expected " + self.name
- if hasattr(self,"exception"):
- self.exception.msg = self.errmsg
+ if __diag__.enable_debug_on_named_expressions:
+ self.setDebug()
return self
- def setResultsName( self, name, listAllMatches=False ):
+ def setResultsName(self, name, listAllMatches=False):
"""
Define name for referencing matching tokens as a nested attribute
of the returned parse results.
@@ -1376,15 +1485,18 @@ class ParserElement(object):
# equivalent form:
date_str = integer("year") + '/' + integer("month") + '/' + integer("day")
"""
+ return self._setResultsName(name, listAllMatches)
+
+ def _setResultsName(self, name, listAllMatches=False):
newself = self.copy()
if name.endswith("*"):
name = name[:-1]
- listAllMatches=True
+ listAllMatches = True
newself.resultsName = name
newself.modalResults = not listAllMatches
return newself
- def setBreak(self,breakFlag = True):
+ def setBreak(self, breakFlag=True):
"""Method to invoke the Python pdb debugger when this element is
about to be parsed. Set ``breakFlag`` to True to enable, False to
disable.
@@ -1393,20 +1505,21 @@ class ParserElement(object):
_parseMethod = self._parse
def breaker(instring, loc, doActions=True, callPreParse=True):
import pdb
+ # this call to pdb.set_trace() is intentional, not a checkin error
pdb.set_trace()
- return _parseMethod( instring, loc, doActions, callPreParse )
+ return _parseMethod(instring, loc, doActions, callPreParse)
breaker._originalParseMethod = _parseMethod
self._parse = breaker
else:
- if hasattr(self._parse,"_originalParseMethod"):
+ if hasattr(self._parse, "_originalParseMethod"):
self._parse = self._parse._originalParseMethod
return self
- def setParseAction( self, *fns, **kwargs ):
+ def setParseAction(self, *fns, **kwargs):
"""
Define one or more actions to perform when successfully matching parse element definition.
- Parse action fn is a callable method with 0-3 arguments, called as ``fn(s,loc,toks)`` ,
- ``fn(loc,toks)`` , ``fn(toks)`` , or just ``fn()`` , where:
+ Parse action fn is a callable method with 0-3 arguments, called as ``fn(s, loc, toks)`` ,
+ ``fn(loc, toks)`` , ``fn(toks)`` , or just ``fn()`` , where:
- s = the original string being parsed (see note below)
- loc = the location of the matching substring
@@ -1416,8 +1529,11 @@ class ParserElement(object):
value from fn, and the modified list of tokens will replace the original.
Otherwise, fn does not need to return any value.
+ If None is passed as the parse action, all previously added parse actions for this
+ expression are cleared.
+
Optional keyword arguments:
- - callDuringTry = (default= ``False`` ) indicate if parse action should be run during lookaheads and alternate testing
+ - callDuringTry = (default= ``False``) indicate if parse action should be run during lookaheads and alternate testing
Note: the default parsing behavior is to expand tabs in the input string
before starting the parsing process. See :class:`parseString for more
@@ -1439,11 +1555,16 @@ class ParserElement(object):
# note that integer fields are now ints, not strings
date_str.parseString("1999/12/31") # -> [1999, '/', 12, '/', 31]
"""
- self.parseAction = list(map(_trim_arity, list(fns)))
- self.callDuringTry = kwargs.get("callDuringTry", False)
+ if list(fns) == [None,]:
+ self.parseAction = []
+ else:
+ if not all(callable(fn) for fn in fns):
+ raise TypeError("parse actions must be callable")
+ self.parseAction = list(map(_trim_arity, list(fns)))
+ self.callDuringTry = kwargs.get("callDuringTry", False)
return self
- def addParseAction( self, *fns, **kwargs ):
+ def addParseAction(self, *fns, **kwargs):
"""
Add one or more parse actions to expression's list of parse actions. See :class:`setParseAction`.
@@ -1471,21 +1592,17 @@ class ParserElement(object):
result = date_str.parseString("1999/12/31") # -> Exception: Only support years 2000 and later (at char 0), (line:1, col:1)
"""
- msg = kwargs.get("message", "failed user-defined condition")
- exc_type = ParseFatalException if kwargs.get("fatal", False) else ParseException
for fn in fns:
- fn = _trim_arity(fn)
- def pa(s,l,t):
- if not bool(fn(s,l,t)):
- raise exc_type(s,l,msg)
- self.parseAction.append(pa)
+ self.parseAction.append(conditionAsParseAction(fn, message=kwargs.get('message'),
+ fatal=kwargs.get('fatal', False)))
+
self.callDuringTry = self.callDuringTry or kwargs.get("callDuringTry", False)
return self
- def setFailAction( self, fn ):
+ def setFailAction(self, fn):
"""Define action to perform if parsing fails at this expression.
Fail acton fn is a callable function that takes the arguments
- ``fn(s,loc,expr,err)`` where:
+ ``fn(s, loc, expr, err)`` where:
- s = string being parsed
- loc = location where expression match was attempted and failed
- expr = the parse expression that failed
@@ -1495,22 +1612,22 @@ class ParserElement(object):
self.failAction = fn
return self
- def _skipIgnorables( self, instring, loc ):
+ def _skipIgnorables(self, instring, loc):
exprsFound = True
while exprsFound:
exprsFound = False
for e in self.ignoreExprs:
try:
while 1:
- loc,dummy = e._parse( instring, loc )
+ loc, dummy = e._parse(instring, loc)
exprsFound = True
except ParseException:
pass
return loc
- def preParse( self, instring, loc ):
+ def preParse(self, instring, loc):
if self.ignoreExprs:
- loc = self._skipIgnorables( instring, loc )
+ loc = self._skipIgnorables(instring, loc)
if self.skipWhitespace:
wt = self.whiteChars
@@ -1520,101 +1637,105 @@ class ParserElement(object):
return loc
- def parseImpl( self, instring, loc, doActions=True ):
+ def parseImpl(self, instring, loc, doActions=True):
return loc, []
- def postParse( self, instring, loc, tokenlist ):
+ def postParse(self, instring, loc, tokenlist):
return tokenlist
- #~ @profile
- def _parseNoCache( self, instring, loc, doActions=True, callPreParse=True ):
- debugging = ( self.debug ) #and doActions )
+ # ~ @profile
+ def _parseNoCache(self, instring, loc, doActions=True, callPreParse=True):
+ TRY, MATCH, FAIL = 0, 1, 2
+ debugging = (self.debug) # and doActions)
if debugging or self.failAction:
- #~ print ("Match",self,"at loc",loc,"(%d,%d)" % ( lineno(loc,instring), col(loc,instring) ))
- if (self.debugActions[0] ):
- self.debugActions[0]( instring, loc, self )
- if callPreParse and self.callPreparse:
- preloc = self.preParse( instring, loc )
- else:
- preloc = loc
- tokensStart = preloc
+ # ~ print ("Match", self, "at loc", loc, "(%d, %d)" % (lineno(loc, instring), col(loc, instring)))
+ if self.debugActions[TRY]:
+ self.debugActions[TRY](instring, loc, self)
try:
- try:
- loc,tokens = self.parseImpl( instring, preloc, doActions )
- except IndexError:
- raise ParseException( instring, len(instring), self.errmsg, self )
- except ParseBaseException as err:
- #~ print ("Exception raised:", err)
- if self.debugActions[2]:
- self.debugActions[2]( instring, tokensStart, self, err )
+ if callPreParse and self.callPreparse:
+ preloc = self.preParse(instring, loc)
+ else:
+ preloc = loc
+ tokensStart = preloc
+ if self.mayIndexError or preloc >= len(instring):
+ try:
+ loc, tokens = self.parseImpl(instring, preloc, doActions)
+ except IndexError:
+ raise ParseException(instring, len(instring), self.errmsg, self)
+ else:
+ loc, tokens = self.parseImpl(instring, preloc, doActions)
+ except Exception as err:
+ # ~ print ("Exception raised:", err)
+ if self.debugActions[FAIL]:
+ self.debugActions[FAIL](instring, tokensStart, self, err)
if self.failAction:
- self.failAction( instring, tokensStart, self, err )
+ self.failAction(instring, tokensStart, self, err)
raise
else:
if callPreParse and self.callPreparse:
- preloc = self.preParse( instring, loc )
+ preloc = self.preParse(instring, loc)
else:
preloc = loc
tokensStart = preloc
if self.mayIndexError or preloc >= len(instring):
try:
- loc,tokens = self.parseImpl( instring, preloc, doActions )
+ loc, tokens = self.parseImpl(instring, preloc, doActions)
except IndexError:
- raise ParseException( instring, len(instring), self.errmsg, self )
+ raise ParseException(instring, len(instring), self.errmsg, self)
else:
- loc,tokens = self.parseImpl( instring, preloc, doActions )
+ loc, tokens = self.parseImpl(instring, preloc, doActions)
- tokens = self.postParse( instring, loc, tokens )
+ tokens = self.postParse(instring, loc, tokens)
- retTokens = ParseResults( tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults )
+ retTokens = ParseResults(tokens, self.resultsName, asList=self.saveAsList, modal=self.modalResults)
if self.parseAction and (doActions or self.callDuringTry):
if debugging:
try:
for fn in self.parseAction:
try:
- tokens = fn( instring, tokensStart, retTokens )
+ tokens = fn(instring, tokensStart, retTokens)
except IndexError as parse_action_exc:
exc = ParseException("exception raised in parse action")
exc.__cause__ = parse_action_exc
raise exc
if tokens is not None and tokens is not retTokens:
- retTokens = ParseResults( tokens,
+ retTokens = ParseResults(tokens,
self.resultsName,
- asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
- modal=self.modalResults )
- except ParseBaseException as err:
- #~ print "Exception raised in user parse action:", err
- if (self.debugActions[2] ):
- self.debugActions[2]( instring, tokensStart, self, err )
+ asList=self.saveAsList and isinstance(tokens, (ParseResults, list)),
+ modal=self.modalResults)
+ except Exception as err:
+ # ~ print "Exception raised in user parse action:", err
+ if self.debugActions[FAIL]:
+ self.debugActions[FAIL](instring, tokensStart, self, err)
raise
else:
for fn in self.parseAction:
try:
- tokens = fn( instring, tokensStart, retTokens )
+ tokens = fn(instring, tokensStart, retTokens)
except IndexError as parse_action_exc:
exc = ParseException("exception raised in parse action")
exc.__cause__ = parse_action_exc
raise exc
if tokens is not None and tokens is not retTokens:
- retTokens = ParseResults( tokens,
+ retTokens = ParseResults(tokens,
self.resultsName,
- asList=self.saveAsList and isinstance(tokens,(ParseResults,list)),
- modal=self.modalResults )
+ asList=self.saveAsList and isinstance(tokens, (ParseResults, list)),
+ modal=self.modalResults)
if debugging:
- #~ print ("Matched",self,"->",retTokens.asList())
- if (self.debugActions[1] ):
- self.debugActions[1]( instring, tokensStart, loc, self, retTokens )
+ # ~ print ("Matched", self, "->", retTokens.asList())
+ if self.debugActions[MATCH]:
+ self.debugActions[MATCH](instring, tokensStart, loc, self, retTokens)
return loc, retTokens
- def tryParse( self, instring, loc ):
+ def tryParse(self, instring, loc):
try:
- return self._parse( instring, loc, doActions=False )[0]
+ return self._parse(instring, loc, doActions=False)[0]
except ParseFatalException:
- raise ParseException( instring, loc, self.errmsg, self)
+ raise ParseException(instring, loc, self.errmsg, self)
def canParseNext(self, instring, loc):
try:
@@ -1711,7 +1832,7 @@ class ParserElement(object):
# this method gets repeatedly called during backtracking with the same arguments -
# we can cache these arguments and save ourselves the trouble of re-parsing the contained expression
- def _parseCache( self, instring, loc, doActions=True, callPreParse=True ):
+ def _parseCache(self, instring, loc, doActions=True, callPreParse=True):
HIT, MISS = 0, 1
lookup = (self, instring, loc, callPreParse, doActions)
with ParserElement.packrat_cache_lock:
@@ -1732,7 +1853,7 @@ class ParserElement(object):
ParserElement.packrat_cache_stats[HIT] += 1
if isinstance(value, Exception):
raise value
- return (value[0], value[1].copy())
+ return value[0], value[1].copy()
_parse = _parseNoCache
@@ -1777,12 +1898,16 @@ class ParserElement(object):
ParserElement.packrat_cache = ParserElement._FifoCache(cache_size_limit)
ParserElement._parse = ParserElement._parseCache
- def parseString( self, instring, parseAll=False ):
+ def parseString(self, instring, parseAll=False):
"""
Execute the parse expression with the given string.
This is the main interface to the client code, once the complete
expression has been built.
+ Returns the parsed data as a :class:`ParseResults` object, which may be
+ accessed as a list, or as a dict or object with attributes if the given parser
+ includes results names.
+
If you want the grammar to require that the entire input string be
successfully parsed, then set ``parseAll`` to True (equivalent to ending
the grammar with ``StringEnd()``).
@@ -1796,7 +1921,7 @@ class ParserElement(object):
- calling ``parseWithTabs`` on your grammar before calling ``parseString``
(see :class:`parseWithTabs`)
- - define your parse action using the full ``(s,loc,toks)`` signature, and
+ - define your parse action using the full ``(s, loc, toks)`` signature, and
reference the input string using the parse action's ``s`` argument
- explictly expand the tabs in your input string before calling
``parseString``
@@ -1809,27 +1934,29 @@ class ParserElement(object):
ParserElement.resetCache()
if not self.streamlined:
self.streamline()
- #~ self.saveAsList = True
+ # ~ self.saveAsList = True
for e in self.ignoreExprs:
e.streamline()
if not self.keepTabs:
instring = instring.expandtabs()
try:
- loc, tokens = self._parse( instring, 0 )
+ loc, tokens = self._parse(instring, 0)
if parseAll:
- loc = self.preParse( instring, loc )
+ loc = self.preParse(instring, loc)
se = Empty() + StringEnd()
- se._parse( instring, loc )
+ se._parse(instring, loc)
except ParseBaseException as exc:
if ParserElement.verbose_stacktrace:
raise
else:
- # catch and re-raise exception from here, clears out pyparsing internal stack trace
+ # catch and re-raise exception from here, clearing out pyparsing internal stack trace
+ if getattr(exc, '__traceback__', None) is not None:
+ exc.__traceback__ = self._trim_traceback(exc.__traceback__)
raise exc
else:
return tokens
- def scanString( self, instring, maxMatches=_MAX_INT, overlap=False ):
+ def scanString(self, instring, maxMatches=_MAX_INT, overlap=False):
"""
Scan the input string for expression matches. Each match will return the
matching tokens, start location, and end location. May be called with optional
@@ -1844,7 +1971,7 @@ class ParserElement(object):
source = "sldjf123lsdjjkf345sldkjf879lkjsfd987"
print(source)
- for tokens,start,end in Word(alphas).scanString(source):
+ for tokens, start, end in Word(alphas).scanString(source):
print(' '*start + '^'*(end-start))
print(' '*start + tokens[0])
@@ -1876,16 +2003,16 @@ class ParserElement(object):
try:
while loc <= instrlen and matches < maxMatches:
try:
- preloc = preparseFn( instring, loc )
- nextLoc,tokens = parseFn( instring, preloc, callPreParse=False )
+ preloc = preparseFn(instring, loc)
+ nextLoc, tokens = parseFn(instring, preloc, callPreParse=False)
except ParseException:
- loc = preloc+1
+ loc = preloc + 1
else:
if nextLoc > loc:
matches += 1
yield tokens, preloc, nextLoc
if overlap:
- nextloc = preparseFn( instring, loc )
+ nextloc = preparseFn(instring, loc)
if nextloc > loc:
loc = nextLoc
else:
@@ -1893,15 +2020,17 @@ class ParserElement(object):
else:
loc = nextLoc
else:
- loc = preloc+1
+ loc = preloc + 1
except ParseBaseException as exc:
if ParserElement.verbose_stacktrace:
raise
else:
- # catch and re-raise exception from here, clears out pyparsing internal stack trace
+ # catch and re-raise exception from here, clearing out pyparsing internal stack trace
+ if getattr(exc, '__traceback__', None) is not None:
+ exc.__traceback__ = self._trim_traceback(exc.__traceback__)
raise exc
- def transformString( self, instring ):
+ def transformString(self, instring):
"""
Extension to :class:`scanString`, to modify matching text with modified tokens that may
be returned from a parse action. To use ``transformString``, define a grammar and
@@ -1927,27 +2056,29 @@ class ParserElement(object):
# keep string locs straight between transformString and scanString
self.keepTabs = True
try:
- for t,s,e in self.scanString( instring ):
- out.append( instring[lastE:s] )
+ for t, s, e in self.scanString(instring):
+ out.append(instring[lastE:s])
if t:
- if isinstance(t,ParseResults):
+ if isinstance(t, ParseResults):
out += t.asList()
- elif isinstance(t,list):
+ elif isinstance(t, list):
out += t
else:
out.append(t)
lastE = e
out.append(instring[lastE:])
out = [o for o in out if o]
- return "".join(map(_ustr,_flatten(out)))
+ return "".join(map(_ustr, _flatten(out)))
except ParseBaseException as exc:
if ParserElement.verbose_stacktrace:
raise
else:
- # catch and re-raise exception from here, clears out pyparsing internal stack trace
+ # catch and re-raise exception from here, clearing out pyparsing internal stack trace
+ if getattr(exc, '__traceback__', None) is not None:
+ exc.__traceback__ = self._trim_traceback(exc.__traceback__)
raise exc
- def searchString( self, instring, maxMatches=_MAX_INT ):
+ def searchString(self, instring, maxMatches=_MAX_INT):
"""
Another extension to :class:`scanString`, simplifying the access to the tokens found
to match the given parse expression. May be called with optional
@@ -1969,12 +2100,14 @@ class ParserElement(object):
['More', 'Iron', 'Lead', 'Gold', 'I', 'Electricity']
"""
try:
- return ParseResults([ t for t,s,e in self.scanString( instring, maxMatches ) ])
+ return ParseResults([t for t, s, e in self.scanString(instring, maxMatches)])
except ParseBaseException as exc:
if ParserElement.verbose_stacktrace:
raise
else:
- # catch and re-raise exception from here, clears out pyparsing internal stack trace
+ # catch and re-raise exception from here, clearing out pyparsing internal stack trace
+ if getattr(exc, '__traceback__', None) is not None:
+ exc.__traceback__ = self._trim_traceback(exc.__traceback__)
raise exc
def split(self, instring, maxsplit=_MAX_INT, includeSeparators=False):
@@ -1995,14 +2128,14 @@ class ParserElement(object):
"""
splits = 0
last = 0
- for t,s,e in self.scanString(instring, maxMatches=maxsplit):
+ for t, s, e in self.scanString(instring, maxMatches=maxsplit):
yield instring[last:s]
if includeSeparators:
yield t[0]
last = e
yield instring[last:]
- def __add__(self, other ):
+ def __add__(self, other):
"""
Implementation of + operator - returns :class:`And`. Adding strings to a ParserElement
converts them to :class:`Literal`s by default.
@@ -2016,24 +2149,42 @@ class ParserElement(object):
prints::
Hello, World! -> ['Hello', ',', 'World', '!']
- """
- if isinstance( other, basestring ):
- other = ParserElement._literalStringClass( other )
- if not isinstance( other, ParserElement ):
- warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
- SyntaxWarning, stacklevel=2)
- return None
- return And( [ self, other ] )
- def __radd__(self, other ):
+ ``...`` may be used as a parse expression as a short form of :class:`SkipTo`.
+
+ Literal('start') + ... + Literal('end')
+
+ is equivalent to:
+
+ Literal('start') + SkipTo('end')("_skipped*") + Literal('end')
+
+ Note that the skipped text is returned with '_skipped' as a results name,
+ and to support having multiple skips in the same parser, the value returned is
+ a list of all skipped text.
+ """
+ if other is Ellipsis:
+ return _PendingSkip(self)
+
+ if isinstance(other, basestring):
+ other = self._literalStringClass(other)
+ if not isinstance(other, ParserElement):
+ warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+ SyntaxWarning, stacklevel=2)
+ return None
+ return And([self, other])
+
+ def __radd__(self, other):
"""
Implementation of + operator when left operand is not a :class:`ParserElement`
"""
- if isinstance( other, basestring ):
- other = ParserElement._literalStringClass( other )
- if not isinstance( other, ParserElement ):
+ if other is Ellipsis:
+ return SkipTo(self)("_skipped*") + self
+
+ if isinstance(other, basestring):
+ other = self._literalStringClass(other)
+ if not isinstance(other, ParserElement):
warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
- SyntaxWarning, stacklevel=2)
+ SyntaxWarning, stacklevel=2)
return None
return other + self
@@ -2041,64 +2192,70 @@ class ParserElement(object):
"""
Implementation of - operator, returns :class:`And` with error stop
"""
- if isinstance( other, basestring ):
- other = ParserElement._literalStringClass( other )
- if not isinstance( other, ParserElement ):
+ if isinstance(other, basestring):
+ other = self._literalStringClass(other)
+ if not isinstance(other, ParserElement):
warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
- SyntaxWarning, stacklevel=2)
+ SyntaxWarning, stacklevel=2)
return None
return self + And._ErrorStop() + other
- def __rsub__(self, other ):
+ def __rsub__(self, other):
"""
Implementation of - operator when left operand is not a :class:`ParserElement`
"""
- if isinstance( other, basestring ):
- other = ParserElement._literalStringClass( other )
- if not isinstance( other, ParserElement ):
+ if isinstance(other, basestring):
+ other = self._literalStringClass(other)
+ if not isinstance(other, ParserElement):
warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
- SyntaxWarning, stacklevel=2)
+ SyntaxWarning, stacklevel=2)
return None
return other - self
- def __mul__(self,other):
+ def __mul__(self, other):
"""
Implementation of * operator, allows use of ``expr * 3`` in place of
``expr + expr + expr``. Expressions may also me multiplied by a 2-integer
- tuple, similar to ``{min,max}`` multipliers in regular expressions. Tuples
+ tuple, similar to ``{min, max}`` multipliers in regular expressions. Tuples
may also include ``None`` as in:
- - ``expr*(n,None)`` or ``expr*(n,)`` is equivalent
+ - ``expr*(n, None)`` or ``expr*(n, )`` is equivalent
to ``expr*n + ZeroOrMore(expr)``
(read as "at least n instances of ``expr``")
- - ``expr*(None,n)`` is equivalent to ``expr*(0,n)``
+ - ``expr*(None, n)`` is equivalent to ``expr*(0, n)``
(read as "0 to n instances of ``expr``")
- - ``expr*(None,None)`` is equivalent to ``ZeroOrMore(expr)``
- - ``expr*(1,None)`` is equivalent to ``OneOrMore(expr)``
+ - ``expr*(None, None)`` is equivalent to ``ZeroOrMore(expr)``
+ - ``expr*(1, None)`` is equivalent to ``OneOrMore(expr)``
- Note that ``expr*(None,n)`` does not raise an exception if
+ Note that ``expr*(None, n)`` does not raise an exception if
more than n exprs exist in the input stream; that is,
- ``expr*(None,n)`` does not enforce a maximum number of expr
+ ``expr*(None, n)`` does not enforce a maximum number of expr
occurrences. If this behavior is desired, then write
- ``expr*(None,n) + ~expr``
+ ``expr*(None, n) + ~expr``
"""
- if isinstance(other,int):
- minElements, optElements = other,0
- elif isinstance(other,tuple):
+ if other is Ellipsis:
+ other = (0, None)
+ elif isinstance(other, tuple) and other[:1] == (Ellipsis,):
+ other = ((0, ) + other[1:] + (None,))[:2]
+
+ if isinstance(other, int):
+ minElements, optElements = other, 0
+ elif isinstance(other, tuple):
+ other = tuple(o if o is not Ellipsis else None for o in other)
other = (other + (None, None))[:2]
if other[0] is None:
other = (0, other[1])
- if isinstance(other[0],int) and other[1] is None:
+ if isinstance(other[0], int) and other[1] is None:
if other[0] == 0:
return ZeroOrMore(self)
if other[0] == 1:
return OneOrMore(self)
else:
- return self*other[0] + ZeroOrMore(self)
- elif isinstance(other[0],int) and isinstance(other[1],int):
+ return self * other[0] + ZeroOrMore(self)
+ elif isinstance(other[0], int) and isinstance(other[1], int):
minElements, optElements = other
optElements -= minElements
else:
- raise TypeError("cannot multiply 'ParserElement' and ('%s','%s') objects", type(other[0]),type(other[1]))
+ raise TypeError("cannot multiply 'ParserElement' and ('%s', '%s') objects", type(other[0]), type(other[1]))
else:
raise TypeError("cannot multiply 'ParserElement' and '%s' objects", type(other))
@@ -2107,108 +2264,152 @@ class ParserElement(object):
if optElements < 0:
raise ValueError("second tuple value must be greater or equal to first tuple value")
if minElements == optElements == 0:
- raise ValueError("cannot multiply ParserElement by 0 or (0,0)")
+ raise ValueError("cannot multiply ParserElement by 0 or (0, 0)")
- if (optElements):
+ if optElements:
def makeOptionalList(n):
- if n>1:
- return Optional(self + makeOptionalList(n-1))
+ if n > 1:
+ return Optional(self + makeOptionalList(n - 1))
else:
return Optional(self)
if minElements:
if minElements == 1:
ret = self + makeOptionalList(optElements)
else:
- ret = And([self]*minElements) + makeOptionalList(optElements)
+ ret = And([self] * minElements) + makeOptionalList(optElements)
else:
ret = makeOptionalList(optElements)
else:
if minElements == 1:
ret = self
else:
- ret = And([self]*minElements)
+ ret = And([self] * minElements)
return ret
def __rmul__(self, other):
return self.__mul__(other)
- def __or__(self, other ):
+ def __or__(self, other):
"""
Implementation of | operator - returns :class:`MatchFirst`
"""
- if isinstance( other, basestring ):
- other = ParserElement._literalStringClass( other )
- if not isinstance( other, ParserElement ):
- warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
- SyntaxWarning, stacklevel=2)
- return None
- return MatchFirst( [ self, other ] )
+ if other is Ellipsis:
+ return _PendingSkip(self, must_skip=True)
- def __ror__(self, other ):
+ if isinstance(other, basestring):
+ other = self._literalStringClass(other)
+ if not isinstance(other, ParserElement):
+ warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
+ SyntaxWarning, stacklevel=2)
+ return None
+ return MatchFirst([self, other])
+
+ def __ror__(self, other):
"""
Implementation of | operator when left operand is not a :class:`ParserElement`
"""
- if isinstance( other, basestring ):
- other = ParserElement._literalStringClass( other )
- if not isinstance( other, ParserElement ):
+ if isinstance(other, basestring):
+ other = self._literalStringClass(other)
+ if not isinstance(other, ParserElement):
warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
- SyntaxWarning, stacklevel=2)
+ SyntaxWarning, stacklevel=2)
return None
return other | self
- def __xor__(self, other ):
+ def __xor__(self, other):
"""
Implementation of ^ operator - returns :class:`Or`
"""
- if isinstance( other, basestring ):
- other = ParserElement._literalStringClass( other )
- if not isinstance( other, ParserElement ):
+ if isinstance(other, basestring):
+ other = self._literalStringClass(other)
+ if not isinstance(other, ParserElement):
warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
- SyntaxWarning, stacklevel=2)
+ SyntaxWarning, stacklevel=2)
return None
- return Or( [ self, other ] )
+ return Or([self, other])
- def __rxor__(self, other ):
+ def __rxor__(self, other):
"""
Implementation of ^ operator when left operand is not a :class:`ParserElement`
"""
- if isinstance( other, basestring ):
- other = ParserElement._literalStringClass( other )
- if not isinstance( other, ParserElement ):
+ if isinstance(other, basestring):
+ other = self._literalStringClass(other)
+ if not isinstance(other, ParserElement):
warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
- SyntaxWarning, stacklevel=2)
+ SyntaxWarning, stacklevel=2)
return None
return other ^ self
- def __and__(self, other ):
+ def __and__(self, other):
"""
Implementation of & operator - returns :class:`Each`
"""
- if isinstance( other, basestring ):
- other = ParserElement._literalStringClass( other )
- if not isinstance( other, ParserElement ):
+ if isinstance(other, basestring):
+ other = self._literalStringClass(other)
+ if not isinstance(other, ParserElement):
warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
- SyntaxWarning, stacklevel=2)
+ SyntaxWarning, stacklevel=2)
return None
- return Each( [ self, other ] )
+ return Each([self, other])
- def __rand__(self, other ):
+ def __rand__(self, other):
"""
Implementation of & operator when left operand is not a :class:`ParserElement`
"""
- if isinstance( other, basestring ):
- other = ParserElement._literalStringClass( other )
- if not isinstance( other, ParserElement ):
+ if isinstance(other, basestring):
+ other = self._literalStringClass(other)
+ if not isinstance(other, ParserElement):
warnings.warn("Cannot combine element of type %s with ParserElement" % type(other),
- SyntaxWarning, stacklevel=2)
+ SyntaxWarning, stacklevel=2)
return None
return other & self
- def __invert__( self ):
+ def __invert__(self):
"""
Implementation of ~ operator - returns :class:`NotAny`
"""
- return NotAny( self )
+ return NotAny(self)
+
+ def __iter__(self):
+ # must implement __iter__ to override legacy use of sequential access to __getitem__ to
+ # iterate over a sequence
+ raise TypeError('%r object is not iterable' % self.__class__.__name__)
+
+ def __getitem__(self, key):
+ """
+ use ``[]`` indexing notation as a short form for expression repetition:
+ - ``expr[n]`` is equivalent to ``expr*n``
+ - ``expr[m, n]`` is equivalent to ``expr*(m, n)``
+ - ``expr[n, ...]`` or ``expr[n,]`` is equivalent
+ to ``expr*n + ZeroOrMore(expr)``
+ (read as "at least n instances of ``expr``")
+ - ``expr[..., n]`` is equivalent to ``expr*(0, n)``
+ (read as "0 to n instances of ``expr``")
+ - ``expr[...]`` and ``expr[0, ...]`` are equivalent to ``ZeroOrMore(expr)``
+ - ``expr[1, ...]`` is equivalent to ``OneOrMore(expr)``
+ ``None`` may be used in place of ``...``.
+
+ Note that ``expr[..., n]`` and ``expr[m, n]``do not raise an exception
+ if more than ``n`` ``expr``s exist in the input stream. If this behavior is
+ desired, then write ``expr[..., n] + ~expr``.
+ """
+
+ # convert single arg keys to tuples
+ try:
+ if isinstance(key, str):
+ key = (key,)
+ iter(key)
+ except TypeError:
+ key = (key, key)
+
+ if len(key) > 2:
+ warnings.warn("only 1 or 2 index arguments supported ({0}{1})".format(key[:5],
+ '... [{0}]'.format(len(key))
+ if len(key) > 5 else ''))
+
+ # clip to 2 elements
+ ret = self * tuple(key[:2])
+ return ret
def __call__(self, name=None):
"""
@@ -2222,22 +2423,22 @@ class ParserElement(object):
Example::
# these are equivalent
- userdata = Word(alphas).setResultsName("name") + Word(nums+"-").setResultsName("socsecno")
- userdata = Word(alphas)("name") + Word(nums+"-")("socsecno")
+ userdata = Word(alphas).setResultsName("name") + Word(nums + "-").setResultsName("socsecno")
+ userdata = Word(alphas)("name") + Word(nums + "-")("socsecno")
"""
if name is not None:
- return self.setResultsName(name)
+ return self._setResultsName(name)
else:
return self.copy()
- def suppress( self ):
+ def suppress(self):
"""
Suppresses the output of this :class:`ParserElement`; useful to keep punctuation from
cluttering up returned output.
"""
- return Suppress( self )
+ return Suppress(self)
- def leaveWhitespace( self ):
+ def leaveWhitespace(self):
"""
Disables the skipping of whitespace before matching the characters in the
:class:`ParserElement`'s defined pattern. This is normally only used internally by
@@ -2246,7 +2447,7 @@ class ParserElement(object):
self.skipWhitespace = False
return self
- def setWhitespaceChars( self, chars ):
+ def setWhitespaceChars(self, chars):
"""
Overrides the default whitespace chars
"""
@@ -2255,7 +2456,7 @@ class ParserElement(object):
self.copyDefaultWhiteChars = False
return self
- def parseWithTabs( self ):
+ def parseWithTabs(self):
"""
Overrides default behavior to expand ````s to spaces before parsing the input string.
Must be called before ``parseString`` when the input grammar contains elements that
@@ -2264,7 +2465,7 @@ class ParserElement(object):
self.keepTabs = True
return self
- def ignore( self, other ):
+ def ignore(self, other):
"""
Define expression to be ignored (e.g., comments) while doing pattern
matching; may be called repeatedly, to define multiple comment or other
@@ -2281,14 +2482,14 @@ class ParserElement(object):
if isinstance(other, basestring):
other = Suppress(other)
- if isinstance( other, Suppress ):
+ if isinstance(other, Suppress):
if other not in self.ignoreExprs:
self.ignoreExprs.append(other)
else:
- self.ignoreExprs.append( Suppress( other.copy() ) )
+ self.ignoreExprs.append(Suppress(other.copy()))
return self
- def setDebugActions( self, startAction, successAction, exceptionAction ):
+ def setDebugActions(self, startAction, successAction, exceptionAction):
"""
Enable display of debugging messages while doing pattern matching.
"""
@@ -2298,7 +2499,7 @@ class ParserElement(object):
self.debug = True
return self
- def setDebug( self, flag=True ):
+ def setDebug(self, flag=True):
"""
Enable display of debugging messages while doing pattern matching.
Set ``flag`` to True to enable, False to disable.
@@ -2336,32 +2537,32 @@ class ParserElement(object):
name created for the :class:`Word` expression without calling ``setName`` is ``"W:(ABCD...)"``.
"""
if flag:
- self.setDebugActions( _defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction )
+ self.setDebugActions(_defaultStartDebugAction, _defaultSuccessDebugAction, _defaultExceptionDebugAction)
else:
self.debug = False
return self
- def __str__( self ):
+ def __str__(self):
return self.name
- def __repr__( self ):
+ def __repr__(self):
return _ustr(self)
- def streamline( self ):
+ def streamline(self):
self.streamlined = True
self.strRepr = None
return self
- def checkRecursion( self, parseElementList ):
+ def checkRecursion(self, parseElementList):
pass
- def validate( self, validateTrace=[] ):
+ def validate(self, validateTrace=None):
"""
Check defined expressions for valid structure, check for infinite recursive definitions.
"""
- self.checkRecursion( [] )
+ self.checkRecursion([])
- def parseFile( self, file_or_filename, parseAll=False ):
+ def parseFile(self, file_or_filename, parseAll=False):
"""
Execute the parse expression on the given file or filename.
If a filename is specified (instead of a file object),
@@ -2378,27 +2579,30 @@ class ParserElement(object):
if ParserElement.verbose_stacktrace:
raise
else:
- # catch and re-raise exception from here, clears out pyparsing internal stack trace
+ # catch and re-raise exception from here, clearing out pyparsing internal stack trace
+ if getattr(exc, '__traceback__', None) is not None:
+ exc.__traceback__ = self._trim_traceback(exc.__traceback__)
raise exc
- def __eq__(self,other):
- if isinstance(other, ParserElement):
- return self is other or vars(self) == vars(other)
+ def __eq__(self, other):
+ if self is other:
+ return True
elif isinstance(other, basestring):
return self.matches(other)
- else:
- return super(ParserElement,self)==other
+ elif isinstance(other, ParserElement):
+ return vars(self) == vars(other)
+ return False
- def __ne__(self,other):
+ def __ne__(self, other):
return not (self == other)
def __hash__(self):
- return hash(id(self))
+ return id(self)
- def __req__(self,other):
+ def __req__(self, other):
return self == other
- def __rne__(self,other):
+ def __rne__(self, other):
return not (self == other)
def matches(self, testString, parseAll=True):
@@ -2422,7 +2626,8 @@ class ParserElement(object):
return False
def runTests(self, tests, parseAll=True, comment='#',
- fullDump=True, printResults=True, failureTests=False, postParse=None):
+ fullDump=True, printResults=True, failureTests=False, postParse=None,
+ file=None):
"""
Execute the parse expression on a series of test strings, showing each
test, the parsed results or where the parse failed. Quick and easy way to
@@ -2439,6 +2644,8 @@ class ParserElement(object):
- failureTests - (default= ``False``) indicates if these tests are expected to fail parsing
- postParse - (default= ``None``) optional callback for successful parse results; called as
`fn(test_string, parse_results)` and returns a string to be added to the test output
+ - file - (default=``None``) optional file-like object to which test output will be written;
+ if None, will default to ``sys.stdout``
Returns: a (success, results) tuple, where success indicates that all tests succeeded
(or failed if ``failureTests`` is True), and the results contain a list of lines of each
@@ -2518,39 +2725,34 @@ class ParserElement(object):
tests = list(map(str.strip, tests.rstrip().splitlines()))
if isinstance(comment, basestring):
comment = Literal(comment)
+ if file is None:
+ file = sys.stdout
+ print_ = file.write
+
allResults = []
comments = []
success = True
+ NL = Literal(r'\n').addParseAction(replaceWith('\n')).ignore(quotedString)
+ BOM = u'\ufeff'
for t in tests:
if comment is not None and comment.matches(t, False) or comments and not t:
comments.append(t)
continue
if not t:
continue
- out = ['\n'.join(comments), t]
+ out = ['\n' + '\n'.join(comments) if comments else '', t]
comments = []
try:
# convert newline marks to actual newlines, and strip leading BOM if present
- NL = Literal(r'\n').addParseAction(replaceWith('\n')).ignore(quotedString)
- BOM = '\ufeff'
t = NL.transformString(t.lstrip(BOM))
result = self.parseString(t, parseAll=parseAll)
- out.append(result.dump(full=fullDump))
- success = success and not failureTests
- if postParse is not None:
- try:
- pp_value = postParse(t, result)
- if pp_value is not None:
- out.append(str(pp_value))
- except Exception as e:
- out.append("{0} failed: {1}: {2}".format(postParse.__name__, type(e).__name__, e))
except ParseBaseException as pe:
fatal = "(FATAL)" if isinstance(pe, ParseFatalException) else ""
if '\n' in t:
out.append(line(pe.loc, t))
- out.append(' '*(col(pe.loc,t)-1) + '^' + fatal)
+ out.append(' ' * (col(pe.loc, t) - 1) + '^' + fatal)
else:
- out.append(' '*pe.loc + '^' + fatal)
+ out.append(' ' * pe.loc + '^' + fatal)
out.append("FAIL: " + str(pe))
success = success and failureTests
result = pe
@@ -2558,30 +2760,80 @@ class ParserElement(object):
out.append("FAIL-EXCEPTION: " + str(exc))
success = success and failureTests
result = exc
+ else:
+ success = success and not failureTests
+ if postParse is not None:
+ try:
+ pp_value = postParse(t, result)
+ if pp_value is not None:
+ if isinstance(pp_value, ParseResults):
+ out.append(pp_value.dump())
+ else:
+ out.append(str(pp_value))
+ else:
+ out.append(result.dump())
+ except Exception as e:
+ out.append(result.dump(full=fullDump))
+ out.append("{0} failed: {1}: {2}".format(postParse.__name__, type(e).__name__, e))
+ else:
+ out.append(result.dump(full=fullDump))
if printResults:
if fullDump:
out.append('')
- print('\n'.join(out))
+ print_('\n'.join(out))
allResults.append((t, result))
return success, allResults
+class _PendingSkip(ParserElement):
+ # internal placeholder class to hold a place were '...' is added to a parser element,
+ # once another ParserElement is added, this placeholder will be replaced with a SkipTo
+ def __init__(self, expr, must_skip=False):
+ super(_PendingSkip, self).__init__()
+ self.strRepr = str(expr + Empty()).replace('Empty', '...')
+ self.name = self.strRepr
+ self.anchor = expr
+ self.must_skip = must_skip
+
+ def __add__(self, other):
+ skipper = SkipTo(other).setName("...")("_skipped*")
+ if self.must_skip:
+ def must_skip(t):
+ if not t._skipped or t._skipped.asList() == ['']:
+ del t[0]
+ t.pop("_skipped", None)
+ def show_skip(t):
+ if t._skipped.asList()[-1:] == ['']:
+ skipped = t.pop('_skipped')
+ t['_skipped'] = 'missing <' + repr(self.anchor) + '>'
+ return (self.anchor + skipper().addParseAction(must_skip)
+ | skipper().addParseAction(show_skip)) + other
+
+ return self.anchor + skipper + other
+
+ def __repr__(self):
+ return self.strRepr
+
+ def parseImpl(self, *args):
+ raise Exception("use of `...` expression without following SkipTo target expression")
+
+
class Token(ParserElement):
"""Abstract :class:`ParserElement` subclass, for defining atomic
matching patterns.
"""
- def __init__( self ):
- super(Token,self).__init__( savelist=False )
+ def __init__(self):
+ super(Token, self).__init__(savelist=False)
class Empty(Token):
"""An empty token, will always match.
"""
- def __init__( self ):
- super(Empty,self).__init__()
+ def __init__(self):
+ super(Empty, self).__init__()
self.name = "Empty"
self.mayReturnEmpty = True
self.mayIndexError = False
@@ -2590,14 +2842,14 @@ class Empty(Token):
class NoMatch(Token):
"""A token that will never match.
"""
- def __init__( self ):
- super(NoMatch,self).__init__()
+ def __init__(self):
+ super(NoMatch, self).__init__()
self.name = "NoMatch"
self.mayReturnEmpty = True
self.mayIndexError = False
self.errmsg = "Unmatchable token"
- def parseImpl( self, instring, loc, doActions=True ):
+ def parseImpl(self, instring, loc, doActions=True):
raise ParseException(instring, loc, self.errmsg, self)
@@ -2615,8 +2867,8 @@ class Literal(Token):
For keyword matching (force word break before and after the matched string),
use :class:`Keyword` or :class:`CaselessKeyword`.
"""
- def __init__( self, matchString ):
- super(Literal,self).__init__()
+ def __init__(self, matchString):
+ super(Literal, self).__init__()
self.match = matchString
self.matchLen = len(matchString)
try:
@@ -2630,15 +2882,22 @@ class Literal(Token):
self.mayReturnEmpty = False
self.mayIndexError = False
- # Performance tuning: this routine gets called a *lot*
- # if this is a single character match string and the first character matches,
- # short-circuit as quickly as possible, and avoid calling startswith
- #~ @profile
- def parseImpl( self, instring, loc, doActions=True ):
- if (instring[loc] == self.firstMatchChar and
- (self.matchLen==1 or instring.startswith(self.match,loc)) ):
- return loc+self.matchLen, self.match
+ # Performance tuning: modify __class__ to select
+ # a parseImpl optimized for single-character check
+ if self.matchLen == 1 and type(self) is Literal:
+ self.__class__ = _SingleCharLiteral
+
+ def parseImpl(self, instring, loc, doActions=True):
+ if instring[loc] == self.firstMatchChar and instring.startswith(self.match, loc):
+ return loc + self.matchLen, self.match
raise ParseException(instring, loc, self.errmsg, self)
+
+class _SingleCharLiteral(Literal):
+ def parseImpl(self, instring, loc, doActions=True):
+ if instring[loc] == self.firstMatchChar:
+ return loc + 1, self.match
+ raise ParseException(instring, loc, self.errmsg, self)
+
_L = Literal
ParserElement._literalStringClass = Literal
@@ -2667,10 +2926,10 @@ class Keyword(Token):
For case-insensitive matching, use :class:`CaselessKeyword`.
"""
- DEFAULT_KEYWORD_CHARS = alphanums+"_$"
+ DEFAULT_KEYWORD_CHARS = alphanums + "_$"
- def __init__( self, matchString, identChars=None, caseless=False ):
- super(Keyword,self).__init__()
+ def __init__(self, matchString, identChars=None, caseless=False):
+ super(Keyword, self).__init__()
if identChars is None:
identChars = Keyword.DEFAULT_KEYWORD_CHARS
self.match = matchString
@@ -2679,7 +2938,7 @@ class Keyword(Token):
self.firstMatchChar = matchString[0]
except IndexError:
warnings.warn("null string passed to Keyword; use Empty() instead",
- SyntaxWarning, stacklevel=2)
+ SyntaxWarning, stacklevel=2)
self.name = '"%s"' % self.match
self.errmsg = "Expected " + self.name
self.mayReturnEmpty = False
@@ -2690,27 +2949,32 @@ class Keyword(Token):
identChars = identChars.upper()
self.identChars = set(identChars)
- def parseImpl( self, instring, loc, doActions=True ):
+ def parseImpl(self, instring, loc, doActions=True):
if self.caseless:
- if ( (instring[ loc:loc+self.matchLen ].upper() == self.caselessmatch) and
- (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen].upper() not in self.identChars) and
- (loc == 0 or instring[loc-1].upper() not in self.identChars) ):
- return loc+self.matchLen, self.match
+ if ((instring[loc:loc + self.matchLen].upper() == self.caselessmatch)
+ and (loc >= len(instring) - self.matchLen
+ or instring[loc + self.matchLen].upper() not in self.identChars)
+ and (loc == 0
+ or instring[loc - 1].upper() not in self.identChars)):
+ return loc + self.matchLen, self.match
+
else:
- if (instring[loc] == self.firstMatchChar and
- (self.matchLen==1 or instring.startswith(self.match,loc)) and
- (loc >= len(instring)-self.matchLen or instring[loc+self.matchLen] not in self.identChars) and
- (loc == 0 or instring[loc-1] not in self.identChars) ):
- return loc+self.matchLen, self.match
+ if instring[loc] == self.firstMatchChar:
+ if ((self.matchLen == 1 or instring.startswith(self.match, loc))
+ and (loc >= len(instring) - self.matchLen
+ or instring[loc + self.matchLen] not in self.identChars)
+ and (loc == 0 or instring[loc - 1] not in self.identChars)):
+ return loc + self.matchLen, self.match
+
raise ParseException(instring, loc, self.errmsg, self)
def copy(self):
- c = super(Keyword,self).copy()
+ c = super(Keyword, self).copy()
c.identChars = Keyword.DEFAULT_KEYWORD_CHARS
return c
@staticmethod
- def setDefaultKeywordChars( chars ):
+ def setDefaultKeywordChars(chars):
"""Overrides the default Keyword chars
"""
Keyword.DEFAULT_KEYWORD_CHARS = chars
@@ -2726,16 +2990,16 @@ class CaselessLiteral(Literal):
(Contrast with example for :class:`CaselessKeyword`.)
"""
- def __init__( self, matchString ):
- super(CaselessLiteral,self).__init__( matchString.upper() )
+ def __init__(self, matchString):
+ super(CaselessLiteral, self).__init__(matchString.upper())
# Preserve the defining literal.
self.returnString = matchString
self.name = "'%s'" % self.returnString
self.errmsg = "Expected " + self.name
- def parseImpl( self, instring, loc, doActions=True ):
- if instring[ loc:loc+self.matchLen ].upper() == self.match:
- return loc+self.matchLen, self.returnString
+ def parseImpl(self, instring, loc, doActions=True):
+ if instring[loc:loc + self.matchLen].upper() == self.match:
+ return loc + self.matchLen, self.returnString
raise ParseException(instring, loc, self.errmsg, self)
class CaselessKeyword(Keyword):
@@ -2748,8 +3012,8 @@ class CaselessKeyword(Keyword):
(Contrast with example for :class:`CaselessLiteral`.)
"""
- def __init__( self, matchString, identChars=None ):
- super(CaselessKeyword,self).__init__( matchString, identChars, caseless=True )
+ def __init__(self, matchString, identChars=None):
+ super(CaselessKeyword, self).__init__(matchString, identChars, caseless=True)
class CloseMatch(Token):
"""A variation on :class:`Literal` which matches "close" matches,
@@ -2785,7 +3049,7 @@ class CloseMatch(Token):
patt.parseString("ATCAXCGAAXGGA") # -> (['ATCAXCGAAXGGA'], {'mismatches': [[4, 9]], 'original': ['ATCATCGAATGGA']})
"""
def __init__(self, match_string, maxMismatches=1):
- super(CloseMatch,self).__init__()
+ super(CloseMatch, self).__init__()
self.name = match_string
self.match_string = match_string
self.maxMismatches = maxMismatches
@@ -2793,7 +3057,7 @@ class CloseMatch(Token):
self.mayIndexError = False
self.mayReturnEmpty = False
- def parseImpl( self, instring, loc, doActions=True ):
+ def parseImpl(self, instring, loc, doActions=True):
start = loc
instrlen = len(instring)
maxloc = start + len(self.match_string)
@@ -2804,8 +3068,8 @@ class CloseMatch(Token):
mismatches = []
maxMismatches = self.maxMismatches
- for match_stringloc,s_m in enumerate(zip(instring[loc:maxloc], self.match_string)):
- src,mat = s_m
+ for match_stringloc, s_m in enumerate(zip(instring[loc:maxloc], match_string)):
+ src, mat = s_m
if src != mat:
mismatches.append(match_stringloc)
if len(mismatches) > maxMismatches:
@@ -2813,7 +3077,7 @@ class CloseMatch(Token):
else:
loc = match_stringloc + 1
results = ParseResults([instring[start:loc]])
- results['original'] = self.match_string
+ results['original'] = match_string
results['mismatches'] = mismatches
return loc, results
@@ -2865,7 +3129,7 @@ class Word(Token):
capital_word = Word(alphas.upper(), alphas.lower())
# hostnames are alphanumeric, with leading alpha, and '-'
- hostname = Word(alphas, alphanums+'-')
+ hostname = Word(alphas, alphanums + '-')
# roman numeral (not a strict parser, accepts invalid mix of characters)
roman = Word("IVXLCDM")
@@ -2873,8 +3137,8 @@ class Word(Token):
# any string of non-whitespace characters, except for ','
csv_value = Word(printables, excludeChars=",")
"""
- def __init__( self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False, excludeChars=None ):
- super(Word,self).__init__()
+ def __init__(self, initChars, bodyChars=None, min=1, max=0, exact=0, asKeyword=False, excludeChars=None):
+ super(Word, self).__init__()
if excludeChars:
excludeChars = set(excludeChars)
initChars = ''.join(c for c in initChars if c not in excludeChars)
@@ -2882,7 +3146,7 @@ class Word(Token):
bodyChars = ''.join(c for c in bodyChars if c not in excludeChars)
self.initCharsOrig = initChars
self.initChars = set(initChars)
- if bodyChars :
+ if bodyChars:
self.bodyCharsOrig = bodyChars
self.bodyChars = set(bodyChars)
else:
@@ -2910,33 +3174,27 @@ class Word(Token):
self.mayIndexError = False
self.asKeyword = asKeyword
- if ' ' not in self.initCharsOrig+self.bodyCharsOrig and (min==1 and max==0 and exact==0):
+ if ' ' not in self.initCharsOrig + self.bodyCharsOrig and (min == 1 and max == 0 and exact == 0):
if self.bodyCharsOrig == self.initCharsOrig:
self.reString = "[%s]+" % _escapeRegexRangeChars(self.initCharsOrig)
elif len(self.initCharsOrig) == 1:
- self.reString = "%s[%s]*" % \
- (re.escape(self.initCharsOrig),
- _escapeRegexRangeChars(self.bodyCharsOrig),)
+ self.reString = "%s[%s]*" % (re.escape(self.initCharsOrig),
+ _escapeRegexRangeChars(self.bodyCharsOrig),)
else:
- self.reString = "[%s][%s]*" % \
- (_escapeRegexRangeChars(self.initCharsOrig),
- _escapeRegexRangeChars(self.bodyCharsOrig),)
+ self.reString = "[%s][%s]*" % (_escapeRegexRangeChars(self.initCharsOrig),
+ _escapeRegexRangeChars(self.bodyCharsOrig),)
if self.asKeyword:
- self.reString = r"\b"+self.reString+r"\b"
+ self.reString = r"\b" + self.reString + r"\b"
+
try:
- self.re = re.compile( self.reString )
+ self.re = re.compile(self.reString)
except Exception:
self.re = None
+ else:
+ self.re_match = self.re.match
+ self.__class__ = _WordRegex
- def parseImpl( self, instring, loc, doActions=True ):
- if self.re:
- result = self.re.match(instring,loc)
- if not result:
- raise ParseException(instring, loc, self.errmsg, self)
-
- loc = result.end()
- return loc, result.group()
-
+ def parseImpl(self, instring, loc, doActions=True):
if instring[loc] not in self.initChars:
raise ParseException(instring, loc, self.errmsg, self)
@@ -2945,7 +3203,7 @@ class Word(Token):
instrlen = len(instring)
bodychars = self.bodyChars
maxloc = start + self.maxLen
- maxloc = min( maxloc, instrlen )
+ maxloc = min(maxloc, instrlen)
while loc < maxloc and instring[loc] in bodychars:
loc += 1
@@ -2955,7 +3213,8 @@ class Word(Token):
elif self.maxSpecified and loc < instrlen and instring[loc] in bodychars:
throwException = True
elif self.asKeyword:
- if (start>0 and instring[start-1] in bodychars) or (loc 0 and instring[start - 1] in bodychars
+ or loc < instrlen and instring[loc] in bodychars):
throwException = True
if throwException:
@@ -2963,38 +3222,49 @@ class Word(Token):
return loc, instring[start:loc]
- def __str__( self ):
+ def __str__(self):
try:
- return super(Word,self).__str__()
+ return super(Word, self).__str__()
except Exception:
pass
-
if self.strRepr is None:
def charsAsStr(s):
- if len(s)>4:
- return s[:4]+"..."
+ if len(s) > 4:
+ return s[:4] + "..."
else:
return s
- if ( self.initCharsOrig != self.bodyCharsOrig ):
- self.strRepr = "W:(%s,%s)" % ( charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig) )
+ if self.initCharsOrig != self.bodyCharsOrig:
+ self.strRepr = "W:(%s, %s)" % (charsAsStr(self.initCharsOrig), charsAsStr(self.bodyCharsOrig))
else:
self.strRepr = "W:(%s)" % charsAsStr(self.initCharsOrig)
return self.strRepr
+class _WordRegex(Word):
+ def parseImpl(self, instring, loc, doActions=True):
+ result = self.re_match(instring, loc)
+ if not result:
+ raise ParseException(instring, loc, self.errmsg, self)
-class Char(Word):
+ loc = result.end()
+ return loc, result.group()
+
+
+class Char(_WordRegex):
"""A short-cut class for defining ``Word(characters, exact=1)``,
when defining a match of any single character in a string of
characters.
"""
def __init__(self, charset, asKeyword=False, excludeChars=None):
super(Char, self).__init__(charset, exact=1, asKeyword=asKeyword, excludeChars=excludeChars)
- self.reString = "[%s]" % _escapeRegexRangeChars(self.initCharsOrig)
- self.re = re.compile( self.reString )
+ self.reString = "[%s]" % _escapeRegexRangeChars(''.join(self.initChars))
+ if asKeyword:
+ self.reString = r"\b%s\b" % self.reString
+ self.re = re.compile(self.reString)
+ self.re_match = self.re.match
class Regex(Token):
@@ -3004,26 +3274,35 @@ class Regex(Token):
If the given regex contains named groups (defined using ``(?P...)``),
these will be preserved as named parse results.
+ If instead of the Python stdlib re module you wish to use a different RE module
+ (such as the `regex` module), you can replace it by either building your
+ Regex object with a compiled RE that was compiled using regex:
+
Example::
realnum = Regex(r"[+-]?\d+\.\d*")
date = Regex(r'(?P\d{4})-(?P\d\d?)-(?P\d\d?)')
# ref: https://stackoverflow.com/questions/267399/how-do-you-match-only-valid-roman-numerals-with-a-regular-expression
roman = Regex(r"M{0,4}(CM|CD|D?{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})")
+
+ # use regex module instead of stdlib re module to construct a Regex using
+ # a compiled regular expression
+ import regex
+ parser = pp.Regex(regex.compile(r'[0-9]'))
+
"""
- compiledREtype = type(re.compile("[A-Z]"))
- def __init__( self, pattern, flags=0, asGroupList=False, asMatch=False):
+ def __init__(self, pattern, flags=0, asGroupList=False, asMatch=False):
"""The parameters ``pattern`` and ``flags`` are passed
to the ``re.compile()`` function as-is. See the Python
`re module `_ module for an
explanation of the acceptable patterns and flags.
"""
- super(Regex,self).__init__()
+ super(Regex, self).__init__()
if isinstance(pattern, basestring):
if not pattern:
warnings.warn("null string passed to Regex; use Empty() instead",
- SyntaxWarning, stacklevel=2)
+ SyntaxWarning, stacklevel=2)
self.pattern = pattern
self.flags = flags
@@ -3033,22 +3312,23 @@ class Regex(Token):
self.reString = self.pattern
except sre_constants.error:
warnings.warn("invalid pattern (%s) passed to Regex" % pattern,
- SyntaxWarning, stacklevel=2)
+ SyntaxWarning, stacklevel=2)
raise
- elif isinstance(pattern, Regex.compiledREtype):
+ elif hasattr(pattern, 'pattern') and hasattr(pattern, 'match'):
self.re = pattern
- self.pattern = \
- self.reString = str(pattern)
+ self.pattern = self.reString = pattern.pattern
self.flags = flags
else:
- raise ValueError("Regex may only be constructed with a string or a compiled RE object")
+ raise TypeError("Regex may only be constructed with a string or a compiled RE object")
+
+ self.re_match = self.re.match
self.name = _ustr(self)
self.errmsg = "Expected " + self.name
self.mayIndexError = False
- self.mayReturnEmpty = True
+ self.mayReturnEmpty = self.re_match("") is not None
self.asGroupList = asGroupList
self.asMatch = asMatch
if self.asGroupList:
@@ -3057,7 +3337,7 @@ class Regex(Token):
self.parseImpl = self.parseImplAsMatch
def parseImpl(self, instring, loc, doActions=True):
- result = self.re.match(instring,loc)
+ result = self.re_match(instring, loc)
if not result:
raise ParseException(instring, loc, self.errmsg, self)
@@ -3070,7 +3350,7 @@ class Regex(Token):
return loc, ret
def parseImplAsGroupList(self, instring, loc, doActions=True):
- result = self.re.match(instring,loc)
+ result = self.re_match(instring, loc)
if not result:
raise ParseException(instring, loc, self.errmsg, self)
@@ -3079,7 +3359,7 @@ class Regex(Token):
return loc, ret
def parseImplAsMatch(self, instring, loc, doActions=True):
- result = self.re.match(instring,loc)
+ result = self.re_match(instring, loc)
if not result:
raise ParseException(instring, loc, self.errmsg, self)
@@ -3087,9 +3367,9 @@ class Regex(Token):
ret = result
return loc, ret
- def __str__( self ):
+ def __str__(self):
try:
- return super(Regex,self).__str__()
+ return super(Regex, self).__str__()
except Exception:
pass
@@ -3111,12 +3391,12 @@ class Regex(Token):
"""
if self.asGroupList:
warnings.warn("cannot use sub() with Regex(asGroupList=True)",
- SyntaxWarning, stacklevel=2)
+ SyntaxWarning, stacklevel=2)
raise SyntaxError()
if self.asMatch and callable(repl):
warnings.warn("cannot use sub() with a callable with Regex(asMatch=True)",
- SyntaxWarning, stacklevel=2)
+ SyntaxWarning, stacklevel=2)
raise SyntaxError()
if self.asMatch:
@@ -3136,20 +3416,20 @@ class QuotedString(Token):
- quoteChar - string of one or more characters defining the
quote delimiting string
- escChar - character to escape quotes, typically backslash
- (default= ``None`` )
+ (default= ``None``)
- escQuote - special quote sequence to escape an embedded quote
string (such as SQL's ``""`` to escape an embedded ``"``)
- (default= ``None`` )
+ (default= ``None``)
- multiline - boolean indicating whether quotes can span
- multiple lines (default= ``False`` )
+ multiple lines (default= ``False``)
- unquoteResults - boolean indicating whether the matched text
- should be unquoted (default= ``True`` )
+ should be unquoted (default= ``True``)
- endQuoteChar - string of one or more characters defining the
end of the quote delimited string (default= ``None`` => same as
quoteChar)
- convertWhitespaceEscapes - convert escaped whitespace
(``'\t'``, ``'\n'``, etc.) to actual whitespace
- (default= ``True`` )
+ (default= ``True``)
Example::
@@ -3166,13 +3446,14 @@ class QuotedString(Token):
[['This is the "quote"']]
[['This is the quote with "embedded" quotes']]
"""
- def __init__( self, quoteChar, escChar=None, escQuote=None, multiline=False, unquoteResults=True, endQuoteChar=None, convertWhitespaceEscapes=True):
- super(QuotedString,self).__init__()
+ def __init__(self, quoteChar, escChar=None, escQuote=None, multiline=False,
+ unquoteResults=True, endQuoteChar=None, convertWhitespaceEscapes=True):
+ super(QuotedString, self).__init__()
# remove white space from quote chars - wont work anyway
quoteChar = quoteChar.strip()
if not quoteChar:
- warnings.warn("quoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
+ warnings.warn("quoteChar cannot be the empty string", SyntaxWarning, stacklevel=2)
raise SyntaxError()
if endQuoteChar is None:
@@ -3180,7 +3461,7 @@ class QuotedString(Token):
else:
endQuoteChar = endQuoteChar.strip()
if not endQuoteChar:
- warnings.warn("endQuoteChar cannot be the empty string",SyntaxWarning,stacklevel=2)
+ warnings.warn("endQuoteChar cannot be the empty string", SyntaxWarning, stacklevel=2)
raise SyntaxError()
self.quoteChar = quoteChar
@@ -3195,35 +3476,34 @@ class QuotedString(Token):
if multiline:
self.flags = re.MULTILINE | re.DOTALL
- self.pattern = r'%s(?:[^%s%s]' % \
- ( re.escape(self.quoteChar),
- _escapeRegexRangeChars(self.endQuoteChar[0]),
- (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
+ self.pattern = r'%s(?:[^%s%s]' % (re.escape(self.quoteChar),
+ _escapeRegexRangeChars(self.endQuoteChar[0]),
+ (escChar is not None and _escapeRegexRangeChars(escChar) or ''))
else:
self.flags = 0
- self.pattern = r'%s(?:[^%s\n\r%s]' % \
- ( re.escape(self.quoteChar),
- _escapeRegexRangeChars(self.endQuoteChar[0]),
- (escChar is not None and _escapeRegexRangeChars(escChar) or '') )
+ self.pattern = r'%s(?:[^%s\n\r%s]' % (re.escape(self.quoteChar),
+ _escapeRegexRangeChars(self.endQuoteChar[0]),
+ (escChar is not None and _escapeRegexRangeChars(escChar) or ''))
if len(self.endQuoteChar) > 1:
self.pattern += (
'|(?:' + ')|(?:'.join("%s[^%s]" % (re.escape(self.endQuoteChar[:i]),
- _escapeRegexRangeChars(self.endQuoteChar[i]))
- for i in range(len(self.endQuoteChar)-1,0,-1)) + ')'
- )
+ _escapeRegexRangeChars(self.endQuoteChar[i]))
+ for i in range(len(self.endQuoteChar) - 1, 0, -1)) + ')')
+
if escQuote:
self.pattern += (r'|(?:%s)' % re.escape(escQuote))
if escChar:
self.pattern += (r'|(?:%s.)' % re.escape(escChar))
- self.escCharReplacePattern = re.escape(self.escChar)+"(.)"
+ self.escCharReplacePattern = re.escape(self.escChar) + "(.)"
self.pattern += (r')*%s' % re.escape(self.endQuoteChar))
try:
self.re = re.compile(self.pattern, self.flags)
self.reString = self.pattern
+ self.re_match = self.re.match
except sre_constants.error:
warnings.warn("invalid pattern (%s) passed to Regex" % self.pattern,
- SyntaxWarning, stacklevel=2)
+ SyntaxWarning, stacklevel=2)
raise
self.name = _ustr(self)
@@ -3231,8 +3511,8 @@ class QuotedString(Token):
self.mayIndexError = False
self.mayReturnEmpty = True
- def parseImpl( self, instring, loc, doActions=True ):
- result = instring[loc] == self.firstQuoteChar and self.re.match(instring,loc) or None
+ def parseImpl(self, instring, loc, doActions=True):
+ result = instring[loc] == self.firstQuoteChar and self.re_match(instring, loc) or None
if not result:
raise ParseException(instring, loc, self.errmsg, self)
@@ -3242,18 +3522,18 @@ class QuotedString(Token):
if self.unquoteResults:
# strip off quotes
- ret = ret[self.quoteCharLen:-self.endQuoteCharLen]
+ ret = ret[self.quoteCharLen: -self.endQuoteCharLen]
- if isinstance(ret,basestring):
+ if isinstance(ret, basestring):
# replace escaped whitespace
if '\\' in ret and self.convertWhitespaceEscapes:
ws_map = {
- r'\t' : '\t',
- r'\n' : '\n',
- r'\f' : '\f',
- r'\r' : '\r',
+ r'\t': '\t',
+ r'\n': '\n',
+ r'\f': '\f',
+ r'\r': '\r',
}
- for wslit,wschar in ws_map.items():
+ for wslit, wschar in ws_map.items():
ret = ret.replace(wslit, wschar)
# replace escaped characters
@@ -3266,9 +3546,9 @@ class QuotedString(Token):
return loc, ret
- def __str__( self ):
+ def __str__(self):
try:
- return super(QuotedString,self).__str__()
+ return super(QuotedString, self).__str__()
except Exception:
pass
@@ -3298,15 +3578,14 @@ class CharsNotIn(Token):
['dkls', 'lsdkjf', 's12 34', '@!#', '213']
"""
- def __init__( self, notChars, min=1, max=0, exact=0 ):
- super(CharsNotIn,self).__init__()
+ def __init__(self, notChars, min=1, max=0, exact=0):
+ super(CharsNotIn, self).__init__()
self.skipWhitespace = False
self.notChars = notChars
if min < 1:
- raise ValueError(
- "cannot specify a minimum length < 1; use " +
- "Optional(CharsNotIn()) if zero-length char group is permitted")
+ raise ValueError("cannot specify a minimum length < 1; use "
+ "Optional(CharsNotIn()) if zero-length char group is permitted")
self.minLen = min
@@ -3321,19 +3600,18 @@ class CharsNotIn(Token):
self.name = _ustr(self)
self.errmsg = "Expected " + self.name
- self.mayReturnEmpty = ( self.minLen == 0 )
+ self.mayReturnEmpty = (self.minLen == 0)
self.mayIndexError = False
- def parseImpl( self, instring, loc, doActions=True ):
+ def parseImpl(self, instring, loc, doActions=True):
if instring[loc] in self.notChars:
raise ParseException(instring, loc, self.errmsg, self)
start = loc
loc += 1
notchars = self.notChars
- maxlen = min( start+self.maxLen, len(instring) )
- while loc < maxlen and \
- (instring[loc] not in notchars):
+ maxlen = min(start + self.maxLen, len(instring))
+ while loc < maxlen and instring[loc] not in notchars:
loc += 1
if loc - start < self.minLen:
@@ -3341,7 +3619,7 @@ class CharsNotIn(Token):
return loc, instring[start:loc]
- def __str__( self ):
+ def __str__(self):
try:
return super(CharsNotIn, self).__str__()
except Exception:
@@ -3370,30 +3648,30 @@ class White(Token):
'\n': '',
'\r': '',
'\f': '',
- 'u\00A0': '',
- 'u\1680': '',
- 'u\180E': '',
- 'u\2000': '',
- 'u\2001': '',
- 'u\2002': '',
- 'u\2003': '',
- 'u\2004': '',
- 'u\2005': '',
- 'u\2006': '',
- 'u\2007': '',
- 'u\2008': '',
- 'u\2009': '',
- 'u\200A': '',
- 'u\200B': '',
- 'u\202F': '',
- 'u\205F': '',
- 'u\3000': '',
+ u'\u00A0': '',
+ u'\u1680': '',
+ u'\u180E': '',
+ u'\u2000': '',
+ u'\u2001': '',
+ u'\u2002': '',
+ u'\u2003': '',
+ u'\u2004': '',
+ u'\u2005': '',
+ u'\u2006': '',
+ u'\u2007': '',
+ u'\u2008': '',
+ u'\u2009': '',
+ u'\u200A': '',
+ u'\u200B': '',
+ u'\u202F': '',
+ u'\u205F': '',
+ u'\u3000': '',
}
def __init__(self, ws=" \t\r\n", min=1, max=0, exact=0):
- super(White,self).__init__()
+ super(White, self).__init__()
self.matchWhite = ws
- self.setWhitespaceChars( "".join(c for c in self.whiteChars if c not in self.matchWhite) )
- #~ self.leaveWhitespace()
+ self.setWhitespaceChars("".join(c for c in self.whiteChars if c not in self.matchWhite))
+ # ~ self.leaveWhitespace()
self.name = ("".join(White.whiteStrs[c] for c in self.matchWhite))
self.mayReturnEmpty = True
self.errmsg = "Expected " + self.name
@@ -3409,13 +3687,13 @@ class White(Token):
self.maxLen = exact
self.minLen = exact
- def parseImpl( self, instring, loc, doActions=True ):
+ def parseImpl(self, instring, loc, doActions=True):
if instring[loc] not in self.matchWhite:
raise ParseException(instring, loc, self.errmsg, self)
start = loc
loc += 1
maxloc = start + self.maxLen
- maxloc = min( maxloc, len(instring) )
+ maxloc = min(maxloc, len(instring))
while loc < maxloc and instring[loc] in self.matchWhite:
loc += 1
@@ -3426,9 +3704,9 @@ class White(Token):
class _PositionToken(Token):
- def __init__( self ):
- super(_PositionToken,self).__init__()
- self.name=self.__class__.__name__
+ def __init__(self):
+ super(_PositionToken, self).__init__()
+ self.name = self.__class__.__name__
self.mayReturnEmpty = True
self.mayIndexError = False
@@ -3436,25 +3714,25 @@ class GoToColumn(_PositionToken):
"""Token to advance to a specific column of input text; useful for
tabular report scraping.
"""
- def __init__( self, colno ):
- super(GoToColumn,self).__init__()
+ def __init__(self, colno):
+ super(GoToColumn, self).__init__()
self.col = colno
- def preParse( self, instring, loc ):
- if col(loc,instring) != self.col:
+ def preParse(self, instring, loc):
+ if col(loc, instring) != self.col:
instrlen = len(instring)
if self.ignoreExprs:
- loc = self._skipIgnorables( instring, loc )
- while loc < instrlen and instring[loc].isspace() and col( loc, instring ) != self.col :
+ loc = self._skipIgnorables(instring, loc)
+ while loc < instrlen and instring[loc].isspace() and col(loc, instring) != self.col:
loc += 1
return loc
- def parseImpl( self, instring, loc, doActions=True ):
- thiscol = col( loc, instring )
+ def parseImpl(self, instring, loc, doActions=True):
+ thiscol = col(loc, instring)
if thiscol > self.col:
- raise ParseException( instring, loc, "Text not in expected column", self )
+ raise ParseException(instring, loc, "Text not in expected column", self)
newloc = loc + self.col - thiscol
- ret = instring[ loc: newloc ]
+ ret = instring[loc: newloc]
return newloc, ret
@@ -3480,11 +3758,11 @@ class LineStart(_PositionToken):
['AAA', ' and this line']
"""
- def __init__( self ):
- super(LineStart,self).__init__()
+ def __init__(self):
+ super(LineStart, self).__init__()
self.errmsg = "Expected start of line"
- def parseImpl( self, instring, loc, doActions=True ):
+ def parseImpl(self, instring, loc, doActions=True):
if col(loc, instring) == 1:
return loc, []
raise ParseException(instring, loc, self.errmsg, self)
@@ -3493,19 +3771,19 @@ class LineEnd(_PositionToken):
"""Matches if current position is at the end of a line within the
parse string
"""
- def __init__( self ):
- super(LineEnd,self).__init__()
- self.setWhitespaceChars( ParserElement.DEFAULT_WHITE_CHARS.replace("\n","") )
+ def __init__(self):
+ super(LineEnd, self).__init__()
+ self.setWhitespaceChars(ParserElement.DEFAULT_WHITE_CHARS.replace("\n", ""))
self.errmsg = "Expected end of line"
- def parseImpl( self, instring, loc, doActions=True ):
- if loc len(instring):
return loc, []
else:
@@ -3550,15 +3828,15 @@ class WordStart(_PositionToken):
the beginning of the string being parsed, or at the beginning of
a line.
"""
- def __init__(self, wordChars = printables):
- super(WordStart,self).__init__()
+ def __init__(self, wordChars=printables):
+ super(WordStart, self).__init__()
self.wordChars = set(wordChars)
self.errmsg = "Not at the start of a word"
- def parseImpl(self, instring, loc, doActions=True ):
+ def parseImpl(self, instring, loc, doActions=True):
if loc != 0:
- if (instring[loc-1] in self.wordChars or
- instring[loc] not in self.wordChars):
+ if (instring[loc - 1] in self.wordChars
+ or instring[loc] not in self.wordChars):
raise ParseException(instring, loc, self.errmsg, self)
return loc, []
@@ -3570,17 +3848,17 @@ class WordEnd(_PositionToken):
will also match at the end of the string being parsed, or at the end
of a line.
"""
- def __init__(self, wordChars = printables):
- super(WordEnd,self).__init__()
+ def __init__(self, wordChars=printables):
+ super(WordEnd, self).__init__()
self.wordChars = set(wordChars)
self.skipWhitespace = False
self.errmsg = "Not at the end of a word"
- def parseImpl(self, instring, loc, doActions=True ):
+ def parseImpl(self, instring, loc, doActions=True):
instrlen = len(instring)
- if instrlen>0 and loc 0 and loc < instrlen:
if (instring[loc] in self.wordChars or
- instring[loc-1] not in self.wordChars):
+ instring[loc - 1] not in self.wordChars):
raise ParseException(instring, loc, self.errmsg, self)
return loc, []
@@ -3589,90 +3867,89 @@ class ParseExpression(ParserElement):
"""Abstract subclass of ParserElement, for combining and
post-processing parsed tokens.
"""
- def __init__( self, exprs, savelist = False ):
- super(ParseExpression,self).__init__(savelist)
- if isinstance( exprs, _generatorType ):
+ def __init__(self, exprs, savelist=False):
+ super(ParseExpression, self).__init__(savelist)
+ if isinstance(exprs, _generatorType):
exprs = list(exprs)
- if isinstance( exprs, basestring ):
- self.exprs = [ ParserElement._literalStringClass( exprs ) ]
- elif isinstance( exprs, Iterable ):
+ if isinstance(exprs, basestring):
+ self.exprs = [self._literalStringClass(exprs)]
+ elif isinstance(exprs, ParserElement):
+ self.exprs = [exprs]
+ elif isinstance(exprs, Iterable):
exprs = list(exprs)
# if sequence of strings provided, wrap with Literal
- if all(isinstance(expr, basestring) for expr in exprs):
- exprs = map(ParserElement._literalStringClass, exprs)
+ if any(isinstance(expr, basestring) for expr in exprs):
+ exprs = (self._literalStringClass(e) if isinstance(e, basestring) else e for e in exprs)
self.exprs = list(exprs)
else:
try:
- self.exprs = list( exprs )
+ self.exprs = list(exprs)
except TypeError:
- self.exprs = [ exprs ]
+ self.exprs = [exprs]
self.callPreparse = False
- def __getitem__( self, i ):
- return self.exprs[i]
-
- def append( self, other ):
- self.exprs.append( other )
+ def append(self, other):
+ self.exprs.append(other)
self.strRepr = None
return self
- def leaveWhitespace( self ):
+ def leaveWhitespace(self):
"""Extends ``leaveWhitespace`` defined in base class, and also invokes ``leaveWhitespace`` on
all contained expressions."""
self.skipWhitespace = False
- self.exprs = [ e.copy() for e in self.exprs ]
+ self.exprs = [e.copy() for e in self.exprs]
for e in self.exprs:
e.leaveWhitespace()
return self
- def ignore( self, other ):
- if isinstance( other, Suppress ):
+ def ignore(self, other):
+ if isinstance(other, Suppress):
if other not in self.ignoreExprs:
- super( ParseExpression, self).ignore( other )
+ super(ParseExpression, self).ignore(other)
for e in self.exprs:
- e.ignore( self.ignoreExprs[-1] )
+ e.ignore(self.ignoreExprs[-1])
else:
- super( ParseExpression, self).ignore( other )
+ super(ParseExpression, self).ignore(other)
for e in self.exprs:
- e.ignore( self.ignoreExprs[-1] )
+ e.ignore(self.ignoreExprs[-1])
return self
- def __str__( self ):
+ def __str__(self):
try:
- return super(ParseExpression,self).__str__()
+ return super(ParseExpression, self).__str__()
except Exception:
pass
if self.strRepr is None:
- self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.exprs) )
+ self.strRepr = "%s:(%s)" % (self.__class__.__name__, _ustr(self.exprs))
return self.strRepr
- def streamline( self ):
- super(ParseExpression,self).streamline()
+ def streamline(self):
+ super(ParseExpression, self).streamline()
for e in self.exprs:
e.streamline()
- # collapse nested And's of the form And( And( And( a,b), c), d) to And( a,b,c,d )
+ # collapse nested And's of the form And(And(And(a, b), c), d) to And(a, b, c, d)
# but only if there are no parse actions or resultsNames on the nested And's
# (likewise for Or's and MatchFirst's)
- if ( len(self.exprs) == 2 ):
+ if len(self.exprs) == 2:
other = self.exprs[0]
- if ( isinstance( other, self.__class__ ) and
- not(other.parseAction) and
- other.resultsName is None and
- not other.debug ):
- self.exprs = other.exprs[:] + [ self.exprs[1] ]
+ if (isinstance(other, self.__class__)
+ and not other.parseAction
+ and other.resultsName is None
+ and not other.debug):
+ self.exprs = other.exprs[:] + [self.exprs[1]]
self.strRepr = None
self.mayReturnEmpty |= other.mayReturnEmpty
self.mayIndexError |= other.mayIndexError
other = self.exprs[-1]
- if ( isinstance( other, self.__class__ ) and
- not(other.parseAction) and
- other.resultsName is None and
- not other.debug ):
+ if (isinstance(other, self.__class__)
+ and not other.parseAction
+ and other.resultsName is None
+ and not other.debug):
self.exprs = self.exprs[:-1] + other.exprs[:]
self.strRepr = None
self.mayReturnEmpty |= other.mayReturnEmpty
@@ -3682,17 +3959,31 @@ class ParseExpression(ParserElement):
return self
- def validate( self, validateTrace=[] ):
- tmp = validateTrace[:]+[self]
+ def validate(self, validateTrace=None):
+ tmp = (validateTrace if validateTrace is not None else [])[:] + [self]
for e in self.exprs:
e.validate(tmp)
- self.checkRecursion( [] )
+ self.checkRecursion([])
def copy(self):
- ret = super(ParseExpression,self).copy()
+ ret = super(ParseExpression, self).copy()
ret.exprs = [e.copy() for e in self.exprs]
return ret
+ def _setResultsName(self, name, listAllMatches=False):
+ if __diag__.warn_ungrouped_named_tokens_in_collection:
+ for e in self.exprs:
+ if isinstance(e, ParserElement) and e.resultsName:
+ warnings.warn("{0}: setting results name {1!r} on {2} expression "
+ "collides with {3!r} on contained expression".format("warn_ungrouped_named_tokens_in_collection",
+ name,
+ type(self).__name__,
+ e.resultsName),
+ stacklevel=3)
+
+ return super(ParseExpression, self)._setResultsName(name, listAllMatches)
+
+
class And(ParseExpression):
"""
Requires all given :class:`ParseExpression` s to be found in the given order.
@@ -3706,33 +3997,59 @@ class And(ParseExpression):
integer = Word(nums)
name_expr = OneOrMore(Word(alphas))
- expr = And([integer("id"),name_expr("name"),integer("age")])
+ expr = And([integer("id"), name_expr("name"), integer("age")])
# more easily written as:
expr = integer("id") + name_expr("name") + integer("age")
"""
class _ErrorStop(Empty):
def __init__(self, *args, **kwargs):
- super(And._ErrorStop,self).__init__(*args, **kwargs)
+ super(And._ErrorStop, self).__init__(*args, **kwargs)
self.name = '-'
self.leaveWhitespace()
- def __init__( self, exprs, savelist = True ):
- super(And,self).__init__(exprs, savelist)
+ def __init__(self, exprs, savelist=True):
+ exprs = list(exprs)
+ if exprs and Ellipsis in exprs:
+ tmp = []
+ for i, expr in enumerate(exprs):
+ if expr is Ellipsis:
+ if i < len(exprs) - 1:
+ skipto_arg = (Empty() + exprs[i + 1]).exprs[-1]
+ tmp.append(SkipTo(skipto_arg)("_skipped*"))
+ else:
+ raise Exception("cannot construct And with sequence ending in ...")
+ else:
+ tmp.append(expr)
+ exprs[:] = tmp
+ super(And, self).__init__(exprs, savelist)
self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs)
- self.setWhitespaceChars( self.exprs[0].whiteChars )
+ self.setWhitespaceChars(self.exprs[0].whiteChars)
self.skipWhitespace = self.exprs[0].skipWhitespace
self.callPreparse = True
def streamline(self):
+ # collapse any _PendingSkip's
+ if self.exprs:
+ if any(isinstance(e, ParseExpression) and e.exprs and isinstance(e.exprs[-1], _PendingSkip)
+ for e in self.exprs[:-1]):
+ for i, e in enumerate(self.exprs[:-1]):
+ if e is None:
+ continue
+ if (isinstance(e, ParseExpression)
+ and e.exprs and isinstance(e.exprs[-1], _PendingSkip)):
+ e.exprs[-1] = e.exprs[-1] + self.exprs[i + 1]
+ self.exprs[i + 1] = None
+ self.exprs = [e for e in self.exprs if e is not None]
+
super(And, self).streamline()
self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs)
return self
- def parseImpl( self, instring, loc, doActions=True ):
+ def parseImpl(self, instring, loc, doActions=True):
# pass False as last arg to _parse for first element, since we already
# pre-parsed the string as part of our And pre-parsing
- loc, resultlist = self.exprs[0]._parse( instring, loc, doActions, callPreParse=False )
+ loc, resultlist = self.exprs[0]._parse(instring, loc, doActions, callPreParse=False)
errorStop = False
for e in self.exprs[1:]:
if isinstance(e, And._ErrorStop):
@@ -3740,7 +4057,7 @@ class And(ParseExpression):
continue
if errorStop:
try:
- loc, exprtokens = e._parse( instring, loc, doActions )
+ loc, exprtokens = e._parse(instring, loc, doActions)
except ParseSyntaxException:
raise
except ParseBaseException as pe:
@@ -3749,25 +4066,25 @@ class And(ParseExpression):
except IndexError:
raise ParseSyntaxException(instring, len(instring), self.errmsg, self)
else:
- loc, exprtokens = e._parse( instring, loc, doActions )
+ loc, exprtokens = e._parse(instring, loc, doActions)
if exprtokens or exprtokens.haskeys():
resultlist += exprtokens
return loc, resultlist
- def __iadd__(self, other ):
- if isinstance( other, basestring ):
- other = ParserElement._literalStringClass( other )
- return self.append( other ) #And( [ self, other ] )
+ def __iadd__(self, other):
+ if isinstance(other, basestring):
+ other = self._literalStringClass(other)
+ return self.append(other) # And([self, other])
- def checkRecursion( self, parseElementList ):
- subRecCheckList = parseElementList[:] + [ self ]
+ def checkRecursion(self, parseElementList):
+ subRecCheckList = parseElementList[:] + [self]
for e in self.exprs:
- e.checkRecursion( subRecCheckList )
+ e.checkRecursion(subRecCheckList)
if not e.mayReturnEmpty:
break
- def __str__( self ):
- if hasattr(self,"name"):
+ def __str__(self):
+ if hasattr(self, "name"):
return self.name
if self.strRepr is None:
@@ -3793,8 +4110,8 @@ class Or(ParseExpression):
[['123'], ['3.1416'], ['789']]
"""
- def __init__( self, exprs, savelist = False ):
- super(Or,self).__init__(exprs, savelist)
+ def __init__(self, exprs, savelist=False):
+ super(Or, self).__init__(exprs, savelist)
if self.exprs:
self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs)
else:
@@ -3806,13 +4123,13 @@ class Or(ParseExpression):
self.saveAsList = any(e.saveAsList for e in self.exprs)
return self
- def parseImpl( self, instring, loc, doActions=True ):
+ def parseImpl(self, instring, loc, doActions=True):
maxExcLoc = -1
maxException = None
matches = []
for e in self.exprs:
try:
- loc2 = e.tryParse( instring, loc )
+ loc2 = e.tryParse(instring, loc)
except ParseException as err:
err.__traceback__ = None
if err.loc > maxExcLoc:
@@ -3820,22 +4137,45 @@ class Or(ParseExpression):
maxExcLoc = err.loc
except IndexError:
if len(instring) > maxExcLoc:
- maxException = ParseException(instring,len(instring),e.errmsg,self)
+ maxException = ParseException(instring, len(instring), e.errmsg, self)
maxExcLoc = len(instring)
else:
# save match among all matches, to retry longest to shortest
matches.append((loc2, e))
if matches:
- matches.sort(key=lambda x: -x[0])
- for _,e in matches:
+ # re-evaluate all matches in descending order of length of match, in case attached actions
+ # might change whether or how much they match of the input.
+ matches.sort(key=itemgetter(0), reverse=True)
+
+ if not doActions:
+ # no further conditions or parse actions to change the selection of
+ # alternative, so the first match will be the best match
+ best_expr = matches[0][1]
+ return best_expr._parse(instring, loc, doActions)
+
+ longest = -1, None
+ for loc1, expr1 in matches:
+ if loc1 <= longest[0]:
+ # already have a longer match than this one will deliver, we are done
+ return longest
+
try:
- return e._parse( instring, loc, doActions )
+ loc2, toks = expr1._parse(instring, loc, doActions)
except ParseException as err:
err.__traceback__ = None
if err.loc > maxExcLoc:
maxException = err
maxExcLoc = err.loc
+ else:
+ if loc2 >= loc1:
+ return loc2, toks
+ # didn't match as much as before
+ elif loc2 > longest[0]:
+ longest = loc2, toks
+
+ if longest != (-1, None):
+ return longest
if maxException is not None:
maxException.msg = self.errmsg
@@ -3844,13 +4184,13 @@ class Or(ParseExpression):
raise ParseException(instring, loc, "no defined alternatives to match", self)
- def __ixor__(self, other ):
- if isinstance( other, basestring ):
- other = ParserElement._literalStringClass( other )
- return self.append( other ) #Or( [ self, other ] )
+ def __ixor__(self, other):
+ if isinstance(other, basestring):
+ other = self._literalStringClass(other)
+ return self.append(other) # Or([self, other])
- def __str__( self ):
- if hasattr(self,"name"):
+ def __str__(self):
+ if hasattr(self, "name"):
return self.name
if self.strRepr is None:
@@ -3858,10 +4198,22 @@ class Or(ParseExpression):
return self.strRepr
- def checkRecursion( self, parseElementList ):
- subRecCheckList = parseElementList[:] + [ self ]
+ def checkRecursion(self, parseElementList):
+ subRecCheckList = parseElementList[:] + [self]
for e in self.exprs:
- e.checkRecursion( subRecCheckList )
+ e.checkRecursion(subRecCheckList)
+
+ def _setResultsName(self, name, listAllMatches=False):
+ if (not __compat__.collect_all_And_tokens
+ and __diag__.warn_multiple_tokens_in_named_alternation):
+ if any(isinstance(e, And) for e in self.exprs):
+ warnings.warn("{0}: setting results name {1!r} on {2} expression "
+ "may only return a single token for an And alternative, "
+ "in future will return the full list of tokens".format(
+ "warn_multiple_tokens_in_named_alternation", name, type(self).__name__),
+ stacklevel=3)
+
+ return super(Or, self)._setResultsName(name, listAllMatches)
class MatchFirst(ParseExpression):
@@ -3881,8 +4233,8 @@ class MatchFirst(ParseExpression):
number = Combine(Word(nums) + '.' + Word(nums)) | Word(nums)
print(number.searchString("123 3.1416 789")) # Better -> [['123'], ['3.1416'], ['789']]
"""
- def __init__( self, exprs, savelist = False ):
- super(MatchFirst,self).__init__(exprs, savelist)
+ def __init__(self, exprs, savelist=False):
+ super(MatchFirst, self).__init__(exprs, savelist)
if self.exprs:
self.mayReturnEmpty = any(e.mayReturnEmpty for e in self.exprs)
else:
@@ -3894,12 +4246,12 @@ class MatchFirst(ParseExpression):
self.saveAsList = any(e.saveAsList for e in self.exprs)
return self
- def parseImpl( self, instring, loc, doActions=True ):
+ def parseImpl(self, instring, loc, doActions=True):
maxExcLoc = -1
maxException = None
for e in self.exprs:
try:
- ret = e._parse( instring, loc, doActions )
+ ret = e._parse(instring, loc, doActions)
return ret
except ParseException as err:
if err.loc > maxExcLoc:
@@ -3907,7 +4259,7 @@ class MatchFirst(ParseExpression):
maxExcLoc = err.loc
except IndexError:
if len(instring) > maxExcLoc:
- maxException = ParseException(instring,len(instring),e.errmsg,self)
+ maxException = ParseException(instring, len(instring), e.errmsg, self)
maxExcLoc = len(instring)
# only got here if no expression matched, raise exception for match that made it the furthest
@@ -3918,13 +4270,13 @@ class MatchFirst(ParseExpression):
else:
raise ParseException(instring, loc, "no defined alternatives to match", self)
- def __ior__(self, other ):
- if isinstance( other, basestring ):
- other = ParserElement._literalStringClass( other )
- return self.append( other ) #MatchFirst( [ self, other ] )
+ def __ior__(self, other):
+ if isinstance(other, basestring):
+ other = self._literalStringClass(other)
+ return self.append(other) # MatchFirst([self, other])
- def __str__( self ):
- if hasattr(self,"name"):
+ def __str__(self):
+ if hasattr(self, "name"):
return self.name
if self.strRepr is None:
@@ -3932,10 +4284,22 @@ class MatchFirst(ParseExpression):
return self.strRepr
- def checkRecursion( self, parseElementList ):
- subRecCheckList = parseElementList[:] + [ self ]
+ def checkRecursion(self, parseElementList):
+ subRecCheckList = parseElementList[:] + [self]
for e in self.exprs:
- e.checkRecursion( subRecCheckList )
+ e.checkRecursion(subRecCheckList)
+
+ def _setResultsName(self, name, listAllMatches=False):
+ if (not __compat__.collect_all_And_tokens
+ and __diag__.warn_multiple_tokens_in_named_alternation):
+ if any(isinstance(e, And) for e in self.exprs):
+ warnings.warn("{0}: setting results name {1!r} on {2} expression "
+ "may only return a single token for an And alternative, "
+ "in future will return the full list of tokens".format(
+ "warn_multiple_tokens_in_named_alternation", name, type(self).__name__),
+ stacklevel=3)
+
+ return super(MatchFirst, self)._setResultsName(name, listAllMatches)
class Each(ParseExpression):
@@ -3995,8 +4359,8 @@ class Each(ParseExpression):
- shape: TRIANGLE
- size: 20
"""
- def __init__( self, exprs, savelist = True ):
- super(Each,self).__init__(exprs, savelist)
+ def __init__(self, exprs, savelist=True):
+ super(Each, self).__init__(exprs, savelist)
self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs)
self.skipWhitespace = True
self.initExprGroups = True
@@ -4007,15 +4371,15 @@ class Each(ParseExpression):
self.mayReturnEmpty = all(e.mayReturnEmpty for e in self.exprs)
return self
- def parseImpl( self, instring, loc, doActions=True ):
+ def parseImpl(self, instring, loc, doActions=True):
if self.initExprGroups:
- self.opt1map = dict((id(e.expr),e) for e in self.exprs if isinstance(e,Optional))
- opt1 = [ e.expr for e in self.exprs if isinstance(e,Optional) ]
- opt2 = [ e for e in self.exprs if e.mayReturnEmpty and not isinstance(e,Optional)]
+ self.opt1map = dict((id(e.expr), e) for e in self.exprs if isinstance(e, Optional))
+ opt1 = [e.expr for e in self.exprs if isinstance(e, Optional)]
+ opt2 = [e for e in self.exprs if e.mayReturnEmpty and not isinstance(e, (Optional, Regex))]
self.optionals = opt1 + opt2
- self.multioptionals = [ e.expr for e in self.exprs if isinstance(e,ZeroOrMore) ]
- self.multirequired = [ e.expr for e in self.exprs if isinstance(e,OneOrMore) ]
- self.required = [ e for e in self.exprs if not isinstance(e,(Optional,ZeroOrMore,OneOrMore)) ]
+ self.multioptionals = [e.expr for e in self.exprs if isinstance(e, ZeroOrMore)]
+ self.multirequired = [e.expr for e in self.exprs if isinstance(e, OneOrMore)]
+ self.required = [e for e in self.exprs if not isinstance(e, (Optional, ZeroOrMore, OneOrMore))]
self.required += self.multirequired
self.initExprGroups = False
tmpLoc = loc
@@ -4029,11 +4393,11 @@ class Each(ParseExpression):
failed = []
for e in tmpExprs:
try:
- tmpLoc = e.tryParse( instring, tmpLoc )
+ tmpLoc = e.tryParse(instring, tmpLoc)
except ParseException:
failed.append(e)
else:
- matchOrder.append(self.opt1map.get(id(e),e))
+ matchOrder.append(self.opt1map.get(id(e), e))
if e in tmpReqd:
tmpReqd.remove(e)
elif e in tmpOpt:
@@ -4043,21 +4407,21 @@ class Each(ParseExpression):
if tmpReqd:
missing = ", ".join(_ustr(e) for e in tmpReqd)
- raise ParseException(instring,loc,"Missing one or more required elements (%s)" % missing )
+ raise ParseException(instring, loc, "Missing one or more required elements (%s)" % missing)
# add any unmatched Optionals, in case they have default values defined
- matchOrder += [e for e in self.exprs if isinstance(e,Optional) and e.expr in tmpOpt]
+ matchOrder += [e for e in self.exprs if isinstance(e, Optional) and e.expr in tmpOpt]
resultlist = []
for e in matchOrder:
- loc,results = e._parse(instring,loc,doActions)
+ loc, results = e._parse(instring, loc, doActions)
resultlist.append(results)
finalResults = sum(resultlist, ParseResults([]))
return loc, finalResults
- def __str__( self ):
- if hasattr(self,"name"):
+ def __str__(self):
+ if hasattr(self, "name"):
return self.name
if self.strRepr is None:
@@ -4065,86 +4429,88 @@ class Each(ParseExpression):
return self.strRepr
- def checkRecursion( self, parseElementList ):
- subRecCheckList = parseElementList[:] + [ self ]
+ def checkRecursion(self, parseElementList):
+ subRecCheckList = parseElementList[:] + [self]
for e in self.exprs:
- e.checkRecursion( subRecCheckList )
+ e.checkRecursion(subRecCheckList)
class ParseElementEnhance(ParserElement):
"""Abstract subclass of :class:`ParserElement`, for combining and
post-processing parsed tokens.
"""
- def __init__( self, expr, savelist=False ):
- super(ParseElementEnhance,self).__init__(savelist)
- if isinstance( expr, basestring ):
- if issubclass(ParserElement._literalStringClass, Token):
- expr = ParserElement._literalStringClass(expr)
+ def __init__(self, expr, savelist=False):
+ super(ParseElementEnhance, self).__init__(savelist)
+ if isinstance(expr, basestring):
+ if issubclass(self._literalStringClass, Token):
+ expr = self._literalStringClass(expr)
else:
- expr = ParserElement._literalStringClass(Literal(expr))
+ expr = self._literalStringClass(Literal(expr))
self.expr = expr
self.strRepr = None
if expr is not None:
self.mayIndexError = expr.mayIndexError
self.mayReturnEmpty = expr.mayReturnEmpty
- self.setWhitespaceChars( expr.whiteChars )
+ self.setWhitespaceChars(expr.whiteChars)
self.skipWhitespace = expr.skipWhitespace
self.saveAsList = expr.saveAsList
self.callPreparse = expr.callPreparse
self.ignoreExprs.extend(expr.ignoreExprs)
- def parseImpl( self, instring, loc, doActions=True ):
+ def parseImpl(self, instring, loc, doActions=True):
if self.expr is not None:
- return self.expr._parse( instring, loc, doActions, callPreParse=False )
+ return self.expr._parse(instring, loc, doActions, callPreParse=False)
else:
- raise ParseException("",loc,self.errmsg,self)
+ raise ParseException("", loc, self.errmsg, self)
- def leaveWhitespace( self ):
+ def leaveWhitespace(self):
self.skipWhitespace = False
self.expr = self.expr.copy()
if self.expr is not None:
self.expr.leaveWhitespace()
return self
- def ignore( self, other ):
- if isinstance( other, Suppress ):
+ def ignore(self, other):
+ if isinstance(other, Suppress):
if other not in self.ignoreExprs:
- super( ParseElementEnhance, self).ignore( other )
+ super(ParseElementEnhance, self).ignore(other)
if self.expr is not None:
- self.expr.ignore( self.ignoreExprs[-1] )
+ self.expr.ignore(self.ignoreExprs[-1])
else:
- super( ParseElementEnhance, self).ignore( other )
+ super(ParseElementEnhance, self).ignore(other)
if self.expr is not None:
- self.expr.ignore( self.ignoreExprs[-1] )
+ self.expr.ignore(self.ignoreExprs[-1])
return self
- def streamline( self ):
- super(ParseElementEnhance,self).streamline()
+ def streamline(self):
+ super(ParseElementEnhance, self).streamline()
if self.expr is not None:
self.expr.streamline()
return self
- def checkRecursion( self, parseElementList ):
+ def checkRecursion(self, parseElementList):
if self in parseElementList:
- raise RecursiveGrammarException( parseElementList+[self] )
- subRecCheckList = parseElementList[:] + [ self ]
+ raise RecursiveGrammarException(parseElementList + [self])
+ subRecCheckList = parseElementList[:] + [self]
if self.expr is not None:
- self.expr.checkRecursion( subRecCheckList )
+ self.expr.checkRecursion(subRecCheckList)
- def validate( self, validateTrace=[] ):
- tmp = validateTrace[:]+[self]
+ def validate(self, validateTrace=None):
+ if validateTrace is None:
+ validateTrace = []
+ tmp = validateTrace[:] + [self]
if self.expr is not None:
self.expr.validate(tmp)
- self.checkRecursion( [] )
+ self.checkRecursion([])
- def __str__( self ):
+ def __str__(self):
try:
- return super(ParseElementEnhance,self).__str__()
+ return super(ParseElementEnhance, self).__str__()
except Exception:
pass
if self.strRepr is None and self.expr is not None:
- self.strRepr = "%s:(%s)" % ( self.__class__.__name__, _ustr(self.expr) )
+ self.strRepr = "%s:(%s)" % (self.__class__.__name__, _ustr(self.expr))
return self.strRepr
@@ -4170,13 +4536,16 @@ class FollowedBy(ParseElementEnhance):
[['shape', 'SQUARE'], ['color', 'BLACK'], ['posn', 'upper left']]
"""
- def __init__( self, expr ):
- super(FollowedBy,self).__init__(expr)
+ def __init__(self, expr):
+ super(FollowedBy, self).__init__(expr)
self.mayReturnEmpty = True
- def parseImpl( self, instring, loc, doActions=True ):
+ def parseImpl(self, instring, loc, doActions=True):
+ # by using self._expr.parse and deleting the contents of the returned ParseResults list
+ # we keep any named results that were defined in the FollowedBy expression
_, ret = self.expr._parse(instring, loc, doActions=doActions)
del ret[:]
+
return loc, ret
@@ -4229,6 +4598,7 @@ class PrecededBy(ParseElementEnhance):
self.retreat = retreat
self.errmsg = "not preceded by " + str(expr)
self.skipWhitespace = False
+ self.parseAction.append(lambda s, l, t: t.__delitem__(slice(None, None)))
def parseImpl(self, instring, loc=0, doActions=True):
if self.exact:
@@ -4239,19 +4609,18 @@ class PrecededBy(ParseElementEnhance):
else:
# retreat specified a maximum lookbehind window, iterate
test_expr = self.expr + StringEnd()
- instring_slice = instring[:loc]
+ instring_slice = instring[max(0, loc - self.retreat):loc]
last_expr = ParseException(instring, loc, self.errmsg)
- for offset in range(1, min(loc, self.retreat+1)):
+ for offset in range(1, min(loc, self.retreat + 1)+1):
try:
- _, ret = test_expr._parse(instring_slice, loc-offset)
+ # print('trying', offset, instring_slice, repr(instring_slice[loc - offset:]))
+ _, ret = test_expr._parse(instring_slice, len(instring_slice) - offset)
except ParseBaseException as pbe:
last_expr = pbe
else:
break
else:
raise last_expr
- # return empty list of tokens, but preserve any defined results names
- del ret[:]
return loc, ret
@@ -4278,20 +4647,20 @@ class NotAny(ParseElementEnhance):
# integers that are followed by "." are actually floats
integer = Word(nums) + ~Char(".")
"""
- def __init__( self, expr ):
- super(NotAny,self).__init__(expr)
- #~ self.leaveWhitespace()
+ def __init__(self, expr):
+ super(NotAny, self).__init__(expr)
+ # ~ self.leaveWhitespace()
self.skipWhitespace = False # do NOT use self.leaveWhitespace(), don't want to propagate to exprs
self.mayReturnEmpty = True
- self.errmsg = "Found unwanted token, "+_ustr(self.expr)
+ self.errmsg = "Found unwanted token, " + _ustr(self.expr)
- def parseImpl( self, instring, loc, doActions=True ):
+ def parseImpl(self, instring, loc, doActions=True):
if self.expr.canParseNext(instring, loc):
raise ParseException(instring, loc, self.errmsg, self)
return loc, []
- def __str__( self ):
- if hasattr(self,"name"):
+ def __str__(self):
+ if hasattr(self, "name"):
return self.name
if self.strRepr is None:
@@ -4300,15 +4669,21 @@ class NotAny(ParseElementEnhance):
return self.strRepr
class _MultipleMatch(ParseElementEnhance):
- def __init__( self, expr, stopOn=None):
+ def __init__(self, expr, stopOn=None):
super(_MultipleMatch, self).__init__(expr)
self.saveAsList = True
ender = stopOn
if isinstance(ender, basestring):
- ender = ParserElement._literalStringClass(ender)
- self.not_ender = ~ender if ender is not None else None
+ ender = self._literalStringClass(ender)
+ self.stopOn(ender)
- def parseImpl( self, instring, loc, doActions=True ):
+ def stopOn(self, ender):
+ if isinstance(ender, basestring):
+ ender = self._literalStringClass(ender)
+ self.not_ender = ~ender if ender is not None else None
+ return self
+
+ def parseImpl(self, instring, loc, doActions=True):
self_expr_parse = self.expr._parse
self_skip_ignorables = self._skipIgnorables
check_ender = self.not_ender is not None
@@ -4319,24 +4694,38 @@ class _MultipleMatch(ParseElementEnhance):
# if so, fail)
if check_ender:
try_not_ender(instring, loc)
- loc, tokens = self_expr_parse( instring, loc, doActions, callPreParse=False )
+ loc, tokens = self_expr_parse(instring, loc, doActions, callPreParse=False)
try:
hasIgnoreExprs = (not not self.ignoreExprs)
while 1:
if check_ender:
try_not_ender(instring, loc)
if hasIgnoreExprs:
- preloc = self_skip_ignorables( instring, loc )
+ preloc = self_skip_ignorables(instring, loc)
else:
preloc = loc
- loc, tmptokens = self_expr_parse( instring, preloc, doActions )
+ loc, tmptokens = self_expr_parse(instring, preloc, doActions)
if tmptokens or tmptokens.haskeys():
tokens += tmptokens
- except (ParseException,IndexError):
+ except (ParseException, IndexError):
pass
return loc, tokens
+ def _setResultsName(self, name, listAllMatches=False):
+ if __diag__.warn_ungrouped_named_tokens_in_collection:
+ for e in [self.expr] + getattr(self.expr, 'exprs', []):
+ if isinstance(e, ParserElement) and e.resultsName:
+ warnings.warn("{0}: setting results name {1!r} on {2} expression "
+ "collides with {3!r} on contained expression".format("warn_ungrouped_named_tokens_in_collection",
+ name,
+ type(self).__name__,
+ e.resultsName),
+ stacklevel=3)
+
+ return super(_MultipleMatch, self)._setResultsName(name, listAllMatches)
+
+
class OneOrMore(_MultipleMatch):
"""Repetition of one or more of the given expression.
@@ -4363,8 +4752,8 @@ class OneOrMore(_MultipleMatch):
(attr_expr * (1,)).parseString(text).pprint()
"""
- def __str__( self ):
- if hasattr(self,"name"):
+ def __str__(self):
+ if hasattr(self, "name"):
return self.name
if self.strRepr is None:
@@ -4383,18 +4772,18 @@ class ZeroOrMore(_MultipleMatch):
Example: similar to :class:`OneOrMore`
"""
- def __init__( self, expr, stopOn=None):
- super(ZeroOrMore,self).__init__(expr, stopOn=stopOn)
+ def __init__(self, expr, stopOn=None):
+ super(ZeroOrMore, self).__init__(expr, stopOn=stopOn)
self.mayReturnEmpty = True
- def parseImpl( self, instring, loc, doActions=True ):
+ def parseImpl(self, instring, loc, doActions=True):
try:
return super(ZeroOrMore, self).parseImpl(instring, loc, doActions)
- except (ParseException,IndexError):
+ except (ParseException, IndexError):
return loc, []
- def __str__( self ):
- if hasattr(self,"name"):
+ def __str__(self):
+ if hasattr(self, "name"):
return self.name
if self.strRepr is None:
@@ -4402,6 +4791,7 @@ class ZeroOrMore(_MultipleMatch):
return self.strRepr
+
class _NullToken(object):
def __bool__(self):
return False
@@ -4409,7 +4799,6 @@ class _NullToken(object):
def __str__(self):
return ""
-_optionalNotMatched = _NullToken()
class Optional(ParseElementEnhance):
"""Optional matching of the given expression.
@@ -4447,28 +4836,30 @@ class Optional(ParseElementEnhance):
^
FAIL: Expected end of text (at char 5), (line:1, col:6)
"""
- def __init__( self, expr, default=_optionalNotMatched ):
- super(Optional,self).__init__( expr, savelist=False )
+ __optionalNotMatched = _NullToken()
+
+ def __init__(self, expr, default=__optionalNotMatched):
+ super(Optional, self).__init__(expr, savelist=False)
self.saveAsList = self.expr.saveAsList
self.defaultValue = default
self.mayReturnEmpty = True
- def parseImpl( self, instring, loc, doActions=True ):
+ def parseImpl(self, instring, loc, doActions=True):
try:
- loc, tokens = self.expr._parse( instring, loc, doActions, callPreParse=False )
- except (ParseException,IndexError):
- if self.defaultValue is not _optionalNotMatched:
+ loc, tokens = self.expr._parse(instring, loc, doActions, callPreParse=False)
+ except (ParseException, IndexError):
+ if self.defaultValue is not self.__optionalNotMatched:
if self.expr.resultsName:
- tokens = ParseResults([ self.defaultValue ])
+ tokens = ParseResults([self.defaultValue])
tokens[self.expr.resultsName] = self.defaultValue
else:
- tokens = [ self.defaultValue ]
+ tokens = [self.defaultValue]
else:
tokens = []
return loc, tokens
- def __str__( self ):
- if hasattr(self,"name"):
+ def __str__(self):
+ if hasattr(self, "name"):
return self.name
if self.strRepr is None:
@@ -4534,20 +4925,20 @@ class SkipTo(ParseElementEnhance):
- issue_num: 79
- sev: Minor
"""
- def __init__( self, other, include=False, ignore=None, failOn=None ):
- super( SkipTo, self ).__init__( other )
+ def __init__(self, other, include=False, ignore=None, failOn=None):
+ super(SkipTo, self).__init__(other)
self.ignoreExpr = ignore
self.mayReturnEmpty = True
self.mayIndexError = False
self.includeMatch = include
self.saveAsList = False
if isinstance(failOn, basestring):
- self.failOn = ParserElement._literalStringClass(failOn)
+ self.failOn = self._literalStringClass(failOn)
else:
self.failOn = failOn
- self.errmsg = "No match found for "+_ustr(self.expr)
+ self.errmsg = "No match found for " + _ustr(self.expr)
- def parseImpl( self, instring, loc, doActions=True ):
+ def parseImpl(self, instring, loc, doActions=True):
startloc = loc
instrlen = len(instring)
expr = self.expr
@@ -4589,7 +4980,7 @@ class SkipTo(ParseElementEnhance):
skipresult = ParseResults(skiptext)
if self.includeMatch:
- loc, mat = expr_parse(instring,loc,doActions,callPreParse=False)
+ loc, mat = expr_parse(instring, loc, doActions, callPreParse=False)
skipresult += mat
return loc, skipresult
@@ -4621,17 +5012,17 @@ class Forward(ParseElementEnhance):
See :class:`ParseResults.pprint` for an example of a recursive
parser created using ``Forward``.
"""
- def __init__( self, other=None ):
- super(Forward,self).__init__( other, savelist=False )
+ def __init__(self, other=None):
+ super(Forward, self).__init__(other, savelist=False)
- def __lshift__( self, other ):
- if isinstance( other, basestring ):
- other = ParserElement._literalStringClass(other)
+ def __lshift__(self, other):
+ if isinstance(other, basestring):
+ other = self._literalStringClass(other)
self.expr = other
self.strRepr = None
self.mayIndexError = self.expr.mayIndexError
self.mayReturnEmpty = self.expr.mayReturnEmpty
- self.setWhitespaceChars( self.expr.whiteChars )
+ self.setWhitespaceChars(self.expr.whiteChars)
self.skipWhitespace = self.expr.skipWhitespace
self.saveAsList = self.expr.saveAsList
self.ignoreExprs.extend(self.expr.ignoreExprs)
@@ -4640,55 +5031,72 @@ class Forward(ParseElementEnhance):
def __ilshift__(self, other):
return self << other
- def leaveWhitespace( self ):
+ def leaveWhitespace(self):
self.skipWhitespace = False
return self
- def streamline( self ):
+ def streamline(self):
if not self.streamlined:
self.streamlined = True
if self.expr is not None:
self.expr.streamline()
return self
- def validate( self, validateTrace=[] ):
+ def validate(self, validateTrace=None):
+ if validateTrace is None:
+ validateTrace = []
+
if self not in validateTrace:
- tmp = validateTrace[:]+[self]
+ tmp = validateTrace[:] + [self]
if self.expr is not None:
self.expr.validate(tmp)
self.checkRecursion([])
- def __str__( self ):
- if hasattr(self,"name"):
+ def __str__(self):
+ if hasattr(self, "name"):
return self.name
+ if self.strRepr is not None:
+ return self.strRepr
- # Avoid infinite recursion by setting a temporary name
- self.name = self.__class__.__name__ + ": ..."
+ # Avoid infinite recursion by setting a temporary strRepr
+ self.strRepr = ": ..."
# Use the string representation of main expression.
+ retString = '...'
try:
if self.expr is not None:
- retString = _ustr(self.expr)
+ retString = _ustr(self.expr)[:1000]
else:
retString = "None"
finally:
- del self.name
- return self.__class__.__name__ + ": " + retString
+ self.strRepr = self.__class__.__name__ + ": " + retString
+ return self.strRepr
def copy(self):
if self.expr is not None:
- return super(Forward,self).copy()
+ return super(Forward, self).copy()
else:
ret = Forward()
ret <<= self
return ret
+ def _setResultsName(self, name, listAllMatches=False):
+ if __diag__.warn_name_set_on_empty_Forward:
+ if self.expr is None:
+ warnings.warn("{0}: setting results name {0!r} on {1} expression "
+ "that has no contained expression".format("warn_name_set_on_empty_Forward",
+ name,
+ type(self).__name__),
+ stacklevel=3)
+
+ return super(Forward, self)._setResultsName(name, listAllMatches)
+
class TokenConverter(ParseElementEnhance):
"""
Abstract subclass of :class:`ParseExpression`, for converting parsed results.
"""
- def __init__( self, expr, savelist=False ):
- super(TokenConverter,self).__init__( expr )#, savelist )
+ def __init__(self, expr, savelist=False):
+ super(TokenConverter, self).__init__(expr) # , savelist)
self.saveAsList = False
class Combine(TokenConverter):
@@ -4709,8 +5117,8 @@ class Combine(TokenConverter):
# no match when there are internal spaces
print(real.parseString('3. 1416')) # -> Exception: Expected W:(0123...)
"""
- def __init__( self, expr, joinString="", adjacent=True ):
- super(Combine,self).__init__( expr )
+ def __init__(self, expr, joinString="", adjacent=True):
+ super(Combine, self).__init__(expr)
# suppress whitespace-stripping in contained parse expressions, but re-enable it on the Combine itself
if adjacent:
self.leaveWhitespace()
@@ -4719,20 +5127,20 @@ class Combine(TokenConverter):
self.joinString = joinString
self.callPreparse = True
- def ignore( self, other ):
+ def ignore(self, other):
if self.adjacent:
ParserElement.ignore(self, other)
else:
- super( Combine, self).ignore( other )
+ super(Combine, self).ignore(other)
return self
- def postParse( self, instring, loc, tokenlist ):
+ def postParse(self, instring, loc, tokenlist):
retToks = tokenlist.copy()
del retToks[:]
- retToks += ParseResults([ "".join(tokenlist._asStringList(self.joinString)) ], modal=self.modalResults)
+ retToks += ParseResults(["".join(tokenlist._asStringList(self.joinString))], modal=self.modalResults)
if self.resultsName and retToks.haskeys():
- return [ retToks ]
+ return [retToks]
else:
return retToks
@@ -4746,17 +5154,17 @@ class Group(TokenConverter):
num = Word(nums)
term = ident | num
func = ident + Optional(delimitedList(term))
- print(func.parseString("fn a,b,100")) # -> ['fn', 'a', 'b', '100']
+ print(func.parseString("fn a, b, 100")) # -> ['fn', 'a', 'b', '100']
func = ident + Group(Optional(delimitedList(term)))
- print(func.parseString("fn a,b,100")) # -> ['fn', ['a', 'b', '100']]
+ print(func.parseString("fn a, b, 100")) # -> ['fn', ['a', 'b', '100']]
"""
- def __init__( self, expr ):
- super(Group,self).__init__( expr )
+ def __init__(self, expr):
+ super(Group, self).__init__(expr)
self.saveAsList = True
- def postParse( self, instring, loc, tokenlist ):
- return [ tokenlist ]
+ def postParse(self, instring, loc, tokenlist):
+ return [tokenlist]
class Dict(TokenConverter):
"""Converter to return a repetitive expression as a list, but also
@@ -4797,31 +5205,31 @@ class Dict(TokenConverter):
See more examples at :class:`ParseResults` of accessing fields by results name.
"""
- def __init__( self, expr ):
- super(Dict,self).__init__( expr )
+ def __init__(self, expr):
+ super(Dict, self).__init__(expr)
self.saveAsList = True
- def postParse( self, instring, loc, tokenlist ):
- for i,tok in enumerate(tokenlist):
+ def postParse(self, instring, loc, tokenlist):
+ for i, tok in enumerate(tokenlist):
if len(tok) == 0:
continue
ikey = tok[0]
- if isinstance(ikey,int):
+ if isinstance(ikey, int):
ikey = _ustr(tok[0]).strip()
- if len(tok)==1:
- tokenlist[ikey] = _ParseResultsWithOffset("",i)
- elif len(tok)==2 and not isinstance(tok[1],ParseResults):
- tokenlist[ikey] = _ParseResultsWithOffset(tok[1],i)
+ if len(tok) == 1:
+ tokenlist[ikey] = _ParseResultsWithOffset("", i)
+ elif len(tok) == 2 and not isinstance(tok[1], ParseResults):
+ tokenlist[ikey] = _ParseResultsWithOffset(tok[1], i)
else:
- dictvalue = tok.copy() #ParseResults(i)
+ dictvalue = tok.copy() # ParseResults(i)
del dictvalue[0]
- if len(dictvalue)!= 1 or (isinstance(dictvalue,ParseResults) and dictvalue.haskeys()):
- tokenlist[ikey] = _ParseResultsWithOffset(dictvalue,i)
+ if len(dictvalue) != 1 or (isinstance(dictvalue, ParseResults) and dictvalue.haskeys()):
+ tokenlist[ikey] = _ParseResultsWithOffset(dictvalue, i)
else:
- tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0],i)
+ tokenlist[ikey] = _ParseResultsWithOffset(dictvalue[0], i)
if self.resultsName:
- return [ tokenlist ]
+ return [tokenlist]
else:
return tokenlist
@@ -4848,10 +5256,10 @@ class Suppress(TokenConverter):
(See also :class:`delimitedList`.)
"""
- def postParse( self, instring, loc, tokenlist ):
+ def postParse(self, instring, loc, tokenlist):
return []
- def suppress( self ):
+ def suppress(self):
return self
@@ -4861,12 +5269,12 @@ class OnlyOnce(object):
def __init__(self, methodCall):
self.callable = _trim_arity(methodCall)
self.called = False
- def __call__(self,s,l,t):
+ def __call__(self, s, l, t):
if not self.called:
- results = self.callable(s,l,t)
+ results = self.callable(s, l, t)
self.called = True
return results
- raise ParseException(s,l,"")
+ raise ParseException(s, l, "")
def reset(self):
self.called = False
@@ -4898,16 +5306,16 @@ def traceParseAction(f):
f = _trim_arity(f)
def z(*paArgs):
thisFunc = f.__name__
- s,l,t = paArgs[-3:]
- if len(paArgs)>3:
+ s, l, t = paArgs[-3:]
+ if len(paArgs) > 3:
thisFunc = paArgs[0].__class__.__name__ + '.' + thisFunc
- sys.stderr.write( ">>entering %s(line: '%s', %d, %r)\n" % (thisFunc,line(l,s),l,t) )
+ sys.stderr.write(">>entering %s(line: '%s', %d, %r)\n" % (thisFunc, line(l, s), l, t))
try:
ret = f(*paArgs)
except Exception as exc:
- sys.stderr.write( "< ['aa', 'bb', 'cc']
delimitedList(Word(hexnums), delim=':', combine=True).parseString("AA:BB:CC:DD:EE") # -> ['AA:BB:CC:DD:EE']
"""
- dlName = _ustr(expr)+" ["+_ustr(delim)+" "+_ustr(expr)+"]..."
+ dlName = _ustr(expr) + " [" + _ustr(delim) + " " + _ustr(expr) + "]..."
if combine:
- return Combine( expr + ZeroOrMore( delim + expr ) ).setName(dlName)
+ return Combine(expr + ZeroOrMore(delim + expr)).setName(dlName)
else:
- return ( expr + ZeroOrMore( Suppress( delim ) + expr ) ).setName(dlName)
+ return (expr + ZeroOrMore(Suppress(delim) + expr)).setName(dlName)
-def countedArray( expr, intExpr=None ):
+def countedArray(expr, intExpr=None):
"""Helper to define a counted list of expressions.
This helper defines a pattern of the form::
@@ -4963,22 +5371,22 @@ def countedArray( expr, intExpr=None ):
countedArray(Word(alphas), intExpr=binaryConstant).parseString('10 ab cd ef') # -> ['ab', 'cd']
"""
arrayExpr = Forward()
- def countFieldParseAction(s,l,t):
+ def countFieldParseAction(s, l, t):
n = t[0]
- arrayExpr << (n and Group(And([expr]*n)) or Group(empty))
+ arrayExpr << (n and Group(And([expr] * n)) or Group(empty))
return []
if intExpr is None:
- intExpr = Word(nums).setParseAction(lambda t:int(t[0]))
+ intExpr = Word(nums).setParseAction(lambda t: int(t[0]))
else:
intExpr = intExpr.copy()
intExpr.setName("arrayLen")
intExpr.addParseAction(countFieldParseAction, callDuringTry=True)
- return ( intExpr + arrayExpr ).setName('(len) ' + _ustr(expr) + '...')
+ return (intExpr + arrayExpr).setName('(len) ' + _ustr(expr) + '...')
def _flatten(L):
ret = []
for i in L:
- if isinstance(i,list):
+ if isinstance(i, list):
ret.extend(_flatten(i))
else:
ret.append(i)
@@ -5000,7 +5408,7 @@ def matchPreviousLiteral(expr):
enabled.
"""
rep = Forward()
- def copyTokenToRepeater(s,l,t):
+ def copyTokenToRepeater(s, l, t):
if t:
if len(t) == 1:
rep << t[0]
@@ -5032,26 +5440,26 @@ def matchPreviousExpr(expr):
rep = Forward()
e2 = expr.copy()
rep <<= e2
- def copyTokenToRepeater(s,l,t):
+ def copyTokenToRepeater(s, l, t):
matchTokens = _flatten(t.asList())
- def mustMatchTheseTokens(s,l,t):
+ def mustMatchTheseTokens(s, l, t):
theseTokens = _flatten(t.asList())
- if theseTokens != matchTokens:
- raise ParseException("",0,"")
- rep.setParseAction( mustMatchTheseTokens, callDuringTry=True )
+ if theseTokens != matchTokens:
+ raise ParseException('', 0, '')
+ rep.setParseAction(mustMatchTheseTokens, callDuringTry=True)
expr.addParseAction(copyTokenToRepeater, callDuringTry=True)
rep.setName('(prev) ' + _ustr(expr))
return rep
def _escapeRegexRangeChars(s):
- #~ escape these chars: ^-]
- for c in r"\^-]":
- s = s.replace(c,_bslash+c)
- s = s.replace("\n",r"\n")
- s = s.replace("\t",r"\t")
+ # ~ escape these chars: ^-[]
+ for c in r"\^-[]":
+ s = s.replace(c, _bslash + c)
+ s = s.replace("\n", r"\n")
+ s = s.replace("\t", r"\t")
return _ustr(s)
-def oneOf( strs, caseless=False, useRegex=True ):
+def oneOf(strs, caseless=False, useRegex=True, asKeyword=False):
"""Helper to quickly define a set of alternative Literals, and makes
sure to do longest-first testing when there is a conflict,
regardless of the input order, but returns
@@ -5065,8 +5473,10 @@ def oneOf( strs, caseless=False, useRegex=True ):
caseless
- useRegex - (default= ``True``) - as an optimization, will
generate a Regex object; otherwise, will generate
- a :class:`MatchFirst` object (if ``caseless=True``, or if
+ a :class:`MatchFirst` object (if ``caseless=True`` or ``asKeyword=True``, or if
creating a :class:`Regex` raises an exception)
+ - asKeyword - (default=``False``) - enforce Keyword-style matching on the
+ generated expressions
Example::
@@ -5081,57 +5491,62 @@ def oneOf( strs, caseless=False, useRegex=True ):
[['B', '=', '12'], ['AA', '=', '23'], ['B', '<=', 'AA'], ['AA', '>', '12']]
"""
+ if isinstance(caseless, basestring):
+ warnings.warn("More than one string argument passed to oneOf, pass "
+ "choices as a list or space-delimited string", stacklevel=2)
+
if caseless:
- isequal = ( lambda a,b: a.upper() == b.upper() )
- masks = ( lambda a,b: b.upper().startswith(a.upper()) )
- parseElementClass = CaselessLiteral
+ isequal = (lambda a, b: a.upper() == b.upper())
+ masks = (lambda a, b: b.upper().startswith(a.upper()))
+ parseElementClass = CaselessKeyword if asKeyword else CaselessLiteral
else:
- isequal = ( lambda a,b: a == b )
- masks = ( lambda a,b: b.startswith(a) )
- parseElementClass = Literal
+ isequal = (lambda a, b: a == b)
+ masks = (lambda a, b: b.startswith(a))
+ parseElementClass = Keyword if asKeyword else Literal
symbols = []
- if isinstance(strs,basestring):
+ if isinstance(strs, basestring):
symbols = strs.split()
elif isinstance(strs, Iterable):
symbols = list(strs)
else:
warnings.warn("Invalid argument to oneOf, expected string or iterable",
- SyntaxWarning, stacklevel=2)
+ SyntaxWarning, stacklevel=2)
if not symbols:
return NoMatch()
- i = 0
- while i < len(symbols)-1:
- cur = symbols[i]
- for j,other in enumerate(symbols[i+1:]):
- if ( isequal(other, cur) ):
- del symbols[i+j+1]
- break
- elif ( masks(cur, other) ):
- del symbols[i+j+1]
- symbols.insert(i,other)
- cur = other
- break
- else:
- i += 1
-
- if not caseless and useRegex:
- #~ print (strs,"->", "|".join( [ _escapeRegexChars(sym) for sym in symbols] ))
- try:
- if len(symbols)==len("".join(symbols)):
- return Regex( "[%s]" % "".join(_escapeRegexRangeChars(sym) for sym in symbols) ).setName(' | '.join(symbols))
+ if not asKeyword:
+ # if not producing keywords, need to reorder to take care to avoid masking
+ # longer choices with shorter ones
+ i = 0
+ while i < len(symbols) - 1:
+ cur = symbols[i]
+ for j, other in enumerate(symbols[i + 1:]):
+ if isequal(other, cur):
+ del symbols[i + j + 1]
+ break
+ elif masks(cur, other):
+ del symbols[i + j + 1]
+ symbols.insert(i, other)
+ break
else:
- return Regex( "|".join(re.escape(sym) for sym in symbols) ).setName(' | '.join(symbols))
+ i += 1
+
+ if not (caseless or asKeyword) and useRegex:
+ # ~ print (strs, "->", "|".join([_escapeRegexChars(sym) for sym in symbols]))
+ try:
+ if len(symbols) == len("".join(symbols)):
+ return Regex("[%s]" % "".join(_escapeRegexRangeChars(sym) for sym in symbols)).setName(' | '.join(symbols))
+ else:
+ return Regex("|".join(re.escape(sym) for sym in symbols)).setName(' | '.join(symbols))
except Exception:
warnings.warn("Exception creating Regex for oneOf, building MatchFirst",
SyntaxWarning, stacklevel=2)
-
# last resort, just use MatchFirst
return MatchFirst(parseElementClass(sym) for sym in symbols).setName(' | '.join(symbols))
-def dictOf( key, value ):
+def dictOf(key, value):
"""Helper to easily and clearly define a dictionary by specifying
the respective patterns for the key and value. Takes care of
defining the :class:`Dict`, :class:`ZeroOrMore`, and
@@ -5189,8 +5604,8 @@ def originalTextFor(expr, asString=True):
Example::
src = "this is test bold text normal text "
- for tag in ("b","i"):
- opener,closer = makeHTMLTags(tag)
+ for tag in ("b", "i"):
+ opener, closer = makeHTMLTags(tag)
patt = originalTextFor(opener + SkipTo(closer) + closer)
print(patt.searchString(src)[0])
@@ -5199,14 +5614,14 @@ def originalTextFor(expr, asString=True):
[' bold text ']
['text ']
"""
- locMarker = Empty().setParseAction(lambda s,loc,t: loc)
+ locMarker = Empty().setParseAction(lambda s, loc, t: loc)
endlocMarker = locMarker.copy()
endlocMarker.callPreparse = False
matchExpr = locMarker("_original_start") + expr + endlocMarker("_original_end")
if asString:
- extractText = lambda s,l,t: s[t._original_start:t._original_end]
+ extractText = lambda s, l, t: s[t._original_start: t._original_end]
else:
- def extractText(s,l,t):
+ def extractText(s, l, t):
t[:] = [s[t.pop('_original_start'):t.pop('_original_end')]]
matchExpr.setParseAction(extractText)
matchExpr.ignoreExprs = expr.ignoreExprs
@@ -5216,7 +5631,7 @@ def ungroup(expr):
"""Helper to undo pyparsing's default grouping of And expressions,
even if all but one are non-empty.
"""
- return TokenConverter(expr).addParseAction(lambda t:t[0])
+ return TokenConverter(expr).addParseAction(lambda t: t[0])
def locatedExpr(expr):
"""Helper to decorate a returned token with its starting and ending
@@ -5243,7 +5658,7 @@ def locatedExpr(expr):
[[8, 'lksdjjf', 15]]
[[18, 'lkkjj', 23]]
"""
- locator = Empty().setParseAction(lambda s,l,t: l)
+ locator = Empty().setParseAction(lambda s, l, t: l)
return Group(locator("locn_start") + expr("value") + locator.copy().leaveWhitespace()("locn_end"))
@@ -5254,12 +5669,12 @@ lineEnd = LineEnd().setName("lineEnd")
stringStart = StringStart().setName("stringStart")
stringEnd = StringEnd().setName("stringEnd")
-_escapedPunc = Word( _bslash, r"\[]-*.$+^?()~ ", exact=2 ).setParseAction(lambda s,l,t:t[0][1])
-_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").setParseAction(lambda s,l,t:unichr(int(t[0].lstrip(r'\0x'),16)))
-_escapedOctChar = Regex(r"\\0[0-7]+").setParseAction(lambda s,l,t:unichr(int(t[0][1:],8)))
+_escapedPunc = Word(_bslash, r"\[]-*.$+^?()~ ", exact=2).setParseAction(lambda s, l, t: t[0][1])
+_escapedHexChar = Regex(r"\\0?[xX][0-9a-fA-F]+").setParseAction(lambda s, l, t: unichr(int(t[0].lstrip(r'\0x'), 16)))
+_escapedOctChar = Regex(r"\\0[0-7]+").setParseAction(lambda s, l, t: unichr(int(t[0][1:], 8)))
_singleChar = _escapedPunc | _escapedHexChar | _escapedOctChar | CharsNotIn(r'\]', exact=1)
_charRange = Group(_singleChar + Suppress("-") + _singleChar)
-_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group( OneOrMore( _charRange | _singleChar ) ).setResultsName("body") + "]"
+_reBracketExpr = Literal("[") + Optional("^").setResultsName("negate") + Group(OneOrMore(_charRange | _singleChar)).setResultsName("body") + "]"
def srange(s):
r"""Helper to easily define string ranges for use in Word
@@ -5287,7 +5702,7 @@ def srange(s):
- any combination of the above (``'aeiouy'``,
``'a-zA-Z0-9_$'``, etc.)
"""
- _expanded = lambda p: p if not isinstance(p,ParseResults) else ''.join(unichr(c) for c in range(ord(p[0]),ord(p[1])+1))
+ _expanded = lambda p: p if not isinstance(p, ParseResults) else ''.join(unichr(c) for c in range(ord(p[0]), ord(p[1]) + 1))
try:
return "".join(_expanded(part) for part in _reBracketExpr.parseString(s).body)
except Exception:
@@ -5297,9 +5712,9 @@ def matchOnlyAtCol(n):
"""Helper method for defining parse actions that require matching at
a specific column in the input text.
"""
- def verifyCol(strg,locn,toks):
- if col(locn,strg) != n:
- raise ParseException(strg,locn,"matched token not at column %d" % n)
+ def verifyCol(strg, locn, toks):
+ if col(locn, strg) != n:
+ raise ParseException(strg, locn, "matched token not at column %d" % n)
return verifyCol
def replaceWith(replStr):
@@ -5315,9 +5730,9 @@ def replaceWith(replStr):
OneOrMore(term).parseString("324 234 N/A 234") # -> [324, 234, nan, 234]
"""
- return lambda s,l,t: [replStr]
+ return lambda s, l, t: [replStr]
-def removeQuotes(s,l,t):
+def removeQuotes(s, l, t):
"""Helper parse action for removing quotation marks from parsed
quoted strings.
@@ -5368,7 +5783,7 @@ def tokenMap(func, *args):
now is the winter of our discontent made glorious summer by this sun of york
['Now Is The Winter Of Our Discontent Made Glorious Summer By This Sun Of York']
"""
- def pa(s,l,t):
+ def pa(s, l, t):
return [func(tokn, *args) for tokn in t]
try:
@@ -5392,34 +5807,34 @@ def _makeTags(tagStr, xml,
suppress_LT=Suppress("<"),
suppress_GT=Suppress(">")):
"""Internal helper to construct opening and closing tag expressions, given a tag name"""
- if isinstance(tagStr,basestring):
+ if isinstance(tagStr, basestring):
resname = tagStr
tagStr = Keyword(tagStr, caseless=not xml)
else:
resname = tagStr.name
- tagAttrName = Word(alphas,alphanums+"_-:")
- if (xml):
- tagAttrValue = dblQuotedString.copy().setParseAction( removeQuotes )
+ tagAttrName = Word(alphas, alphanums + "_-:")
+ if xml:
+ tagAttrValue = dblQuotedString.copy().setParseAction(removeQuotes)
openTag = (suppress_LT
+ tagStr("tag")
- + Dict(ZeroOrMore(Group(tagAttrName + Suppress("=") + tagAttrValue )))
- + Optional("/", default=[False])("empty").setParseAction(lambda s,l,t:t[0]=='/')
+ + Dict(ZeroOrMore(Group(tagAttrName + Suppress("=") + tagAttrValue)))
+ + Optional("/", default=[False])("empty").setParseAction(lambda s, l, t: t[0] == '/')
+ suppress_GT)
else:
- tagAttrValue = quotedString.copy().setParseAction( removeQuotes ) | Word(printables, excludeChars=">")
+ tagAttrValue = quotedString.copy().setParseAction(removeQuotes) | Word(printables, excludeChars=">")
openTag = (suppress_LT
+ tagStr("tag")
+ Dict(ZeroOrMore(Group(tagAttrName.setParseAction(downcaseTokens)
+ Optional(Suppress("=") + tagAttrValue))))
- + Optional("/",default=[False])("empty").setParseAction(lambda s,l,t:t[0]=='/')
+ + Optional("/", default=[False])("empty").setParseAction(lambda s, l, t: t[0] == '/')
+ suppress_GT)
closeTag = Combine(_L("") + tagStr + ">", adjacent=False)
openTag.setName("<%s>" % resname)
# add start results name in parse action now that ungrouped names are not reported at two levels
- openTag.addParseAction(lambda t: t.__setitem__("start"+"".join(resname.replace(":"," ").title().split()), t.copy()))
- closeTag = closeTag("end"+"".join(resname.replace(":"," ").title().split())).setName("%s>" % resname)
+ openTag.addParseAction(lambda t: t.__setitem__("start" + "".join(resname.replace(":", " ").title().split()), t.copy()))
+ closeTag = closeTag("end" + "".join(resname.replace(":", " ").title().split())).setName("%s>" % resname)
openTag.tag = resname
closeTag.tag = resname
openTag.tag_body = SkipTo(closeTag())
@@ -5435,7 +5850,7 @@ def makeHTMLTags(tagStr):
text = 'More info at the pyparsing wiki page '
# makeHTMLTags returns pyparsing expressions for the opening and
# closing tags as a 2-tuple
- a,a_end = makeHTMLTags("A")
+ a, a_end = makeHTMLTags("A")
link_expr = a + SkipTo(a_end)("link_text") + a_end
for link in link_expr.searchString(text):
@@ -5447,7 +5862,7 @@ def makeHTMLTags(tagStr):
pyparsing -> https://github.com/pyparsing/pyparsing/wiki
"""
- return _makeTags( tagStr, False )
+ return _makeTags(tagStr, False)
def makeXMLTags(tagStr):
"""Helper to construct opening and closing tag expressions for XML,
@@ -5455,9 +5870,9 @@ def makeXMLTags(tagStr):
Example: similar to :class:`makeHTMLTags`
"""
- return _makeTags( tagStr, True )
+ return _makeTags(tagStr, True)
-def withAttribute(*args,**attrDict):
+def withAttribute(*args, **attrDict):
"""Helper to create a validating parse action to be used with start
tags created with :class:`makeXMLTags` or
:class:`makeHTMLTags`. Use ``withAttribute`` to qualify
@@ -5470,7 +5885,7 @@ def withAttribute(*args,**attrDict):
- keyword arguments, as in ``(align="right")``, or
- as an explicit dict with ``**`` operator, when an attribute
name is also a Python reserved word, as in ``**{"class":"Customer", "align":"right"}``
- - a list of name-value tuples, as in ``(("ns1:class", "Customer"), ("ns2:align","right"))``
+ - a list of name-value tuples, as in ``(("ns1:class", "Customer"), ("ns2:align", "right"))``
For attribute names with a namespace prefix, you must use the second
form. Attribute names are matched insensitive to upper/lower case.
@@ -5517,13 +5932,13 @@ def withAttribute(*args,**attrDict):
attrs = args[:]
else:
attrs = attrDict.items()
- attrs = [(k,v) for k,v in attrs]
- def pa(s,l,tokens):
- for attrName,attrValue in attrs:
+ attrs = [(k, v) for k, v in attrs]
+ def pa(s, l, tokens):
+ for attrName, attrValue in attrs:
if attrName not in tokens:
- raise ParseException(s,l,"no matching attribute " + attrName)
+ raise ParseException(s, l, "no matching attribute " + attrName)
if attrValue != withAttribute.ANY_VALUE and tokens[attrName] != attrValue:
- raise ParseException(s,l,"attribute '%s' has value '%s', must be '%s'" %
+ raise ParseException(s, l, "attribute '%s' has value '%s', must be '%s'" %
(attrName, tokens[attrName], attrValue))
return pa
withAttribute.ANY_VALUE = object()
@@ -5564,13 +5979,13 @@ def withClass(classname, namespace=''):
1,3 2,3 1,1
"""
classattr = "%s:class" % namespace if namespace else "class"
- return withAttribute(**{classattr : classname})
+ return withAttribute(**{classattr: classname})
opAssoc = SimpleNamespace()
opAssoc.LEFT = object()
opAssoc.RIGHT = object()
-def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ):
+def infixNotation(baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')')):
"""Helper method for constructing grammars of expressions made up of
operators working in a precedence hierarchy. Operators may be unary
or binary, left- or right-associative. Parse actions can also be
@@ -5648,9 +6063,9 @@ def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ):
return loc, []
ret = Forward()
- lastExpr = baseExpr | ( lpar + ret + rpar )
- for i,operDef in enumerate(opList):
- opExpr,arity,rightLeftAssoc,pa = (operDef + (None,))[:4]
+ lastExpr = baseExpr | (lpar + ret + rpar)
+ for i, operDef in enumerate(opList):
+ opExpr, arity, rightLeftAssoc, pa = (operDef + (None, ))[:4]
termName = "%s term" % opExpr if arity < 3 else "%s%s term" % opExpr
if arity == 3:
if opExpr is None or len(opExpr) != 2:
@@ -5660,15 +6075,15 @@ def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ):
thisExpr = Forward().setName(termName)
if rightLeftAssoc == opAssoc.LEFT:
if arity == 1:
- matchExpr = _FB(lastExpr + opExpr) + Group( lastExpr + OneOrMore( opExpr ) )
+ matchExpr = _FB(lastExpr + opExpr) + Group(lastExpr + OneOrMore(opExpr))
elif arity == 2:
if opExpr is not None:
- matchExpr = _FB(lastExpr + opExpr + lastExpr) + Group( lastExpr + OneOrMore( opExpr + lastExpr ) )
+ matchExpr = _FB(lastExpr + opExpr + lastExpr) + Group(lastExpr + OneOrMore(opExpr + lastExpr))
else:
- matchExpr = _FB(lastExpr+lastExpr) + Group( lastExpr + OneOrMore(lastExpr) )
+ matchExpr = _FB(lastExpr + lastExpr) + Group(lastExpr + OneOrMore(lastExpr))
elif arity == 3:
- matchExpr = _FB(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr) + \
- Group( lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr )
+ matchExpr = (_FB(lastExpr + opExpr1 + lastExpr + opExpr2 + lastExpr)
+ + Group(lastExpr + OneOrMore(opExpr1 + lastExpr + opExpr2 + lastExpr)))
else:
raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
elif rightLeftAssoc == opAssoc.RIGHT:
@@ -5676,15 +6091,15 @@ def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ):
# try to avoid LR with this extra test
if not isinstance(opExpr, Optional):
opExpr = Optional(opExpr)
- matchExpr = _FB(opExpr.expr + thisExpr) + Group( opExpr + thisExpr )
+ matchExpr = _FB(opExpr.expr + thisExpr) + Group(opExpr + thisExpr)
elif arity == 2:
if opExpr is not None:
- matchExpr = _FB(lastExpr + opExpr + thisExpr) + Group( lastExpr + OneOrMore( opExpr + thisExpr ) )
+ matchExpr = _FB(lastExpr + opExpr + thisExpr) + Group(lastExpr + OneOrMore(opExpr + thisExpr))
else:
- matchExpr = _FB(lastExpr + thisExpr) + Group( lastExpr + OneOrMore( thisExpr ) )
+ matchExpr = _FB(lastExpr + thisExpr) + Group(lastExpr + OneOrMore(thisExpr))
elif arity == 3:
- matchExpr = _FB(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr) + \
- Group( lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr )
+ matchExpr = (_FB(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr)
+ + Group(lastExpr + opExpr1 + thisExpr + opExpr2 + thisExpr))
else:
raise ValueError("operator must be unary (1), binary (2), or ternary (3)")
else:
@@ -5694,7 +6109,7 @@ def infixNotation( baseExpr, opList, lpar=Suppress('('), rpar=Suppress(')') ):
matchExpr.setParseAction(*pa)
else:
matchExpr.setParseAction(pa)
- thisExpr <<= ( matchExpr.setName(termName) | lastExpr )
+ thisExpr <<= (matchExpr.setName(termName) | lastExpr)
lastExpr = thisExpr
ret <<= lastExpr
return ret
@@ -5703,10 +6118,10 @@ operatorPrecedence = infixNotation
"""(Deprecated) Former name of :class:`infixNotation`, will be
dropped in a future release."""
-dblQuotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"').setName("string enclosed in double quotes")
-sglQuotedString = Combine(Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("string enclosed in single quotes")
-quotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*')+'"'|
- Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*")+"'").setName("quotedString using single or double quotes")
+dblQuotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*') + '"').setName("string enclosed in double quotes")
+sglQuotedString = Combine(Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*") + "'").setName("string enclosed in single quotes")
+quotedString = Combine(Regex(r'"(?:[^"\n\r\\]|(?:"")|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*') + '"'
+ | Regex(r"'(?:[^'\n\r\\]|(?:'')|(?:\\(?:[^x]|x[0-9a-fA-F]+)))*") + "'").setName("quotedString using single or double quotes")
unicodeString = Combine(_L('u') + quotedString.copy()).setName("unicode string literal")
def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.copy()):
@@ -5742,7 +6157,7 @@ def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.cop
ident = Word(alphas+'_', alphanums+'_')
number = pyparsing_common.number
arg = Group(decl_data_type + ident)
- LPAR,RPAR = map(Suppress, "()")
+ LPAR, RPAR = map(Suppress, "()")
code_body = nestedExpr('{', '}', ignoreExpr=(quotedString | cStyleComment))
@@ -5777,33 +6192,40 @@ def nestedExpr(opener="(", closer=")", content=None, ignoreExpr=quotedString.cop
if opener == closer:
raise ValueError("opening and closing strings cannot be the same")
if content is None:
- if isinstance(opener,basestring) and isinstance(closer,basestring):
- if len(opener) == 1 and len(closer)==1:
+ if isinstance(opener, basestring) and isinstance(closer, basestring):
+ if len(opener) == 1 and len(closer) == 1:
if ignoreExpr is not None:
- content = (Combine(OneOrMore(~ignoreExpr +
- CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS,exact=1))
- ).setParseAction(lambda t:t[0].strip()))
+ content = (Combine(OneOrMore(~ignoreExpr
+ + CharsNotIn(opener
+ + closer
+ + ParserElement.DEFAULT_WHITE_CHARS, exact=1)
+ )
+ ).setParseAction(lambda t: t[0].strip()))
else:
- content = (empty.copy()+CharsNotIn(opener+closer+ParserElement.DEFAULT_WHITE_CHARS
- ).setParseAction(lambda t:t[0].strip()))
+ content = (empty.copy() + CharsNotIn(opener
+ + closer
+ + ParserElement.DEFAULT_WHITE_CHARS
+ ).setParseAction(lambda t: t[0].strip()))
else:
if ignoreExpr is not None:
- content = (Combine(OneOrMore(~ignoreExpr +
- ~Literal(opener) + ~Literal(closer) +
- CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))
- ).setParseAction(lambda t:t[0].strip()))
+ content = (Combine(OneOrMore(~ignoreExpr
+ + ~Literal(opener)
+ + ~Literal(closer)
+ + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS, exact=1))
+ ).setParseAction(lambda t: t[0].strip()))
else:
- content = (Combine(OneOrMore(~Literal(opener) + ~Literal(closer) +
- CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS,exact=1))
- ).setParseAction(lambda t:t[0].strip()))
+ content = (Combine(OneOrMore(~Literal(opener)
+ + ~Literal(closer)
+ + CharsNotIn(ParserElement.DEFAULT_WHITE_CHARS, exact=1))
+ ).setParseAction(lambda t: t[0].strip()))
else:
raise ValueError("opening and closing arguments must be strings if no content expression is given")
ret = Forward()
if ignoreExpr is not None:
- ret <<= Group( Suppress(opener) + ZeroOrMore( ignoreExpr | ret | content ) + Suppress(closer) )
+ ret <<= Group(Suppress(opener) + ZeroOrMore(ignoreExpr | ret | content) + Suppress(closer))
else:
- ret <<= Group( Suppress(opener) + ZeroOrMore( ret | content ) + Suppress(closer) )
- ret.setName('nested %s%s expression' % (opener,closer))
+ ret <<= Group(Suppress(opener) + ZeroOrMore(ret | content) + Suppress(closer))
+ ret.setName('nested %s%s expression' % (opener, closer))
return ret
def indentedBlock(blockStatementExpr, indentStack, indent=True):
@@ -5818,7 +6240,7 @@ def indentedBlock(blockStatementExpr, indentStack, indent=True):
(multiple statementWithIndentedBlock expressions within a single
grammar should share a common indentStack)
- indent - boolean indicating whether block must be indented beyond
- the the current level; set to False for block of left-most
+ the current level; set to False for block of left-most
statements (default= ``True``)
A valid block must contain at least one ``blockStatement``.
@@ -5851,15 +6273,15 @@ def indentedBlock(blockStatementExpr, indentStack, indent=True):
stmt = Forward()
identifier = Word(alphas, alphanums)
- funcDecl = ("def" + identifier + Group( "(" + Optional( delimitedList(identifier) ) + ")" ) + ":")
+ funcDecl = ("def" + identifier + Group("(" + Optional(delimitedList(identifier)) + ")") + ":")
func_body = indentedBlock(stmt, indentStack)
- funcDef = Group( funcDecl + func_body )
+ funcDef = Group(funcDecl + func_body)
rvalue = Forward()
funcCall = Group(identifier + "(" + Optional(delimitedList(rvalue)) + ")")
rvalue << (funcCall | identifier | Word(nums))
assignment = Group(identifier + "=" + rvalue)
- stmt << ( funcDef | assignment | identifier )
+ stmt << (funcDef | assignment | identifier)
module_body = OneOrMore(stmt)
@@ -5892,39 +6314,42 @@ def indentedBlock(blockStatementExpr, indentStack, indent=True):
def reset_stack():
indentStack[:] = backup_stack
- def checkPeerIndent(s,l,t):
+ def checkPeerIndent(s, l, t):
if l >= len(s): return
- curCol = col(l,s)
+ curCol = col(l, s)
if curCol != indentStack[-1]:
if curCol > indentStack[-1]:
- raise ParseException(s,l,"illegal nesting")
- raise ParseException(s,l,"not a peer entry")
+ raise ParseException(s, l, "illegal nesting")
+ raise ParseException(s, l, "not a peer entry")
- def checkSubIndent(s,l,t):
- curCol = col(l,s)
+ def checkSubIndent(s, l, t):
+ curCol = col(l, s)
if curCol > indentStack[-1]:
- indentStack.append( curCol )
+ indentStack.append(curCol)
else:
- raise ParseException(s,l,"not a subentry")
+ raise ParseException(s, l, "not a subentry")
- def checkUnindent(s,l,t):
+ def checkUnindent(s, l, t):
if l >= len(s): return
- curCol = col(l,s)
- if not(indentStack and curCol < indentStack[-1] and curCol <= indentStack[-2]):
- raise ParseException(s,l,"not an unindent")
- indentStack.pop()
+ curCol = col(l, s)
+ if not(indentStack and curCol in indentStack):
+ raise ParseException(s, l, "not an unindent")
+ if curCol < indentStack[-1]:
+ indentStack.pop()
- NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress())
+ NL = OneOrMore(LineEnd().setWhitespaceChars("\t ").suppress(), stopOn=StringEnd())
INDENT = (Empty() + Empty().setParseAction(checkSubIndent)).setName('INDENT')
PEER = Empty().setParseAction(checkPeerIndent).setName('')
UNDENT = Empty().setParseAction(checkUnindent).setName('UNINDENT')
if indent:
- smExpr = Group( Optional(NL) +
- #~ FollowedBy(blockStatementExpr) +
- INDENT + (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) + UNDENT)
+ smExpr = Group(Optional(NL)
+ + INDENT
+ + OneOrMore(PEER + Group(blockStatementExpr) + Optional(NL), stopOn=StringEnd())
+ + UNDENT)
else:
- smExpr = Group( Optional(NL) +
- (OneOrMore( PEER + Group(blockStatementExpr) + Optional(NL) )) )
+ smExpr = Group(Optional(NL)
+ + OneOrMore(PEER + Group(blockStatementExpr) + Optional(NL), stopOn=StringEnd())
+ + UNDENT)
smExpr.setFailAction(lambda a, b, c, d: reset_stack())
blockStatementExpr.ignore(_bslash + LineEnd())
return smExpr.setName('indented block')
@@ -5932,8 +6357,8 @@ def indentedBlock(blockStatementExpr, indentStack, indent=True):
alphas8bit = srange(r"[\0xc0-\0xd6\0xd8-\0xf6\0xf8-\0xff]")
punc8bit = srange(r"[\0xa1-\0xbf\0xd7\0xf7]")
-anyOpenTag,anyCloseTag = makeHTMLTags(Word(alphas,alphanums+"_:").setName('any tag'))
-_htmlEntityMap = dict(zip("gt lt amp nbsp quot apos".split(),'><& "\''))
+anyOpenTag, anyCloseTag = makeHTMLTags(Word(alphas, alphanums + "_:").setName('any tag'))
+_htmlEntityMap = dict(zip("gt lt amp nbsp quot apos".split(), '><& "\''))
commonHTMLEntity = Regex('&(?P' + '|'.join(_htmlEntityMap.keys()) +");").setName("common HTML entity")
def replaceHTMLEntity(t):
"""Helper parser action to replace common HTML entities with their special characters"""
@@ -5950,7 +6375,7 @@ restOfLine = Regex(r".*").leaveWhitespace().setName("rest of line")
dblSlashComment = Regex(r"//(?:\\\n|[^\n])*").setName("// comment")
"Comment of the form ``// ... (to end of line)``"
-cppStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/'| dblSlashComment).setName("C++ style comment")
+cppStyleComment = Combine(Regex(r"/\*(?:[^*]|\*(?!/))*") + '*/' | dblSlashComment).setName("C++ style comment")
"Comment of either form :class:`cStyleComment` or :class:`dblSlashComment`"
javaStyleComment = cppStyleComment
@@ -5959,10 +6384,10 @@ javaStyleComment = cppStyleComment
pythonStyleComment = Regex(r"#.*").setName("Python style comment")
"Comment of the form ``# ... (to end of line)``"
-_commasepitem = Combine(OneOrMore(Word(printables, excludeChars=',') +
- Optional( Word(" \t") +
- ~Literal(",") + ~LineEnd() ) ) ).streamline().setName("commaItem")
-commaSeparatedList = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("commaSeparatedList")
+_commasepitem = Combine(OneOrMore(Word(printables, excludeChars=',')
+ + Optional(Word(" \t")
+ + ~Literal(",") + ~LineEnd()))).streamline().setName("commaItem")
+commaSeparatedList = delimitedList(Optional(quotedString.copy() | _commasepitem, default="")).setName("commaSeparatedList")
"""(Deprecated) Predefined expression of 1 or more printable words or
quoted strings, separated by commas.
@@ -6128,7 +6553,7 @@ class pyparsing_common:
integer = Word(nums).setName("integer").setParseAction(convertToInteger)
"""expression that parses an unsigned integer, returns an int"""
- hex_integer = Word(hexnums).setName("hex integer").setParseAction(tokenMap(int,16))
+ hex_integer = Word(hexnums).setName("hex integer").setParseAction(tokenMap(int, 16))
"""expression that parses a hexadecimal integer, returns an int"""
signed_integer = Regex(r'[+-]?\d+').setName("signed integer").setParseAction(convertToInteger)
@@ -6142,10 +6567,10 @@ class pyparsing_common:
"""mixed integer of the form 'integer - fraction', with optional leading integer, returns float"""
mixed_integer.addParseAction(sum)
- real = Regex(r'[+-]?\d+\.\d*').setName("real number").setParseAction(convertToFloat)
+ real = Regex(r'[+-]?(?:\d+\.\d*|\.\d+)').setName("real number").setParseAction(convertToFloat)
"""expression that parses a floating point number and returns a float"""
- sci_real = Regex(r'[+-]?\d+([eE][+-]?\d+|\.\d*([eE][+-]?\d+)?)').setName("real number with scientific notation").setParseAction(convertToFloat)
+ sci_real = Regex(r'[+-]?(?:\d+(?:[eE][+-]?\d+)|(?:\d+\.\d*|\.\d+)(?:[eE][+-]?\d+)?)').setName("real number with scientific notation").setParseAction(convertToFloat)
"""expression that parses a floating point number with optional
scientific notation and returns a float"""
@@ -6156,15 +6581,18 @@ class pyparsing_common:
fnumber = Regex(r'[+-]?\d+\.?\d*([eE][+-]?\d+)?').setName("fnumber").setParseAction(convertToFloat)
"""any int or real number, returned as float"""
- identifier = Word(alphas+'_', alphanums+'_').setName("identifier")
+ identifier = Word(alphas + '_', alphanums + '_').setName("identifier")
"""typical code identifier (leading alpha or '_', followed by 0 or more alphas, nums, or '_')"""
ipv4_address = Regex(r'(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})(\.(25[0-5]|2[0-4][0-9]|1?[0-9]{1,2})){3}').setName("IPv4 address")
"IPv4 address (``0.0.0.0 - 255.255.255.255``)"
_ipv6_part = Regex(r'[0-9a-fA-F]{1,4}').setName("hex_integer")
- _full_ipv6_address = (_ipv6_part + (':' + _ipv6_part)*7).setName("full IPv6 address")
- _short_ipv6_address = (Optional(_ipv6_part + (':' + _ipv6_part)*(0,6)) + "::" + Optional(_ipv6_part + (':' + _ipv6_part)*(0,6))).setName("short IPv6 address")
+ _full_ipv6_address = (_ipv6_part + (':' + _ipv6_part) * 7).setName("full IPv6 address")
+ _short_ipv6_address = (Optional(_ipv6_part + (':' + _ipv6_part) * (0, 6))
+ + "::"
+ + Optional(_ipv6_part + (':' + _ipv6_part) * (0, 6))
+ ).setName("short IPv6 address")
_short_ipv6_address.addCondition(lambda t: sum(1 for tt in t if pyparsing_common._ipv6_part.matches(tt)) < 8)
_mixed_ipv6_address = ("::ffff:" + ipv4_address).setName("mixed IPv6 address")
ipv6_address = Combine((_full_ipv6_address | _mixed_ipv6_address | _short_ipv6_address).setName("IPv6 address")).setName("IPv6 address")
@@ -6191,7 +6619,7 @@ class pyparsing_common:
[datetime.date(1999, 12, 31)]
"""
- def cvt_fn(s,l,t):
+ def cvt_fn(s, l, t):
try:
return datetime.strptime(t[0], fmt).date()
except ValueError as ve:
@@ -6216,7 +6644,7 @@ class pyparsing_common:
[datetime.datetime(1999, 12, 31, 23, 59, 59, 999000)]
"""
- def cvt_fn(s,l,t):
+ def cvt_fn(s, l, t):
try:
return datetime.strptime(t[0], fmt)
except ValueError as ve:
@@ -6241,7 +6669,7 @@ class pyparsing_common:
# strip HTML links from normal text
text = 'More info at the pyparsing wiki page '
- td,td_end = makeHTMLTags("TD")
+ td, td_end = makeHTMLTags("TD")
table_text = td + SkipTo(td_end).setParseAction(pyparsing_common.stripHTMLTags)("body") + td_end
print(table_text.parseString(text).body)
@@ -6251,9 +6679,13 @@ class pyparsing_common:
"""
return pyparsing_common._html_stripper.transformString(tokens[0])
- _commasepitem = Combine(OneOrMore(~Literal(",") + ~LineEnd() + Word(printables, excludeChars=',')
- + Optional( White(" \t") ) ) ).streamline().setName("commaItem")
- comma_separated_list = delimitedList( Optional( quotedString.copy() | _commasepitem, default="") ).setName("comma separated list")
+ _commasepitem = Combine(OneOrMore(~Literal(",")
+ + ~LineEnd()
+ + Word(printables, excludeChars=',')
+ + Optional(White(" \t")))).streamline().setName("commaItem")
+ comma_separated_list = delimitedList(Optional(quotedString.copy()
+ | _commasepitem, default='')
+ ).setName("comma separated list")
"""Predefined expression of 1 or more printable words or quoted strings, separated by commas."""
upcaseTokens = staticmethod(tokenMap(lambda t: _ustr(t).upper()))
@@ -6272,7 +6704,8 @@ class _lazyclassproperty(object):
def __get__(self, obj, cls):
if cls is None:
cls = type(obj)
- if not hasattr(cls, '_intern') or any(cls._intern is getattr(superclass, '_intern', []) for superclass in cls.__mro__[1:]):
+ if not hasattr(cls, '_intern') or any(cls._intern is getattr(superclass, '_intern', [])
+ for superclass in cls.__mro__[1:]):
cls._intern = {}
attrname = self.fn.__name__
if attrname not in cls._intern:
@@ -6303,7 +6736,7 @@ class unicode_set(object):
if cc is unicode_set:
break
for rr in cc._ranges:
- ret.extend(range(rr[0], rr[-1]+1))
+ ret.extend(range(rr[0], rr[-1] + 1))
return [unichr(c) for c in sorted(set(ret))]
@_lazyclassproperty
@@ -6359,27 +6792,27 @@ class pyparsing_unicode(unicode_set):
class Chinese(unicode_set):
"Unicode set for Chinese Unicode Character Range"
- _ranges = [(0x4e00, 0x9fff), (0x3000, 0x303f), ]
+ _ranges = [(0x4e00, 0x9fff), (0x3000, 0x303f),]
class Japanese(unicode_set):
"Unicode set for Japanese Unicode Character Range, combining Kanji, Hiragana, and Katakana ranges"
- _ranges = [ ]
+ _ranges = []
class Kanji(unicode_set):
"Unicode set for Kanji Unicode Character Range"
- _ranges = [(0x4E00, 0x9Fbf), (0x3000, 0x303f), ]
+ _ranges = [(0x4E00, 0x9Fbf), (0x3000, 0x303f),]
class Hiragana(unicode_set):
"Unicode set for Hiragana Unicode Character Range"
- _ranges = [(0x3040, 0x309f), ]
+ _ranges = [(0x3040, 0x309f),]
class Katakana(unicode_set):
"Unicode set for Katakana Unicode Character Range"
- _ranges = [(0x30a0, 0x30ff), ]
+ _ranges = [(0x30a0, 0x30ff),]
class Korean(unicode_set):
"Unicode set for Korean Unicode Character Range"
- _ranges = [(0xac00, 0xd7af), (0x1100, 0x11ff), (0x3130, 0x318f), (0xa960, 0xa97f), (0xd7b0, 0xd7ff), (0x3000, 0x303f), ]
+ _ranges = [(0xac00, 0xd7af), (0x1100, 0x11ff), (0x3130, 0x318f), (0xa960, 0xa97f), (0xd7b0, 0xd7ff), (0x3000, 0x303f),]
class CJK(Chinese, Japanese, Korean):
"Unicode set for combined Chinese, Japanese, and Korean (CJK) Unicode Character Range"
@@ -6387,15 +6820,15 @@ class pyparsing_unicode(unicode_set):
class Thai(unicode_set):
"Unicode set for Thai Unicode Character Range"
- _ranges = [(0x0e01, 0x0e3a), (0x0e3f, 0x0e5b), ]
+ _ranges = [(0x0e01, 0x0e3a), (0x0e3f, 0x0e5b),]
class Arabic(unicode_set):
"Unicode set for Arabic Unicode Character Range"
- _ranges = [(0x0600, 0x061b), (0x061e, 0x06ff), (0x0700, 0x077f), ]
+ _ranges = [(0x0600, 0x061b), (0x061e, 0x06ff), (0x0700, 0x077f),]
class Hebrew(unicode_set):
"Unicode set for Hebrew Unicode Character Range"
- _ranges = [(0x0590, 0x05ff), ]
+ _ranges = [(0x0590, 0x05ff),]
class Devanagari(unicode_set):
"Unicode set for Devanagari Unicode Character Range"
@@ -6407,18 +6840,199 @@ pyparsing_unicode.Japanese._ranges = (pyparsing_unicode.Japanese.Kanji._ranges
# define ranges in language character sets
if PY_3:
- setattr(pyparsing_unicode, "العربية", pyparsing_unicode.Arabic)
- setattr(pyparsing_unicode, "中文", pyparsing_unicode.Chinese)
- setattr(pyparsing_unicode, "кириллица", pyparsing_unicode.Cyrillic)
- setattr(pyparsing_unicode, "Ελληνικά", pyparsing_unicode.Greek)
- setattr(pyparsing_unicode, "עִברִית", pyparsing_unicode.Hebrew)
- setattr(pyparsing_unicode, "日本語", pyparsing_unicode.Japanese)
- setattr(pyparsing_unicode.Japanese, "漢字", pyparsing_unicode.Japanese.Kanji)
- setattr(pyparsing_unicode.Japanese, "カタカナ", pyparsing_unicode.Japanese.Katakana)
- setattr(pyparsing_unicode.Japanese, "ひらがな", pyparsing_unicode.Japanese.Hiragana)
- setattr(pyparsing_unicode, "한국어", pyparsing_unicode.Korean)
- setattr(pyparsing_unicode, "ไทย", pyparsing_unicode.Thai)
- setattr(pyparsing_unicode, "देवनागरी", pyparsing_unicode.Devanagari)
+ setattr(pyparsing_unicode, u"العربية", pyparsing_unicode.Arabic)
+ setattr(pyparsing_unicode, u"中文", pyparsing_unicode.Chinese)
+ setattr(pyparsing_unicode, u"кириллица", pyparsing_unicode.Cyrillic)
+ setattr(pyparsing_unicode, u"Ελληνικά", pyparsing_unicode.Greek)
+ setattr(pyparsing_unicode, u"עִברִית", pyparsing_unicode.Hebrew)
+ setattr(pyparsing_unicode, u"日本語", pyparsing_unicode.Japanese)
+ setattr(pyparsing_unicode.Japanese, u"漢字", pyparsing_unicode.Japanese.Kanji)
+ setattr(pyparsing_unicode.Japanese, u"カタカナ", pyparsing_unicode.Japanese.Katakana)
+ setattr(pyparsing_unicode.Japanese, u"ひらがな", pyparsing_unicode.Japanese.Hiragana)
+ setattr(pyparsing_unicode, u"한국어", pyparsing_unicode.Korean)
+ setattr(pyparsing_unicode, u"ไทย", pyparsing_unicode.Thai)
+ setattr(pyparsing_unicode, u"देवनागरी", pyparsing_unicode.Devanagari)
+
+
+class pyparsing_test:
+ """
+ namespace class for classes useful in writing unit tests
+ """
+
+ class reset_pyparsing_context:
+ """
+ Context manager to be used when writing unit tests that modify pyparsing config values:
+ - packrat parsing
+ - default whitespace characters.
+ - default keyword characters
+ - literal string auto-conversion class
+ - __diag__ settings
+
+ Example:
+ with reset_pyparsing_context():
+ # test that literals used to construct a grammar are automatically suppressed
+ ParserElement.inlineLiteralsUsing(Suppress)
+
+ term = Word(alphas) | Word(nums)
+ group = Group('(' + term[...] + ')')
+
+ # assert that the '()' characters are not included in the parsed tokens
+ self.assertParseAndCheckLisst(group, "(abc 123 def)", ['abc', '123', 'def'])
+
+ # after exiting context manager, literals are converted to Literal expressions again
+ """
+
+ def __init__(self):
+ self._save_context = {}
+
+ def save(self):
+ self._save_context["default_whitespace"] = ParserElement.DEFAULT_WHITE_CHARS
+ self._save_context["default_keyword_chars"] = Keyword.DEFAULT_KEYWORD_CHARS
+ self._save_context[
+ "literal_string_class"
+ ] = ParserElement._literalStringClass
+ self._save_context["packrat_enabled"] = ParserElement._packratEnabled
+ self._save_context["packrat_parse"] = ParserElement._parse
+ self._save_context["__diag__"] = {
+ name: getattr(__diag__, name) for name in __diag__._all_names
+ }
+ self._save_context["__compat__"] = {
+ "collect_all_And_tokens": __compat__.collect_all_And_tokens
+ }
+ return self
+
+ def restore(self):
+ # reset pyparsing global state
+ if (
+ ParserElement.DEFAULT_WHITE_CHARS
+ != self._save_context["default_whitespace"]
+ ):
+ ParserElement.setDefaultWhitespaceChars(
+ self._save_context["default_whitespace"]
+ )
+ Keyword.DEFAULT_KEYWORD_CHARS = self._save_context["default_keyword_chars"]
+ ParserElement.inlineLiteralsUsing(
+ self._save_context["literal_string_class"]
+ )
+ for name, value in self._save_context["__diag__"].items():
+ setattr(__diag__, name, value)
+ ParserElement._packratEnabled = self._save_context["packrat_enabled"]
+ ParserElement._parse = self._save_context["packrat_parse"]
+ __compat__.collect_all_And_tokens = self._save_context["__compat__"]
+
+ def __enter__(self):
+ return self.save()
+
+ def __exit__(self, *args):
+ return self.restore()
+
+ class TestParseResultsAsserts:
+ """
+ A mixin class to add parse results assertion methods to normal unittest.TestCase classes.
+ """
+ def assertParseResultsEquals(
+ self, result, expected_list=None, expected_dict=None, msg=None
+ ):
+ """
+ Unit test assertion to compare a ParseResults object with an optional expected_list,
+ and compare any defined results names with an optional expected_dict.
+ """
+ if expected_list is not None:
+ self.assertEqual(expected_list, result.asList(), msg=msg)
+ if expected_dict is not None:
+ self.assertEqual(expected_dict, result.asDict(), msg=msg)
+
+ def assertParseAndCheckList(
+ self, expr, test_string, expected_list, msg=None, verbose=True
+ ):
+ """
+ Convenience wrapper assert to test a parser element and input string, and assert that
+ the resulting ParseResults.asList() is equal to the expected_list.
+ """
+ result = expr.parseString(test_string, parseAll=True)
+ if verbose:
+ print(result.dump())
+ self.assertParseResultsEquals(result, expected_list=expected_list, msg=msg)
+
+ def assertParseAndCheckDict(
+ self, expr, test_string, expected_dict, msg=None, verbose=True
+ ):
+ """
+ Convenience wrapper assert to test a parser element and input string, and assert that
+ the resulting ParseResults.asDict() is equal to the expected_dict.
+ """
+ result = expr.parseString(test_string, parseAll=True)
+ if verbose:
+ print(result.dump())
+ self.assertParseResultsEquals(result, expected_dict=expected_dict, msg=msg)
+
+ def assertRunTestResults(
+ self, run_tests_report, expected_parse_results=None, msg=None
+ ):
+ """
+ Unit test assertion to evaluate output of ParserElement.runTests(). If a list of
+ list-dict tuples is given as the expected_parse_results argument, then these are zipped
+ with the report tuples returned by runTests and evaluated using assertParseResultsEquals.
+ Finally, asserts that the overall runTests() success value is True.
+
+ :param run_tests_report: tuple(bool, [tuple(str, ParseResults or Exception)]) returned from runTests
+ :param expected_parse_results (optional): [tuple(str, list, dict, Exception)]
+ """
+ run_test_success, run_test_results = run_tests_report
+
+ if expected_parse_results is not None:
+ merged = [
+ (rpt[0], rpt[1], expected)
+ for rpt, expected in zip(run_test_results, expected_parse_results)
+ ]
+ for test_string, result, expected in merged:
+ # expected should be a tuple containing a list and/or a dict or an exception,
+ # and optional failure message string
+ # an empty tuple will skip any result validation
+ fail_msg = next(
+ (exp for exp in expected if isinstance(exp, str)), None
+ )
+ expected_exception = next(
+ (
+ exp
+ for exp in expected
+ if isinstance(exp, type) and issubclass(exp, Exception)
+ ),
+ None,
+ )
+ if expected_exception is not None:
+ with self.assertRaises(
+ expected_exception=expected_exception, msg=fail_msg or msg
+ ):
+ if isinstance(result, Exception):
+ raise result
+ else:
+ expected_list = next(
+ (exp for exp in expected if isinstance(exp, list)), None
+ )
+ expected_dict = next(
+ (exp for exp in expected if isinstance(exp, dict)), None
+ )
+ if (expected_list, expected_dict) != (None, None):
+ self.assertParseResultsEquals(
+ result,
+ expected_list=expected_list,
+ expected_dict=expected_dict,
+ msg=fail_msg or msg,
+ )
+ else:
+ # warning here maybe?
+ print("no validation for {!r}".format(test_string))
+
+ # do this last, in case some specific test results can be reported instead
+ self.assertTrue(
+ run_test_success, msg=msg if msg is not None else "failed runTests"
+ )
+
+ @contextmanager
+ def assertRaisesParseException(self, exc_type=ParseException, msg=None):
+ with self.assertRaises(exc_type, msg=msg):
+ yield
if __name__ == "__main__":
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__init__.py
deleted file mode 100644
index 8ed060f..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from .core import TomlError
-from .parser import load, loads
-from .test import translate_to_test
-from .writer import dump, dumps
\ No newline at end of file
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__pycache__/__init__.cpython-38.pyc
deleted file mode 100644
index 0399b6e..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__pycache__/__init__.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__pycache__/core.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__pycache__/core.cpython-38.pyc
deleted file mode 100644
index 7015fff..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__pycache__/core.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__pycache__/parser.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__pycache__/parser.cpython-38.pyc
deleted file mode 100644
index 3d691be..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__pycache__/parser.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__pycache__/test.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__pycache__/test.cpython-38.pyc
deleted file mode 100644
index e208799..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__pycache__/test.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__pycache__/utils.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__pycache__/utils.cpython-38.pyc
deleted file mode 100644
index f6f9254..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__pycache__/utils.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__pycache__/writer.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__pycache__/writer.cpython-38.pyc
deleted file mode 100644
index 82c5535..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/__pycache__/writer.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/core.py b/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/core.py
deleted file mode 100644
index c182734..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/core.py
+++ /dev/null
@@ -1,13 +0,0 @@
-class TomlError(RuntimeError):
- def __init__(self, message, line, col, filename):
- RuntimeError.__init__(self, message, line, col, filename)
- self.message = message
- self.line = line
- self.col = col
- self.filename = filename
-
- def __str__(self):
- return '{}({}, {}): {}'.format(self.filename, self.line, self.col, self.message)
-
- def __repr__(self):
- return 'TomlError({!r}, {!r}, {!r}, {!r})'.format(self.message, self.line, self.col, self.filename)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/parser.py b/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/parser.py
deleted file mode 100644
index 3493aa6..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/parser.py
+++ /dev/null
@@ -1,341 +0,0 @@
-import string, re, sys, datetime
-from .core import TomlError
-from .utils import rfc3339_re, parse_rfc3339_re
-
-if sys.version_info[0] == 2:
- _chr = unichr
-else:
- _chr = chr
-
-def load(fin, translate=lambda t, x, v: v, object_pairs_hook=dict):
- return loads(fin.read(), translate=translate, object_pairs_hook=object_pairs_hook, filename=getattr(fin, 'name', repr(fin)))
-
-def loads(s, filename='', translate=lambda t, x, v: v, object_pairs_hook=dict):
- if isinstance(s, bytes):
- s = s.decode('utf-8')
-
- s = s.replace('\r\n', '\n')
-
- root = object_pairs_hook()
- tables = object_pairs_hook()
- scope = root
-
- src = _Source(s, filename=filename)
- ast = _p_toml(src, object_pairs_hook=object_pairs_hook)
-
- def error(msg):
- raise TomlError(msg, pos[0], pos[1], filename)
-
- def process_value(v, object_pairs_hook):
- kind, text, value, pos = v
- if kind == 'str' and value.startswith('\n'):
- value = value[1:]
- if kind == 'array':
- if value and any(k != value[0][0] for k, t, v, p in value[1:]):
- error('array-type-mismatch')
- value = [process_value(item, object_pairs_hook=object_pairs_hook) for item in value]
- elif kind == 'table':
- value = object_pairs_hook([(k, process_value(value[k], object_pairs_hook=object_pairs_hook)) for k in value])
- return translate(kind, text, value)
-
- for kind, value, pos in ast:
- if kind == 'kv':
- k, v = value
- if k in scope:
- error('duplicate_keys. Key "{0}" was used more than once.'.format(k))
- scope[k] = process_value(v, object_pairs_hook=object_pairs_hook)
- else:
- is_table_array = (kind == 'table_array')
- cur = tables
- for name in value[:-1]:
- if isinstance(cur.get(name), list):
- d, cur = cur[name][-1]
- else:
- d, cur = cur.setdefault(name, (None, object_pairs_hook()))
-
- scope = object_pairs_hook()
- name = value[-1]
- if name not in cur:
- if is_table_array:
- cur[name] = [(scope, object_pairs_hook())]
- else:
- cur[name] = (scope, object_pairs_hook())
- elif isinstance(cur[name], list):
- if not is_table_array:
- error('table_type_mismatch')
- cur[name].append((scope, object_pairs_hook()))
- else:
- if is_table_array:
- error('table_type_mismatch')
- old_scope, next_table = cur[name]
- if old_scope is not None:
- error('duplicate_tables')
- cur[name] = (scope, next_table)
-
- def merge_tables(scope, tables):
- if scope is None:
- scope = object_pairs_hook()
- for k in tables:
- if k in scope:
- error('key_table_conflict')
- v = tables[k]
- if isinstance(v, list):
- scope[k] = [merge_tables(sc, tbl) for sc, tbl in v]
- else:
- scope[k] = merge_tables(v[0], v[1])
- return scope
-
- return merge_tables(root, tables)
-
-class _Source:
- def __init__(self, s, filename=None):
- self.s = s
- self._pos = (1, 1)
- self._last = None
- self._filename = filename
- self.backtrack_stack = []
-
- def last(self):
- return self._last
-
- def pos(self):
- return self._pos
-
- def fail(self):
- return self._expect(None)
-
- def consume_dot(self):
- if self.s:
- self._last = self.s[0]
- self.s = self[1:]
- self._advance(self._last)
- return self._last
- return None
-
- def expect_dot(self):
- return self._expect(self.consume_dot())
-
- def consume_eof(self):
- if not self.s:
- self._last = ''
- return True
- return False
-
- def expect_eof(self):
- return self._expect(self.consume_eof())
-
- def consume(self, s):
- if self.s.startswith(s):
- self.s = self.s[len(s):]
- self._last = s
- self._advance(s)
- return True
- return False
-
- def expect(self, s):
- return self._expect(self.consume(s))
-
- def consume_re(self, re):
- m = re.match(self.s)
- if m:
- self.s = self.s[len(m.group(0)):]
- self._last = m
- self._advance(m.group(0))
- return m
- return None
-
- def expect_re(self, re):
- return self._expect(self.consume_re(re))
-
- def __enter__(self):
- self.backtrack_stack.append((self.s, self._pos))
-
- def __exit__(self, type, value, traceback):
- if type is None:
- self.backtrack_stack.pop()
- else:
- self.s, self._pos = self.backtrack_stack.pop()
- return type == TomlError
-
- def commit(self):
- self.backtrack_stack[-1] = (self.s, self._pos)
-
- def _expect(self, r):
- if not r:
- raise TomlError('msg', self._pos[0], self._pos[1], self._filename)
- return r
-
- def _advance(self, s):
- suffix_pos = s.rfind('\n')
- if suffix_pos == -1:
- self._pos = (self._pos[0], self._pos[1] + len(s))
- else:
- self._pos = (self._pos[0] + s.count('\n'), len(s) - suffix_pos)
-
-_ews_re = re.compile(r'(?:[ \t]|#[^\n]*\n|#[^\n]*\Z|\n)*')
-def _p_ews(s):
- s.expect_re(_ews_re)
-
-_ws_re = re.compile(r'[ \t]*')
-def _p_ws(s):
- s.expect_re(_ws_re)
-
-_escapes = { 'b': '\b', 'n': '\n', 'r': '\r', 't': '\t', '"': '"',
- '\\': '\\', 'f': '\f' }
-
-_basicstr_re = re.compile(r'[^"\\\000-\037]*')
-_short_uni_re = re.compile(r'u([0-9a-fA-F]{4})')
-_long_uni_re = re.compile(r'U([0-9a-fA-F]{8})')
-_escapes_re = re.compile(r'[btnfr\"\\]')
-_newline_esc_re = re.compile('\n[ \t\n]*')
-def _p_basicstr_content(s, content=_basicstr_re):
- res = []
- while True:
- res.append(s.expect_re(content).group(0))
- if not s.consume('\\'):
- break
- if s.consume_re(_newline_esc_re):
- pass
- elif s.consume_re(_short_uni_re) or s.consume_re(_long_uni_re):
- v = int(s.last().group(1), 16)
- if 0xd800 <= v < 0xe000:
- s.fail()
- res.append(_chr(v))
- else:
- s.expect_re(_escapes_re)
- res.append(_escapes[s.last().group(0)])
- return ''.join(res)
-
-_key_re = re.compile(r'[0-9a-zA-Z-_]+')
-def _p_key(s):
- with s:
- s.expect('"')
- r = _p_basicstr_content(s, _basicstr_re)
- s.expect('"')
- return r
- if s.consume('\''):
- if s.consume('\'\''):
- r = s.expect_re(_litstr_ml_re).group(0)
- s.expect('\'\'\'')
- else:
- r = s.expect_re(_litstr_re).group(0)
- s.expect('\'')
- return r
- return s.expect_re(_key_re).group(0)
-
-_float_re = re.compile(r'[+-]?(?:0|[1-9](?:_?\d)*)(?:\.\d(?:_?\d)*)?(?:[eE][+-]?(?:\d(?:_?\d)*))?')
-
-_basicstr_ml_re = re.compile(r'(?:""?(?!")|[^"\\\000-\011\013-\037])*')
-_litstr_re = re.compile(r"[^'\000\010\012-\037]*")
-_litstr_ml_re = re.compile(r"(?:(?:|'|'')(?:[^'\000-\010\013-\037]))*")
-def _p_value(s, object_pairs_hook):
- pos = s.pos()
-
- if s.consume('true'):
- return 'bool', s.last(), True, pos
- if s.consume('false'):
- return 'bool', s.last(), False, pos
-
- if s.consume('"'):
- if s.consume('""'):
- r = _p_basicstr_content(s, _basicstr_ml_re)
- s.expect('"""')
- else:
- r = _p_basicstr_content(s, _basicstr_re)
- s.expect('"')
- return 'str', r, r, pos
-
- if s.consume('\''):
- if s.consume('\'\''):
- r = s.expect_re(_litstr_ml_re).group(0)
- s.expect('\'\'\'')
- else:
- r = s.expect_re(_litstr_re).group(0)
- s.expect('\'')
- return 'str', r, r, pos
-
- if s.consume_re(rfc3339_re):
- m = s.last()
- return 'datetime', m.group(0), parse_rfc3339_re(m), pos
-
- if s.consume_re(_float_re):
- m = s.last().group(0)
- r = m.replace('_','')
- if '.' in m or 'e' in m or 'E' in m:
- return 'float', m, float(r), pos
- else:
- return 'int', m, int(r, 10), pos
-
- if s.consume('['):
- items = []
- with s:
- while True:
- _p_ews(s)
- items.append(_p_value(s, object_pairs_hook=object_pairs_hook))
- s.commit()
- _p_ews(s)
- s.expect(',')
- s.commit()
- _p_ews(s)
- s.expect(']')
- return 'array', None, items, pos
-
- if s.consume('{'):
- _p_ws(s)
- items = object_pairs_hook()
- if not s.consume('}'):
- k = _p_key(s)
- _p_ws(s)
- s.expect('=')
- _p_ws(s)
- items[k] = _p_value(s, object_pairs_hook=object_pairs_hook)
- _p_ws(s)
- while s.consume(','):
- _p_ws(s)
- k = _p_key(s)
- _p_ws(s)
- s.expect('=')
- _p_ws(s)
- items[k] = _p_value(s, object_pairs_hook=object_pairs_hook)
- _p_ws(s)
- s.expect('}')
- return 'table', None, items, pos
-
- s.fail()
-
-def _p_stmt(s, object_pairs_hook):
- pos = s.pos()
- if s.consume( '['):
- is_array = s.consume('[')
- _p_ws(s)
- keys = [_p_key(s)]
- _p_ws(s)
- while s.consume('.'):
- _p_ws(s)
- keys.append(_p_key(s))
- _p_ws(s)
- s.expect(']')
- if is_array:
- s.expect(']')
- return 'table_array' if is_array else 'table', keys, pos
-
- key = _p_key(s)
- _p_ws(s)
- s.expect('=')
- _p_ws(s)
- value = _p_value(s, object_pairs_hook=object_pairs_hook)
- return 'kv', (key, value), pos
-
-_stmtsep_re = re.compile(r'(?:[ \t]*(?:#[^\n]*)?\n)+[ \t]*')
-def _p_toml(s, object_pairs_hook):
- stmts = []
- _p_ews(s)
- with s:
- stmts.append(_p_stmt(s, object_pairs_hook=object_pairs_hook))
- while True:
- s.commit()
- s.expect_re(_stmtsep_re)
- stmts.append(_p_stmt(s, object_pairs_hook=object_pairs_hook))
- _p_ews(s)
- s.expect_eof()
- return stmts
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/test.py b/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/test.py
deleted file mode 100644
index ec8abfc..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/test.py
+++ /dev/null
@@ -1,30 +0,0 @@
-import datetime
-from .utils import format_rfc3339
-
-try:
- _string_types = (str, unicode)
- _int_types = (int, long)
-except NameError:
- _string_types = str
- _int_types = int
-
-def translate_to_test(v):
- if isinstance(v, dict):
- return { k: translate_to_test(v) for k, v in v.items() }
- if isinstance(v, list):
- a = [translate_to_test(x) for x in v]
- if v and isinstance(v[0], dict):
- return a
- else:
- return {'type': 'array', 'value': a}
- if isinstance(v, datetime.datetime):
- return {'type': 'datetime', 'value': format_rfc3339(v)}
- if isinstance(v, bool):
- return {'type': 'bool', 'value': 'true' if v else 'false'}
- if isinstance(v, _int_types):
- return {'type': 'integer', 'value': str(v)}
- if isinstance(v, float):
- return {'type': 'float', 'value': '{:.17}'.format(v)}
- if isinstance(v, _string_types):
- return {'type': 'string', 'value': v}
- raise RuntimeError('unexpected value: {!r}'.format(v))
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/utils.py b/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/utils.py
deleted file mode 100644
index 636a680..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/utils.py
+++ /dev/null
@@ -1,67 +0,0 @@
-import datetime
-import re
-
-rfc3339_re = re.compile(r'(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(\.\d+)?(?:Z|([+-]\d{2}):(\d{2}))')
-
-def parse_rfc3339(v):
- m = rfc3339_re.match(v)
- if not m or m.group(0) != v:
- return None
- return parse_rfc3339_re(m)
-
-def parse_rfc3339_re(m):
- r = map(int, m.groups()[:6])
- if m.group(7):
- micro = float(m.group(7))
- else:
- micro = 0
-
- if m.group(8):
- g = int(m.group(8), 10) * 60 + int(m.group(9), 10)
- tz = _TimeZone(datetime.timedelta(0, g * 60))
- else:
- tz = _TimeZone(datetime.timedelta(0, 0))
-
- y, m, d, H, M, S = r
- return datetime.datetime(y, m, d, H, M, S, int(micro * 1000000), tz)
-
-
-def format_rfc3339(v):
- offs = v.utcoffset()
- offs = int(offs.total_seconds()) // 60 if offs is not None else 0
-
- if offs == 0:
- suffix = 'Z'
- else:
- if offs > 0:
- suffix = '+'
- else:
- suffix = '-'
- offs = -offs
- suffix = '{0}{1:02}:{2:02}'.format(suffix, offs // 60, offs % 60)
-
- if v.microsecond:
- return v.strftime('%Y-%m-%dT%H:%M:%S.%f') + suffix
- else:
- return v.strftime('%Y-%m-%dT%H:%M:%S') + suffix
-
-class _TimeZone(datetime.tzinfo):
- def __init__(self, offset):
- self._offset = offset
-
- def utcoffset(self, dt):
- return self._offset
-
- def dst(self, dt):
- return None
-
- def tzname(self, dt):
- m = self._offset.total_seconds() // 60
- if m < 0:
- res = '-'
- m = -m
- else:
- res = '+'
- h = m // 60
- m = m - h * 60
- return '{}{:.02}{:.02}'.format(res, h, m)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/writer.py b/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/writer.py
deleted file mode 100644
index 73b5089..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/pytoml/writer.py
+++ /dev/null
@@ -1,106 +0,0 @@
-from __future__ import unicode_literals
-import io, datetime, math, string, sys
-
-from .utils import format_rfc3339
-
-if sys.version_info[0] == 3:
- long = int
- unicode = str
-
-
-def dumps(obj, sort_keys=False):
- fout = io.StringIO()
- dump(obj, fout, sort_keys=sort_keys)
- return fout.getvalue()
-
-
-_escapes = {'\n': 'n', '\r': 'r', '\\': '\\', '\t': 't', '\b': 'b', '\f': 'f', '"': '"'}
-
-
-def _escape_string(s):
- res = []
- start = 0
-
- def flush():
- if start != i:
- res.append(s[start:i])
- return i + 1
-
- i = 0
- while i < len(s):
- c = s[i]
- if c in '"\\\n\r\t\b\f':
- start = flush()
- res.append('\\' + _escapes[c])
- elif ord(c) < 0x20:
- start = flush()
- res.append('\\u%04x' % ord(c))
- i += 1
-
- flush()
- return '"' + ''.join(res) + '"'
-
-
-_key_chars = string.digits + string.ascii_letters + '-_'
-def _escape_id(s):
- if any(c not in _key_chars for c in s):
- return _escape_string(s)
- return s
-
-
-def _format_value(v):
- if isinstance(v, bool):
- return 'true' if v else 'false'
- if isinstance(v, int) or isinstance(v, long):
- return unicode(v)
- if isinstance(v, float):
- if math.isnan(v) or math.isinf(v):
- raise ValueError("{0} is not a valid TOML value".format(v))
- else:
- return repr(v)
- elif isinstance(v, unicode) or isinstance(v, bytes):
- return _escape_string(v)
- elif isinstance(v, datetime.datetime):
- return format_rfc3339(v)
- elif isinstance(v, list):
- return '[{0}]'.format(', '.join(_format_value(obj) for obj in v))
- elif isinstance(v, dict):
- return '{{{0}}}'.format(', '.join('{} = {}'.format(_escape_id(k), _format_value(obj)) for k, obj in v.items()))
- else:
- raise RuntimeError(v)
-
-
-def dump(obj, fout, sort_keys=False):
- tables = [((), obj, False)]
-
- while tables:
- name, table, is_array = tables.pop()
- if name:
- section_name = '.'.join(_escape_id(c) for c in name)
- if is_array:
- fout.write('[[{0}]]\n'.format(section_name))
- else:
- fout.write('[{0}]\n'.format(section_name))
-
- table_keys = sorted(table.keys()) if sort_keys else table.keys()
- new_tables = []
- has_kv = False
- for k in table_keys:
- v = table[k]
- if isinstance(v, dict):
- new_tables.append((name + (k,), v, False))
- elif isinstance(v, list) and v and all(isinstance(o, dict) for o in v):
- new_tables.extend((name + (k,), d, True) for d in v)
- elif v is None:
- # based on mojombo's comment: https://github.com/toml-lang/toml/issues/146#issuecomment-25019344
- fout.write(
- '#{} = null # To use: uncomment and replace null with value\n'.format(_escape_id(k)))
- has_kv = True
- else:
- fout.write('{0} = {1}\n'.format(_escape_id(k), _format_value(v)))
- has_kv = True
-
- tables.extend(reversed(new_tables))
-
- if (name or has_kv) and tables:
- fout.write('\n')
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__init__.py
index 1d30e3e..517458b 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__init__.py
@@ -9,14 +9,14 @@
Requests HTTP Library
~~~~~~~~~~~~~~~~~~~~~
-Requests is an HTTP library, written in Python, for human beings. Basic GET
-usage:
+Requests is an HTTP library, written in Python, for human beings.
+Basic GET usage:
>>> import requests
>>> r = requests.get('https://www.python.org')
>>> r.status_code
200
- >>> 'Python is a programming language' in r.content
+ >>> b'Python is a programming language' in r.content
True
... or POST:
@@ -27,14 +27,14 @@ usage:
{
...
"form": {
- "key2": "value2",
- "key1": "value1"
+ "key1": "value1",
+ "key2": "value2"
},
...
}
The other HTTP methods are supported - see `requests.api`. Full documentation
-is at .
+is at .
:copyright: (c) 2017 by Kenneth Reitz.
:license: Apache 2.0, see LICENSE for more details.
@@ -90,18 +90,29 @@ except (AssertionError, ValueError):
"version!".format(urllib3.__version__, chardet.__version__),
RequestsDependencyWarning)
-# Attempt to enable urllib3's SNI support, if possible
-from pip._internal.utils.compat import WINDOWS
-if not WINDOWS:
+# Attempt to enable urllib3's fallback for SNI support
+# if the standard library doesn't support SNI or the
+# 'ssl' library isn't available.
+try:
+ # Note: This logic prevents upgrading cryptography on Windows, if imported
+ # as part of pip.
+ from pip._internal.utils.compat import WINDOWS
+ if not WINDOWS:
+ raise ImportError("pip internals: don't import cryptography on Windows")
try:
+ import ssl
+ except ImportError:
+ ssl = None
+
+ if not getattr(ssl, "HAS_SNI", False):
from pip._vendor.urllib3.contrib import pyopenssl
pyopenssl.inject_into_urllib3()
# Check cryptography version
from cryptography import __version__ as cryptography_version
_check_cryptography(cryptography_version)
- except ImportError:
- pass
+except ImportError:
+ pass
# urllib3's DependencyWarnings should be silenced.
from pip._vendor.urllib3.exceptions import DependencyWarning
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-38.pyc
index c075fce..67c88b8 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-38.pyc
index a1bd847..1432de0 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-38.pyc
index 00d8e51..bcfa33a 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-38.pyc
index 00342c8..c7c8825 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/api.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/api.cpython-38.pyc
index 3fb5b98..c1b34ed 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/api.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/api.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-38.pyc
index 3161342..70e9b56 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-38.pyc
index 0261dad..7f645a6 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-38.pyc
index 7e373f6..11a3e04 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-38.pyc
index 76a4d43..5324822 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-38.pyc
index a3474e1..25d0a10 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/help.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/help.cpython-38.pyc
index 800fd72..75e2b3d 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/help.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/help.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-38.pyc
index ec2c8df..c734232 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/models.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/models.cpython-38.pyc
index 4eb009e..09f562e 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/models.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/models.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-38.pyc
index 45fbe51..65a6fbe 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-38.pyc
index 17c22e4..83fe2f8 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-38.pyc
index 2d26448..b7a5177 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-38.pyc
index a5b04a2..ec498a0 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-38.pyc
index 4dfb1c9..643819c 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__version__.py b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__version__.py
index 9844f74..531e26c 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/requests/__version__.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/requests/__version__.py
@@ -4,11 +4,11 @@
__title__ = 'requests'
__description__ = 'Python HTTP for Humans.'
-__url__ = 'http://python-requests.org'
-__version__ = '2.22.0'
-__build__ = 0x022200
+__url__ = 'https://requests.readthedocs.io'
+__version__ = '2.24.0'
+__build__ = 0x022400
__author__ = 'Kenneth Reitz'
__author_email__ = 'me@kennethreitz.org'
__license__ = 'Apache 2.0'
-__copyright__ = 'Copyright 2019 Kenneth Reitz'
+__copyright__ = 'Copyright 2020 Kenneth Reitz'
__cake__ = u'\u2728 \U0001f370 \u2728'
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/api.py b/venv/lib/python3.8/site-packages/pip/_vendor/requests/api.py
index ef71d07..e978e20 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/requests/api.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/requests/api.py
@@ -16,7 +16,7 @@ from . import sessions
def request(method, url, **kwargs):
"""Constructs and sends a :class:`Request `.
- :param method: method for the new :class:`Request` object.
+ :param method: method for the new :class:`Request` object: ``GET``, ``OPTIONS``, ``HEAD``, ``POST``, ``PUT``, ``PATCH``, or ``DELETE``.
:param url: URL for the new :class:`Request` object.
:param params: (optional) Dictionary, list of tuples or bytes to send
in the query string for the :class:`Request`.
@@ -50,6 +50,7 @@ def request(method, url, **kwargs):
>>> import requests
>>> req = requests.request('GET', 'https://httpbin.org/get')
+ >>> req
"""
@@ -92,7 +93,9 @@ def head(url, **kwargs):
r"""Sends a HEAD request.
:param url: URL for the new :class:`Request` object.
- :param \*\*kwargs: Optional arguments that ``request`` takes.
+ :param \*\*kwargs: Optional arguments that ``request`` takes. If
+ `allow_redirects` is not provided, it will be set to `False` (as
+ opposed to the default :meth:`request` behavior).
:return: :class:`Response ` object
:rtype: requests.Response
"""
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/auth.py b/venv/lib/python3.8/site-packages/pip/_vendor/requests/auth.py
index bdde51c..eeface3 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/requests/auth.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/requests/auth.py
@@ -50,7 +50,7 @@ def _basic_auth_str(username, password):
"Non-string passwords will no longer be supported in Requests "
"3.0.0. Please convert the object you've passed in ({!r}) to "
"a string or bytes object in the near future to avoid "
- "problems.".format(password),
+ "problems.".format(type(password)),
category=DeprecationWarning,
)
password = str(password)
@@ -239,7 +239,7 @@ class HTTPDigestAuth(AuthBase):
"""
# If response is not 4xx, do not auth
- # See https://github.com/requests/requests/issues/3772
+ # See https://github.com/psf/requests/issues/3772
if not 400 <= r.status_code < 500:
self._thread_local.num_401_calls = 1
return r
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/compat.py b/venv/lib/python3.8/site-packages/pip/_vendor/requests/compat.py
index 6a86893..9e29371 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/requests/compat.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/requests/compat.py
@@ -47,6 +47,7 @@ if is_py2:
import cookielib
from Cookie import Morsel
from StringIO import StringIO
+ # Keep OrderedDict for backwards compatibility.
from collections import Callable, Mapping, MutableMapping, OrderedDict
@@ -63,6 +64,7 @@ elif is_py3:
from http import cookiejar as cookielib
from http.cookies import Morsel
from io import StringIO
+ # Keep OrderedDict for backwards compatibility.
from collections import OrderedDict
from collections.abc import Callable, Mapping, MutableMapping
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/exceptions.py b/venv/lib/python3.8/site-packages/pip/_vendor/requests/exceptions.py
index a91e1fd..9ef9e6e 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/requests/exceptions.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/requests/exceptions.py
@@ -94,11 +94,11 @@ class ChunkedEncodingError(RequestException):
class ContentDecodingError(RequestException, BaseHTTPError):
- """Failed to decode response content"""
+ """Failed to decode response content."""
class StreamConsumedError(RequestException, TypeError):
- """The content for this response was already consumed"""
+ """The content for this response was already consumed."""
class RetryError(RequestException):
@@ -106,21 +106,18 @@ class RetryError(RequestException):
class UnrewindableBodyError(RequestException):
- """Requests encountered an error when trying to rewind a body"""
+ """Requests encountered an error when trying to rewind a body."""
# Warnings
class RequestsWarning(Warning):
"""Base warning for Requests."""
- pass
class FileModeWarning(RequestsWarning, DeprecationWarning):
"""A file was opened in text mode, but Requests determined its binary length."""
- pass
class RequestsDependencyWarning(RequestsWarning):
"""An imported dependency doesn't match the expected version range."""
- pass
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/models.py b/venv/lib/python3.8/site-packages/pip/_vendor/requests/models.py
index 0839957..015e715 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/requests/models.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/requests/models.py
@@ -12,7 +12,7 @@ import sys
# Import encoding now, to avoid implicit import later.
# Implicit import within threads may cause LookupError when standard library is in a ZIP,
-# such as in Embedded Python. See https://github.com/requests/requests/issues/3578.
+# such as in Embedded Python. See https://github.com/psf/requests/issues/3578.
import encodings.idna
from pip._vendor.urllib3.fields import RequestField
@@ -280,6 +280,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
>>> import requests
>>> req = requests.Request('GET', 'https://httpbin.org/get')
>>> r = req.prepare()
+ >>> r
>>> s = requests.Session()
@@ -358,7 +359,7 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
#: We're unable to blindly call unicode/str functions
#: as this will include the bytestring indicator (b'')
#: on python 3.x.
- #: https://github.com/requests/requests/pull/2238
+ #: https://github.com/psf/requests/pull/2238
if isinstance(url, bytes):
url = url.decode('utf8')
else:
@@ -472,12 +473,12 @@ class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
not isinstance(data, (basestring, list, tuple, Mapping))
])
- try:
- length = super_len(data)
- except (TypeError, AttributeError, UnsupportedOperation):
- length = None
-
if is_stream:
+ try:
+ length = super_len(data)
+ except (TypeError, AttributeError, UnsupportedOperation):
+ length = None
+
body = data
if getattr(body, 'tell', None) is not None:
@@ -608,7 +609,7 @@ class Response(object):
#: File-like object representation of response (for advanced usage).
#: Use of ``raw`` requires that ``stream=True`` be set on the request.
- # This requirement does not apply for use internally to Requests.
+ #: This requirement does not apply for use internally to Requests.
self.raw = None
#: Final URL location of Response.
@@ -915,7 +916,7 @@ class Response(object):
return l
def raise_for_status(self):
- """Raises stored :class:`HTTPError`, if one occurred."""
+ """Raises :class:`HTTPError`, if one occurred."""
http_error_msg = ''
if isinstance(self.reason, bytes):
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/sessions.py b/venv/lib/python3.8/site-packages/pip/_vendor/requests/sessions.py
index d73d700..e8e2d60 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/requests/sessions.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/requests/sessions.py
@@ -11,9 +11,10 @@ import os
import sys
import time
from datetime import timedelta
+from collections import OrderedDict
from .auth import _basic_auth_str
-from .compat import cookielib, is_py3, OrderedDict, urljoin, urlparse, Mapping
+from .compat import cookielib, is_py3, urljoin, urlparse, Mapping
from .cookies import (
cookiejar_from_dict, extract_cookies_to_jar, RequestsCookieJar, merge_cookies)
from .models import Request, PreparedRequest, DEFAULT_REDIRECT_LIMIT
@@ -162,7 +163,7 @@ class SessionRedirectMixin(object):
resp.raw.read(decode_content=False)
if len(resp.history) >= self.max_redirects:
- raise TooManyRedirects('Exceeded %s redirects.' % self.max_redirects, response=resp)
+ raise TooManyRedirects('Exceeded {} redirects.'.format(self.max_redirects), response=resp)
# Release the connection back into the pool.
resp.close()
@@ -170,7 +171,7 @@ class SessionRedirectMixin(object):
# Handle redirection without scheme (see: RFC 1808 Section 4)
if url.startswith('//'):
parsed_rurl = urlparse(resp.url)
- url = '%s:%s' % (to_native_string(parsed_rurl.scheme), url)
+ url = ':'.join([to_native_string(parsed_rurl.scheme), url])
# Normalize url case and attach previous fragment if needed (RFC 7231 7.1.2)
parsed = urlparse(url)
@@ -192,19 +193,16 @@ class SessionRedirectMixin(object):
self.rebuild_method(prepared_request, resp)
- # https://github.com/requests/requests/issues/1084
+ # https://github.com/psf/requests/issues/1084
if resp.status_code not in (codes.temporary_redirect, codes.permanent_redirect):
- # https://github.com/requests/requests/issues/3490
+ # https://github.com/psf/requests/issues/3490
purged_headers = ('Content-Length', 'Content-Type', 'Transfer-Encoding')
for header in purged_headers:
prepared_request.headers.pop(header, None)
prepared_request.body = None
headers = prepared_request.headers
- try:
- del headers['Cookie']
- except KeyError:
- pass
+ headers.pop('Cookie', None)
# Extract any cookies sent on the response to the cookiejar
# in the new request. Because we've mutated our copied prepared
@@ -271,7 +269,6 @@ class SessionRedirectMixin(object):
if new_auth is not None:
prepared_request.prepare_auth(new_auth)
- return
def rebuild_proxies(self, prepared_request, proxies):
"""This method re-evaluates the proxy configuration by considering the
@@ -352,13 +349,13 @@ class Session(SessionRedirectMixin):
Or as a context manager::
>>> with requests.Session() as s:
- >>> s.get('https://httpbin.org/get')
+ ... s.get('https://httpbin.org/get')
"""
__attrs__ = [
'headers', 'cookies', 'auth', 'proxies', 'hooks', 'params', 'verify',
- 'cert', 'prefetch', 'adapters', 'stream', 'trust_env',
+ 'cert', 'adapters', 'stream', 'trust_env',
'max_redirects',
]
@@ -661,11 +658,13 @@ class Session(SessionRedirectMixin):
extract_cookies_to_jar(self.cookies, request, r.raw)
- # Redirect resolving generator.
- gen = self.resolve_redirects(r, request, **kwargs)
-
# Resolve redirects if allowed.
- history = [resp for resp in gen] if allow_redirects else []
+ if allow_redirects:
+ # Redirect resolving generator.
+ gen = self.resolve_redirects(r, request, **kwargs)
+ history = [resp for resp in gen]
+ else:
+ history = []
# Shuffle things around if there's history.
if history:
@@ -728,7 +727,7 @@ class Session(SessionRedirectMixin):
return adapter
# Nothing matches :-/
- raise InvalidSchema("No connection adapters were found for '%s'" % url)
+ raise InvalidSchema("No connection adapters were found for {!r}".format(url))
def close(self):
"""Closes all adapters and as such the session"""
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/status_codes.py b/venv/lib/python3.8/site-packages/pip/_vendor/requests/status_codes.py
index 813e8c4..d80a7cd 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/requests/status_codes.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/requests/status_codes.py
@@ -5,12 +5,15 @@ The ``codes`` object defines a mapping from common names for HTTP statuses
to their numerical codes, accessible either as attributes or as dictionary
items.
->>> requests.codes['temporary_redirect']
-307
->>> requests.codes.teapot
-418
->>> requests.codes['\o/']
-200
+Example::
+
+ >>> import requests
+ >>> requests.codes['temporary_redirect']
+ 307
+ >>> requests.codes.teapot
+ 418
+ >>> requests.codes['\o/']
+ 200
Some codes have multiple names, and both upper- and lower-case versions of
the names are allowed. For example, ``codes.ok``, ``codes.OK``, and
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/structures.py b/venv/lib/python3.8/site-packages/pip/_vendor/requests/structures.py
index da930e2..8ee0ba7 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/requests/structures.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/requests/structures.py
@@ -7,7 +7,9 @@ requests.structures
Data structures that power Requests.
"""
-from .compat import OrderedDict, Mapping, MutableMapping
+from collections import OrderedDict
+
+from .compat import Mapping, MutableMapping
class CaseInsensitiveDict(MutableMapping):
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/requests/utils.py b/venv/lib/python3.8/site-packages/pip/_vendor/requests/utils.py
index 8170a8d..c1700d7 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/requests/utils.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/requests/utils.py
@@ -19,6 +19,7 @@ import sys
import tempfile
import warnings
import zipfile
+from collections import OrderedDict
from .__version__ import __version__
from . import certs
@@ -26,7 +27,7 @@ from . import certs
from ._internal_utils import to_native_string
from .compat import parse_http_list as _parse_list_header
from .compat import (
- quote, urlparse, bytes, str, OrderedDict, unquote, getproxies,
+ quote, urlparse, bytes, str, unquote, getproxies,
proxy_bypass, urlunparse, basestring, integer_types, is_py3,
proxy_bypass_environment, getproxies_environment, Mapping)
from .cookies import cookiejar_from_dict
@@ -179,7 +180,7 @@ def get_netrc_auth(url, raise_errors=False):
except KeyError:
# os.path.expanduser can fail when $HOME is undefined and
# getpwuid fails. See https://bugs.python.org/issue20164 &
- # https://github.com/requests/requests/issues/1846
+ # https://github.com/psf/requests/issues/1846
return
if os.path.exists(loc):
@@ -266,6 +267,8 @@ def from_key_val_list(value):
>>> from_key_val_list([('key', 'val')])
OrderedDict([('key', 'val')])
>>> from_key_val_list('string')
+ Traceback (most recent call last):
+ ...
ValueError: cannot encode objects that are not 2-tuples
>>> from_key_val_list({'key': 'val'})
OrderedDict([('key', 'val')])
@@ -292,7 +295,9 @@ def to_key_val_list(value):
>>> to_key_val_list({'key': 'val'})
[('key', 'val')]
>>> to_key_val_list('string')
- ValueError: cannot encode objects that are not 2-tuples.
+ Traceback (most recent call last):
+ ...
+ ValueError: cannot encode objects that are not 2-tuples
:rtype: list
"""
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/six.py b/venv/lib/python3.8/site-packages/pip/_vendor/six.py
index 89b2188..83f6978 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/six.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/six.py
@@ -1,4 +1,4 @@
-# Copyright (c) 2010-2018 Benjamin Peterson
+# Copyright (c) 2010-2020 Benjamin Peterson
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -29,7 +29,7 @@ import sys
import types
__author__ = "Benjamin Peterson "
-__version__ = "1.12.0"
+__version__ = "1.15.0"
# Useful for very coarse version differentiation.
@@ -255,9 +255,11 @@ _moved_attributes = [
MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
MovedModule("builtins", "__builtin__"),
MovedModule("configparser", "ConfigParser"),
+ MovedModule("collections_abc", "collections", "collections.abc" if sys.version_info >= (3, 3) else "collections"),
MovedModule("copyreg", "copy_reg"),
MovedModule("dbm_gnu", "gdbm", "dbm.gnu"),
- MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread"),
+ MovedModule("dbm_ndbm", "dbm", "dbm.ndbm"),
+ MovedModule("_dummy_thread", "dummy_thread", "_dummy_thread" if sys.version_info < (3, 9) else "_thread"),
MovedModule("http_cookiejar", "cookielib", "http.cookiejar"),
MovedModule("http_cookies", "Cookie", "http.cookies"),
MovedModule("html_entities", "htmlentitydefs", "html.entities"),
@@ -637,13 +639,16 @@ if PY3:
import io
StringIO = io.StringIO
BytesIO = io.BytesIO
+ del io
_assertCountEqual = "assertCountEqual"
if sys.version_info[1] <= 1:
_assertRaisesRegex = "assertRaisesRegexp"
_assertRegex = "assertRegexpMatches"
+ _assertNotRegex = "assertNotRegexpMatches"
else:
_assertRaisesRegex = "assertRaisesRegex"
_assertRegex = "assertRegex"
+ _assertNotRegex = "assertNotRegex"
else:
def b(s):
return s
@@ -665,6 +670,7 @@ else:
_assertCountEqual = "assertItemsEqual"
_assertRaisesRegex = "assertRaisesRegexp"
_assertRegex = "assertRegexpMatches"
+ _assertNotRegex = "assertNotRegexpMatches"
_add_doc(b, """Byte literal""")
_add_doc(u, """Text literal""")
@@ -681,6 +687,10 @@ def assertRegex(self, *args, **kwargs):
return getattr(self, _assertRegex)(*args, **kwargs)
+def assertNotRegex(self, *args, **kwargs):
+ return getattr(self, _assertNotRegex)(*args, **kwargs)
+
+
if PY3:
exec_ = getattr(moves.builtins, "exec")
@@ -716,16 +726,7 @@ else:
""")
-if sys.version_info[:2] == (3, 2):
- exec_("""def raise_from(value, from_value):
- try:
- if from_value is None:
- raise value
- raise value from from_value
- finally:
- value = None
-""")
-elif sys.version_info[:2] > (3, 2):
+if sys.version_info[:2] > (3,):
exec_("""def raise_from(value, from_value):
try:
raise value from from_value
@@ -805,13 +806,33 @@ if sys.version_info[:2] < (3, 3):
_add_doc(reraise, """Reraise an exception.""")
if sys.version_info[0:2] < (3, 4):
+ # This does exactly the same what the :func:`py3:functools.update_wrapper`
+ # function does on Python versions after 3.2. It sets the ``__wrapped__``
+ # attribute on ``wrapper`` object and it doesn't raise an error if any of
+ # the attributes mentioned in ``assigned`` and ``updated`` are missing on
+ # ``wrapped`` object.
+ def _update_wrapper(wrapper, wrapped,
+ assigned=functools.WRAPPER_ASSIGNMENTS,
+ updated=functools.WRAPPER_UPDATES):
+ for attr in assigned:
+ try:
+ value = getattr(wrapped, attr)
+ except AttributeError:
+ continue
+ else:
+ setattr(wrapper, attr, value)
+ for attr in updated:
+ getattr(wrapper, attr).update(getattr(wrapped, attr, {}))
+ wrapper.__wrapped__ = wrapped
+ return wrapper
+ _update_wrapper.__doc__ = functools.update_wrapper.__doc__
+
def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
updated=functools.WRAPPER_UPDATES):
- def wrapper(f):
- f = functools.wraps(wrapped, assigned, updated)(f)
- f.__wrapped__ = wrapped
- return f
- return wrapper
+ return functools.partial(_update_wrapper, wrapped=wrapped,
+ assigned=assigned, updated=updated)
+ wraps.__doc__ = functools.wraps.__doc__
+
else:
wraps = functools.wraps
@@ -824,7 +845,15 @@ def with_metaclass(meta, *bases):
class metaclass(type):
def __new__(cls, name, this_bases, d):
- return meta(name, bases, d)
+ if sys.version_info[:2] >= (3, 7):
+ # This version introduced PEP 560 that requires a bit
+ # of extra care (we mimic what is done by __build_class__).
+ resolved_bases = types.resolve_bases(bases)
+ if resolved_bases is not bases:
+ d['__orig_bases__'] = bases
+ else:
+ resolved_bases = bases
+ return meta(name, resolved_bases, d)
@classmethod
def __prepare__(cls, name, this_bases):
@@ -861,12 +890,11 @@ def ensure_binary(s, encoding='utf-8', errors='strict'):
- `str` -> encoded to `bytes`
- `bytes` -> `bytes`
"""
+ if isinstance(s, binary_type):
+ return s
if isinstance(s, text_type):
return s.encode(encoding, errors)
- elif isinstance(s, binary_type):
- return s
- else:
- raise TypeError("not expecting type '%s'" % type(s))
+ raise TypeError("not expecting type '%s'" % type(s))
def ensure_str(s, encoding='utf-8', errors='strict'):
@@ -880,12 +908,15 @@ def ensure_str(s, encoding='utf-8', errors='strict'):
- `str` -> `str`
- `bytes` -> decoded to `str`
"""
- if not isinstance(s, (text_type, binary_type)):
- raise TypeError("not expecting type '%s'" % type(s))
+ # Optimization: Fast return for the common case.
+ if type(s) is str:
+ return s
if PY2 and isinstance(s, text_type):
- s = s.encode(encoding, errors)
+ return s.encode(encoding, errors)
elif PY3 and isinstance(s, binary_type):
- s = s.decode(encoding, errors)
+ return s.decode(encoding, errors)
+ elif not isinstance(s, (text_type, binary_type)):
+ raise TypeError("not expecting type '%s'" % type(s))
return s
@@ -908,10 +939,9 @@ def ensure_text(s, encoding='utf-8', errors='strict'):
raise TypeError("not expecting type '%s'" % type(s))
-
def python_2_unicode_compatible(klass):
"""
- A decorator that defines __unicode__ and __str__ methods under Python 2.
+ A class decorator that defines __unicode__ and __str__ methods under Python 2.
Under Python 3 it does nothing.
To support Python 2 and 3 with a single code base, define a __str__ method
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__init__.py
index c4c0dde..667e9bc 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__init__.py
@@ -4,11 +4,7 @@ urllib3 - Thread-safe connection pooling and re-using.
from __future__ import absolute_import
import warnings
-from .connectionpool import (
- HTTPConnectionPool,
- HTTPSConnectionPool,
- connection_from_url
-)
+from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool, connection_from_url
from . import exceptions
from .filepost import encode_multipart_formdata
@@ -24,25 +20,25 @@ from .util.retry import Retry
import logging
from logging import NullHandler
-__author__ = 'Andrey Petrov (andrey.petrov@shazow.net)'
-__license__ = 'MIT'
-__version__ = '1.25.3'
+__author__ = "Andrey Petrov (andrey.petrov@shazow.net)"
+__license__ = "MIT"
+__version__ = "1.25.9"
__all__ = (
- 'HTTPConnectionPool',
- 'HTTPSConnectionPool',
- 'PoolManager',
- 'ProxyManager',
- 'HTTPResponse',
- 'Retry',
- 'Timeout',
- 'add_stderr_logger',
- 'connection_from_url',
- 'disable_warnings',
- 'encode_multipart_formdata',
- 'get_host',
- 'make_headers',
- 'proxy_from_url',
+ "HTTPConnectionPool",
+ "HTTPSConnectionPool",
+ "PoolManager",
+ "ProxyManager",
+ "HTTPResponse",
+ "Retry",
+ "Timeout",
+ "add_stderr_logger",
+ "connection_from_url",
+ "disable_warnings",
+ "encode_multipart_formdata",
+ "get_host",
+ "make_headers",
+ "proxy_from_url",
)
logging.getLogger(__name__).addHandler(NullHandler())
@@ -59,10 +55,10 @@ def add_stderr_logger(level=logging.DEBUG):
# even if urllib3 is vendored within another package.
logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
- handler.setFormatter(logging.Formatter('%(asctime)s %(levelname)s %(message)s'))
+ handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s"))
logger.addHandler(handler)
logger.setLevel(level)
- logger.debug('Added a stderr logging handler to logger: %s', __name__)
+ logger.debug("Added a stderr logging handler to logger: %s", __name__)
return handler
@@ -74,18 +70,17 @@ del NullHandler
# shouldn't be: otherwise, it's very hard for users to use most Python
# mechanisms to silence them.
# SecurityWarning's always go off by default.
-warnings.simplefilter('always', exceptions.SecurityWarning, append=True)
+warnings.simplefilter("always", exceptions.SecurityWarning, append=True)
# SubjectAltNameWarning's should go off once per host
-warnings.simplefilter('default', exceptions.SubjectAltNameWarning, append=True)
+warnings.simplefilter("default", exceptions.SubjectAltNameWarning, append=True)
# InsecurePlatformWarning's don't vary between requests, so we keep it default.
-warnings.simplefilter('default', exceptions.InsecurePlatformWarning,
- append=True)
+warnings.simplefilter("default", exceptions.InsecurePlatformWarning, append=True)
# SNIMissingWarnings should go off only once.
-warnings.simplefilter('default', exceptions.SNIMissingWarning, append=True)
+warnings.simplefilter("default", exceptions.SNIMissingWarning, append=True)
def disable_warnings(category=exceptions.HTTPWarning):
"""
Helper for quickly disabling all urllib3 warnings.
"""
- warnings.simplefilter('ignore', category)
+ warnings.simplefilter("ignore", category)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-38.pyc
index f815b1d..ac4fe20 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-38.pyc
index bbe823d..9801f04 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-38.pyc
index 121685f..1f6e0b7 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-38.pyc
index 94fc1e6..06c2b58 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-38.pyc
index 36dda80..4fc5d5c 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-38.pyc
index e7fb4dd..5d44a0c 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-38.pyc
index 2c77f52..f20915b 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-38.pyc
index 08d9102..6d292f4 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-38.pyc
index 369e119..c1e0a38 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-38.pyc
index 0b6399a..57b5a2d 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/_collections.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/_collections.py
index 34f2381..019d151 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/_collections.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/_collections.py
@@ -1,4 +1,5 @@
from __future__ import absolute_import
+
try:
from collections.abc import Mapping, MutableMapping
except ImportError:
@@ -6,6 +7,7 @@ except ImportError:
try:
from threading import RLock
except ImportError: # Platform-specific: No threads available
+
class RLock:
def __enter__(self):
pass
@@ -19,7 +21,7 @@ from .exceptions import InvalidHeader
from .packages.six import iterkeys, itervalues, PY3
-__all__ = ['RecentlyUsedContainer', 'HTTPHeaderDict']
+__all__ = ["RecentlyUsedContainer", "HTTPHeaderDict"]
_Null = object()
@@ -82,7 +84,9 @@ class RecentlyUsedContainer(MutableMapping):
return len(self._container)
def __iter__(self):
- raise NotImplementedError('Iteration over this class is unlikely to be threadsafe.')
+ raise NotImplementedError(
+ "Iteration over this class is unlikely to be threadsafe."
+ )
def clear(self):
with self.lock:
@@ -150,7 +154,7 @@ class HTTPHeaderDict(MutableMapping):
def __getitem__(self, key):
val = self._container[key.lower()]
- return ', '.join(val[1:])
+ return ", ".join(val[1:])
def __delitem__(self, key):
del self._container[key.lower()]
@@ -159,12 +163,13 @@ class HTTPHeaderDict(MutableMapping):
return key.lower() in self._container
def __eq__(self, other):
- if not isinstance(other, Mapping) and not hasattr(other, 'keys'):
+ if not isinstance(other, Mapping) and not hasattr(other, "keys"):
return False
if not isinstance(other, type(self)):
other = type(self)(other)
- return (dict((k.lower(), v) for k, v in self.itermerged()) ==
- dict((k.lower(), v) for k, v in other.itermerged()))
+ return dict((k.lower(), v) for k, v in self.itermerged()) == dict(
+ (k.lower(), v) for k, v in other.itermerged()
+ )
def __ne__(self, other):
return not self.__eq__(other)
@@ -184,9 +189,9 @@ class HTTPHeaderDict(MutableMapping):
yield vals[0]
def pop(self, key, default=__marker):
- '''D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
+ """D.pop(k[,d]) -> v, remove specified key and return the corresponding value.
If key is not found, d is returned if given, otherwise KeyError is raised.
- '''
+ """
# Using the MutableMapping function directly fails due to the private marker.
# Using ordinary dict.pop would expose the internal structures.
# So let's reinvent the wheel.
@@ -228,8 +233,10 @@ class HTTPHeaderDict(MutableMapping):
with self.add instead of self.__setitem__
"""
if len(args) > 1:
- raise TypeError("extend() takes at most 1 positional "
- "arguments ({0} given)".format(len(args)))
+ raise TypeError(
+ "extend() takes at most 1 positional "
+ "arguments ({0} given)".format(len(args))
+ )
other = args[0] if len(args) >= 1 else ()
if isinstance(other, HTTPHeaderDict):
@@ -295,7 +302,7 @@ class HTTPHeaderDict(MutableMapping):
"""Iterate over all headers, merging duplicate ones together."""
for key in self:
val = self._container[key.lower()]
- yield val[0], ', '.join(val[1:])
+ yield val[0], ", ".join(val[1:])
def items(self):
return list(self.iteritems())
@@ -306,7 +313,7 @@ class HTTPHeaderDict(MutableMapping):
# python2.7 does not expose a proper API for exporting multiheaders
# efficiently. This function re-reads raw lines from the message
# object and extracts the multiheaders properly.
- obs_fold_continued_leaders = (' ', '\t')
+ obs_fold_continued_leaders = (" ", "\t")
headers = []
for line in message.headers:
@@ -316,14 +323,14 @@ class HTTPHeaderDict(MutableMapping):
# in RFC-7230 S3.2.4. This indicates a multiline header, but
# there exists no previous header to which we can attach it.
raise InvalidHeader(
- 'Header continuation with no previous header: %s' % line
+ "Header continuation with no previous header: %s" % line
)
else:
key, value = headers[-1]
- headers[-1] = (key, value + ' ' + line.strip())
+ headers[-1] = (key, value + " " + line.strip())
continue
- key, value = line.split(':', 1)
+ key, value = line.split(":", 1)
headers.append((key, value.strip()))
return cls(headers)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/connection.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/connection.py
index 57c58fe..6da1cf4 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/connection.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/connection.py
@@ -1,4 +1,5 @@
from __future__ import absolute_import
+import re
import datetime
import logging
import os
@@ -11,6 +12,7 @@ from .packages.six.moves.http_client import HTTPException # noqa: F401
try: # Compiled with SSL?
import ssl
+
BaseSSLError = ssl.SSLError
except (ImportError, AttributeError): # Platform-specific: No SSL.
ssl = None
@@ -41,7 +43,7 @@ from .util.ssl_ import (
resolve_ssl_version,
assert_fingerprint,
create_urllib3_context,
- ssl_wrap_socket
+ ssl_wrap_socket,
)
@@ -51,20 +53,18 @@ from ._collections import HTTPHeaderDict
log = logging.getLogger(__name__)
-port_by_scheme = {
- 'http': 80,
- 'https': 443,
-}
+port_by_scheme = {"http": 80, "https": 443}
-# When updating RECENT_DATE, move it to within two years of the current date,
-# and not less than 6 months ago.
-# Example: if Today is 2018-01-01, then RECENT_DATE should be any date on or
-# after 2016-01-01 (today - 2 years) AND before 2017-07-01 (today - 6 months)
-RECENT_DATE = datetime.date(2017, 6, 30)
+# When it comes time to update this value as a part of regular maintenance
+# (ie test_recent_date is failing) update it to ~6 months before the current date.
+RECENT_DATE = datetime.date(2019, 1, 1)
+
+_CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]")
class DummyConnection(object):
"""Used to detect a failed ConnectionCls import."""
+
pass
@@ -92,7 +92,7 @@ class HTTPConnection(_HTTPConnection, object):
Or you may want to disable the defaults by passing an empty list (e.g., ``[]``).
"""
- default_port = port_by_scheme['http']
+ default_port = port_by_scheme["http"]
#: Disable Nagle's algorithm by default.
#: ``[(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)]``
@@ -102,15 +102,15 @@ class HTTPConnection(_HTTPConnection, object):
is_verified = False
def __init__(self, *args, **kw):
- if six.PY3:
- kw.pop('strict', None)
+ if not six.PY2:
+ kw.pop("strict", None)
# Pre-set source_address.
- self.source_address = kw.get('source_address')
+ self.source_address = kw.get("source_address")
#: The socket options provided by the user. If no options are
#: provided, we use the default options.
- self.socket_options = kw.pop('socket_options', self.default_socket_options)
+ self.socket_options = kw.pop("socket_options", self.default_socket_options)
_HTTPConnection.__init__(self, *args, **kw)
@@ -131,7 +131,7 @@ class HTTPConnection(_HTTPConnection, object):
those cases where it's appropriate (i.e., when doing DNS lookup to establish the
actual TCP connection across which we're going to send HTTP requests).
"""
- return self._dns_host.rstrip('.')
+ return self._dns_host.rstrip(".")
@host.setter
def host(self, value):
@@ -150,30 +150,34 @@ class HTTPConnection(_HTTPConnection, object):
"""
extra_kw = {}
if self.source_address:
- extra_kw['source_address'] = self.source_address
+ extra_kw["source_address"] = self.source_address
if self.socket_options:
- extra_kw['socket_options'] = self.socket_options
+ extra_kw["socket_options"] = self.socket_options
try:
conn = connection.create_connection(
- (self._dns_host, self.port), self.timeout, **extra_kw)
+ (self._dns_host, self.port), self.timeout, **extra_kw
+ )
except SocketTimeout:
raise ConnectTimeoutError(
- self, "Connection to %s timed out. (connect timeout=%s)" %
- (self.host, self.timeout))
+ self,
+ "Connection to %s timed out. (connect timeout=%s)"
+ % (self.host, self.timeout),
+ )
except SocketError as e:
raise NewConnectionError(
- self, "Failed to establish a new connection: %s" % e)
+ self, "Failed to establish a new connection: %s" % e
+ )
return conn
def _prepare_conn(self, conn):
self.sock = conn
# Google App Engine's httplib does not define _tunnel_host
- if getattr(self, '_tunnel_host', None):
+ if getattr(self, "_tunnel_host", None):
# TODO: Fix tunnel so it doesn't depend on self.sock state.
self._tunnel()
# Mark this connection as not reusable
@@ -183,24 +187,32 @@ class HTTPConnection(_HTTPConnection, object):
conn = self._new_conn()
self._prepare_conn(conn)
+ def putrequest(self, method, url, *args, **kwargs):
+ """Send a request to the server"""
+ match = _CONTAINS_CONTROL_CHAR_RE.search(method)
+ if match:
+ raise ValueError(
+ "Method cannot contain non-token characters %r (found at least %r)"
+ % (method, match.group())
+ )
+
+ return _HTTPConnection.putrequest(self, method, url, *args, **kwargs)
+
def request_chunked(self, method, url, body=None, headers=None):
"""
Alternative to the common request method, which sends the
body with chunked encoding and not as one block
"""
headers = HTTPHeaderDict(headers if headers is not None else {})
- skip_accept_encoding = 'accept-encoding' in headers
- skip_host = 'host' in headers
+ skip_accept_encoding = "accept-encoding" in headers
+ skip_host = "host" in headers
self.putrequest(
- method,
- url,
- skip_accept_encoding=skip_accept_encoding,
- skip_host=skip_host
+ method, url, skip_accept_encoding=skip_accept_encoding, skip_host=skip_host
)
for header, value in headers.items():
self.putheader(header, value)
- if 'transfer-encoding' not in headers:
- self.putheader('Transfer-Encoding', 'chunked')
+ if "transfer-encoding" not in headers:
+ self.putheader("Transfer-Encoding", "chunked")
self.endheaders()
if body is not None:
@@ -211,29 +223,42 @@ class HTTPConnection(_HTTPConnection, object):
if not chunk:
continue
if not isinstance(chunk, bytes):
- chunk = chunk.encode('utf8')
+ chunk = chunk.encode("utf8")
len_str = hex(len(chunk))[2:]
- self.send(len_str.encode('utf-8'))
- self.send(b'\r\n')
+ self.send(len_str.encode("utf-8"))
+ self.send(b"\r\n")
self.send(chunk)
- self.send(b'\r\n')
+ self.send(b"\r\n")
# After the if clause, to always have a closed body
- self.send(b'0\r\n\r\n')
+ self.send(b"0\r\n\r\n")
class HTTPSConnection(HTTPConnection):
- default_port = port_by_scheme['https']
+ default_port = port_by_scheme["https"]
+ cert_reqs = None
+ ca_certs = None
+ ca_cert_dir = None
+ ca_cert_data = None
ssl_version = None
+ assert_fingerprint = None
- def __init__(self, host, port=None, key_file=None, cert_file=None,
- key_password=None, strict=None,
- timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
- ssl_context=None, server_hostname=None, **kw):
+ def __init__(
+ self,
+ host,
+ port=None,
+ key_file=None,
+ cert_file=None,
+ key_password=None,
+ strict=None,
+ timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
+ ssl_context=None,
+ server_hostname=None,
+ **kw
+ ):
- HTTPConnection.__init__(self, host, port, strict=strict,
- timeout=timeout, **kw)
+ HTTPConnection.__init__(self, host, port, strict=strict, timeout=timeout, **kw)
self.key_file = key_file
self.cert_file = cert_file
@@ -243,54 +268,20 @@ class HTTPSConnection(HTTPConnection):
# Required property for Google AppEngine 1.9.0 which otherwise causes
# HTTPS requests to go out as HTTP. (See Issue #356)
- self._protocol = 'https'
+ self._protocol = "https"
- def connect(self):
- conn = self._new_conn()
- self._prepare_conn(conn)
-
- # Wrap socket using verification with the root certs in
- # trusted_root_certs
- default_ssl_context = False
- if self.ssl_context is None:
- default_ssl_context = True
- self.ssl_context = create_urllib3_context(
- ssl_version=resolve_ssl_version(self.ssl_version),
- cert_reqs=resolve_cert_reqs(self.cert_reqs),
- )
-
- # Try to load OS default certs if none are given.
- # Works well on Windows (requires Python3.4+)
- context = self.ssl_context
- if (not self.ca_certs and not self.ca_cert_dir and default_ssl_context
- and hasattr(context, 'load_default_certs')):
- context.load_default_certs()
-
- self.sock = ssl_wrap_socket(
- sock=conn,
- keyfile=self.key_file,
- certfile=self.cert_file,
- key_password=self.key_password,
- ssl_context=self.ssl_context,
- server_hostname=self.server_hostname
- )
-
-
-class VerifiedHTTPSConnection(HTTPSConnection):
- """
- Based on httplib.HTTPSConnection but wraps the socket with
- SSL certification.
- """
- cert_reqs = None
- ca_certs = None
- ca_cert_dir = None
- ssl_version = None
- assert_fingerprint = None
-
- def set_cert(self, key_file=None, cert_file=None,
- cert_reqs=None, key_password=None, ca_certs=None,
- assert_hostname=None, assert_fingerprint=None,
- ca_cert_dir=None):
+ def set_cert(
+ self,
+ key_file=None,
+ cert_file=None,
+ cert_reqs=None,
+ key_password=None,
+ ca_certs=None,
+ assert_hostname=None,
+ assert_fingerprint=None,
+ ca_cert_dir=None,
+ ca_cert_data=None,
+ ):
"""
This method should only be called once, before the connection is used.
"""
@@ -310,6 +301,7 @@ class VerifiedHTTPSConnection(HTTPSConnection):
self.assert_fingerprint = assert_fingerprint
self.ca_certs = ca_certs and os.path.expanduser(ca_certs)
self.ca_cert_dir = ca_cert_dir and os.path.expanduser(ca_cert_dir)
+ self.ca_cert_data = ca_cert_data
def connect(self):
# Add certificate verification
@@ -317,7 +309,7 @@ class VerifiedHTTPSConnection(HTTPSConnection):
hostname = self.host
# Google App Engine's httplib does not define _tunnel_host
- if getattr(self, '_tunnel_host', None):
+ if getattr(self, "_tunnel_host", None):
self.sock = conn
# Calls self._set_hostport(), so self.host is
# self._tunnel_host below.
@@ -334,10 +326,12 @@ class VerifiedHTTPSConnection(HTTPSConnection):
is_time_off = datetime.date.today() < RECENT_DATE
if is_time_off:
- warnings.warn((
- 'System time is way off (before {0}). This will probably '
- 'lead to SSL verification errors').format(RECENT_DATE),
- SystemTimeWarning
+ warnings.warn(
+ (
+ "System time is way off (before {0}). This will probably "
+ "lead to SSL verification errors"
+ ).format(RECENT_DATE),
+ SystemTimeWarning,
)
# Wrap socket using verification with the root certs in
@@ -355,8 +349,13 @@ class VerifiedHTTPSConnection(HTTPSConnection):
# Try to load OS default certs if none are given.
# Works well on Windows (requires Python3.4+)
- if (not self.ca_certs and not self.ca_cert_dir and default_ssl_context
- and hasattr(context, 'load_default_certs')):
+ if (
+ not self.ca_certs
+ and not self.ca_cert_dir
+ and not self.ca_cert_data
+ and default_ssl_context
+ and hasattr(context, "load_default_certs")
+ ):
context.load_default_certs()
self.sock = ssl_wrap_socket(
@@ -366,32 +365,39 @@ class VerifiedHTTPSConnection(HTTPSConnection):
key_password=self.key_password,
ca_certs=self.ca_certs,
ca_cert_dir=self.ca_cert_dir,
+ ca_cert_data=self.ca_cert_data,
server_hostname=server_hostname,
- ssl_context=context)
+ ssl_context=context,
+ )
if self.assert_fingerprint:
- assert_fingerprint(self.sock.getpeercert(binary_form=True),
- self.assert_fingerprint)
- elif context.verify_mode != ssl.CERT_NONE \
- and not getattr(context, 'check_hostname', False) \
- and self.assert_hostname is not False:
+ assert_fingerprint(
+ self.sock.getpeercert(binary_form=True), self.assert_fingerprint
+ )
+ elif (
+ context.verify_mode != ssl.CERT_NONE
+ and not getattr(context, "check_hostname", False)
+ and self.assert_hostname is not False
+ ):
# While urllib3 attempts to always turn off hostname matching from
# the TLS library, this cannot always be done. So we check whether
# the TLS Library still thinks it's matching hostnames.
cert = self.sock.getpeercert()
- if not cert.get('subjectAltName', ()):
- warnings.warn((
- 'Certificate for {0} has no `subjectAltName`, falling back to check for a '
- '`commonName` for now. This feature is being removed by major browsers and '
- 'deprecated by RFC 2818. (See https://github.com/shazow/urllib3/issues/497 '
- 'for details.)'.format(hostname)),
- SubjectAltNameWarning
+ if not cert.get("subjectAltName", ()):
+ warnings.warn(
+ (
+ "Certificate for {0} has no `subjectAltName`, falling back to check for a "
+ "`commonName` for now. This feature is being removed by major browsers and "
+ "deprecated by RFC 2818. (See https://github.com/urllib3/urllib3/issues/497 "
+ "for details.)".format(hostname)
+ ),
+ SubjectAltNameWarning,
)
_match_hostname(cert, self.assert_hostname or server_hostname)
self.is_verified = (
- context.verify_mode == ssl.CERT_REQUIRED or
- self.assert_fingerprint is not None
+ context.verify_mode == ssl.CERT_REQUIRED
+ or self.assert_fingerprint is not None
)
@@ -399,9 +405,10 @@ def _match_hostname(cert, asserted_hostname):
try:
match_hostname(cert, asserted_hostname)
except CertificateError as e:
- log.error(
- 'Certificate did not match expected hostname: %s. '
- 'Certificate: %s', asserted_hostname, cert
+ log.warning(
+ "Certificate did not match expected hostname: %s. Certificate: %s",
+ asserted_hostname,
+ cert,
)
# Add cert to exception and reraise so client code can inspect
# the cert when catching the exception, if they want to
@@ -409,9 +416,8 @@ def _match_hostname(cert, asserted_hostname):
raise
-if ssl:
- # Make a copy for testing.
- UnverifiedHTTPSConnection = HTTPSConnection
- HTTPSConnection = VerifiedHTTPSConnection
-else:
- HTTPSConnection = DummyConnection
+if not ssl:
+ HTTPSConnection = DummyConnection # noqa: F811
+
+
+VerifiedHTTPSConnection = HTTPSConnection
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/connectionpool.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/connectionpool.py
index 157568a..5f044db 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/connectionpool.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/connectionpool.py
@@ -26,12 +26,14 @@ from .exceptions import (
from .packages.ssl_match_hostname import CertificateError
from .packages import six
from .packages.six.moves import queue
-from .packages.rfc3986.normalizers import normalize_host
from .connection import (
port_by_scheme,
DummyConnection,
- HTTPConnection, HTTPSConnection, VerifiedHTTPSConnection,
- HTTPException, BaseSSLError,
+ HTTPConnection,
+ HTTPSConnection,
+ VerifiedHTTPSConnection,
+ HTTPException,
+ BaseSSLError,
)
from .request import RequestMethods
from .response import HTTPResponse
@@ -41,7 +43,13 @@ from .util.request import set_file_position
from .util.response import assert_header_parsing
from .util.retry import Retry
from .util.timeout import Timeout
-from .util.url import get_host, Url, NORMALIZABLE_SCHEMES
+from .util.url import (
+ get_host,
+ parse_url,
+ Url,
+ _normalize_host as normalize_host,
+ _encode_target,
+)
from .util.queue import LifoQueue
@@ -57,6 +65,11 @@ class ConnectionPool(object):
"""
Base class for all connection pools, such as
:class:`.HTTPConnectionPool` and :class:`.HTTPSConnectionPool`.
+
+ .. note::
+ ConnectionPool.urlopen() does not normalize or percent-encode target URIs
+ which is useful if your target server doesn't support percent-encoded
+ target URIs.
"""
scheme = None
@@ -71,8 +84,7 @@ class ConnectionPool(object):
self.port = port
def __str__(self):
- return '%s(host=%r, port=%r)' % (type(self).__name__,
- self.host, self.port)
+ return "%s(host=%r, port=%r)" % (type(self).__name__, self.host, self.port)
def __enter__(self):
return self
@@ -153,15 +165,24 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
:class:`urllib3.connection.HTTPSConnection` instances.
"""
- scheme = 'http'
+ scheme = "http"
ConnectionCls = HTTPConnection
ResponseCls = HTTPResponse
- def __init__(self, host, port=None, strict=False,
- timeout=Timeout.DEFAULT_TIMEOUT, maxsize=1, block=False,
- headers=None, retries=None,
- _proxy=None, _proxy_headers=None,
- **conn_kw):
+ def __init__(
+ self,
+ host,
+ port=None,
+ strict=False,
+ timeout=Timeout.DEFAULT_TIMEOUT,
+ maxsize=1,
+ block=False,
+ headers=None,
+ retries=None,
+ _proxy=None,
+ _proxy_headers=None,
+ **conn_kw
+ ):
ConnectionPool.__init__(self, host, port)
RequestMethods.__init__(self, headers)
@@ -195,19 +216,27 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
# Enable Nagle's algorithm for proxies, to avoid packet fragmentation.
# We cannot know if the user has added default socket options, so we cannot replace the
# list.
- self.conn_kw.setdefault('socket_options', [])
+ self.conn_kw.setdefault("socket_options", [])
def _new_conn(self):
"""
Return a fresh :class:`HTTPConnection`.
"""
self.num_connections += 1
- log.debug("Starting new HTTP connection (%d): %s:%s",
- self.num_connections, self.host, self.port or "80")
+ log.debug(
+ "Starting new HTTP connection (%d): %s:%s",
+ self.num_connections,
+ self.host,
+ self.port or "80",
+ )
- conn = self.ConnectionCls(host=self.host, port=self.port,
- timeout=self.timeout.connect_timeout,
- strict=self.strict, **self.conn_kw)
+ conn = self.ConnectionCls(
+ host=self.host,
+ port=self.port,
+ timeout=self.timeout.connect_timeout,
+ strict=self.strict,
+ **self.conn_kw
+ )
return conn
def _get_conn(self, timeout=None):
@@ -231,16 +260,17 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
except queue.Empty:
if self.block:
- raise EmptyPoolError(self,
- "Pool reached maximum size and no more "
- "connections are allowed.")
+ raise EmptyPoolError(
+ self,
+ "Pool reached maximum size and no more connections are allowed.",
+ )
pass # Oh well, we'll create a new connection then
# If this is a persistent connection, check if it got disconnected
if conn and is_connection_dropped(conn):
log.debug("Resetting dropped connection: %s", self.host)
conn.close()
- if getattr(conn, 'auto_open', 1) == 0:
+ if getattr(conn, "auto_open", 1) == 0:
# This is a proxied connection that has been mutated by
# httplib._tunnel() and cannot be reused (since it would
# attempt to bypass the proxy)
@@ -270,9 +300,7 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
pass
except queue.Full:
# This should never happen if self.block == True
- log.warning(
- "Connection pool is full, discarding connection: %s",
- self.host)
+ log.warning("Connection pool is full, discarding connection: %s", self.host)
# Connection never got put back into the pool, close it.
if conn:
@@ -304,21 +332,30 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
"""Is the error actually a timeout? Will raise a ReadTimeout or pass"""
if isinstance(err, SocketTimeout):
- raise ReadTimeoutError(self, url, "Read timed out. (read timeout=%s)" % timeout_value)
+ raise ReadTimeoutError(
+ self, url, "Read timed out. (read timeout=%s)" % timeout_value
+ )
# See the above comment about EAGAIN in Python 3. In Python 2 we have
# to specifically catch it and throw the timeout error
- if hasattr(err, 'errno') and err.errno in _blocking_errnos:
- raise ReadTimeoutError(self, url, "Read timed out. (read timeout=%s)" % timeout_value)
+ if hasattr(err, "errno") and err.errno in _blocking_errnos:
+ raise ReadTimeoutError(
+ self, url, "Read timed out. (read timeout=%s)" % timeout_value
+ )
# Catch possible read timeouts thrown as SSL errors. If not the
# case, rethrow the original. We need to do this because of:
# http://bugs.python.org/issue10272
- if 'timed out' in str(err) or 'did not complete (read)' in str(err): # Python < 2.7.4
- raise ReadTimeoutError(self, url, "Read timed out. (read timeout=%s)" % timeout_value)
+ if "timed out" in str(err) or "did not complete (read)" in str(
+ err
+ ): # Python < 2.7.4
+ raise ReadTimeoutError(
+ self, url, "Read timed out. (read timeout=%s)" % timeout_value
+ )
- def _make_request(self, conn, method, url, timeout=_Default, chunked=False,
- **httplib_request_kw):
+ def _make_request(
+ self, conn, method, url, timeout=_Default, chunked=False, **httplib_request_kw
+ ):
"""
Perform a request on a given urllib connection object taken from our
pool.
@@ -358,7 +395,7 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
read_timeout = timeout_obj.read_timeout
# App Engine doesn't have a sock attr
- if getattr(conn, 'sock', None):
+ if getattr(conn, "sock", None):
# In Python 3 socket.py will catch EAGAIN and return None when you
# try and read into the file pointer created by http.client, which
# instead raises a BadStatusLine exception. Instead of catching
@@ -366,7 +403,8 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
# timeouts, check for a zero timeout before making the request.
if read_timeout == 0:
raise ReadTimeoutError(
- self, url, "Read timed out. (read timeout=%s)" % read_timeout)
+ self, url, "Read timed out. (read timeout=%s)" % read_timeout
+ )
if read_timeout is Timeout.DEFAULT_TIMEOUT:
conn.sock.settimeout(socket.getdefaulttimeout())
else: # None or a value
@@ -381,26 +419,38 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
# Python 3
try:
httplib_response = conn.getresponse()
- except Exception as e:
- # Remove the TypeError from the exception chain in Python 3;
- # otherwise it looks like a programming error was the cause.
+ except BaseException as e:
+ # Remove the TypeError from the exception chain in
+ # Python 3 (including for exceptions like SystemExit).
+ # Otherwise it looks like a bug in the code.
six.raise_from(e, None)
except (SocketTimeout, BaseSSLError, SocketError) as e:
self._raise_timeout(err=e, url=url, timeout_value=read_timeout)
raise
# AppEngine doesn't have a version attr.
- http_version = getattr(conn, '_http_vsn_str', 'HTTP/?')
- log.debug("%s://%s:%s \"%s %s %s\" %s %s", self.scheme, self.host, self.port,
- method, url, http_version, httplib_response.status,
- httplib_response.length)
+ http_version = getattr(conn, "_http_vsn_str", "HTTP/?")
+ log.debug(
+ '%s://%s:%s "%s %s %s" %s %s',
+ self.scheme,
+ self.host,
+ self.port,
+ method,
+ url,
+ http_version,
+ httplib_response.status,
+ httplib_response.length,
+ )
try:
assert_header_parsing(httplib_response.msg)
except (HeaderParsingError, TypeError) as hpe: # Platform-specific: Python 3
log.warning(
- 'Failed to parse headers (url=%s): %s',
- self._absolute_url(url), hpe, exc_info=True)
+ "Failed to parse headers (url=%s): %s",
+ self._absolute_url(url),
+ hpe,
+ exc_info=True,
+ )
return httplib_response
@@ -430,7 +480,7 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
Check if the given ``url`` is a member of the same host as this
connection pool.
"""
- if url.startswith('/'):
+ if url.startswith("/"):
return True
# TODO: Add optional support for socket.gethostbyname checking.
@@ -446,10 +496,22 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
return (scheme, host, port) == (self.scheme, self.host, self.port)
- def urlopen(self, method, url, body=None, headers=None, retries=None,
- redirect=True, assert_same_host=True, timeout=_Default,
- pool_timeout=None, release_conn=None, chunked=False,
- body_pos=None, **response_kw):
+ def urlopen(
+ self,
+ method,
+ url,
+ body=None,
+ headers=None,
+ retries=None,
+ redirect=True,
+ assert_same_host=True,
+ timeout=_Default,
+ pool_timeout=None,
+ release_conn=None,
+ chunked=False,
+ body_pos=None,
+ **response_kw
+ ):
"""
Get a connection from the pool and perform an HTTP request. This is the
lowest level call for making a request, so you'll need to specify all
@@ -547,12 +609,18 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
retries = Retry.from_int(retries, redirect=redirect, default=self.retries)
if release_conn is None:
- release_conn = response_kw.get('preload_content', True)
+ release_conn = response_kw.get("preload_content", True)
# Check host
if assert_same_host and not self.is_same_host(url):
raise HostChangedError(self, url, retries)
+ # Ensure that the URL we're connecting to is properly encoded
+ if url.startswith("/"):
+ url = six.ensure_str(_encode_target(url))
+ else:
+ url = six.ensure_str(parse_url(url).url)
+
conn = None
# Track whether `conn` needs to be released before
@@ -563,13 +631,13 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
#
# See issue #651 [1] for details.
#
- # [1]
+ # [1]
release_this_conn = release_conn
# Merge the proxy headers. Only do this in HTTP. We have to copy the
# headers dict so we can safely change it without those changes being
# reflected in anyone else's copy.
- if self.scheme == 'http':
+ if self.scheme == "http":
headers = headers.copy()
headers.update(self.proxy_headers)
@@ -592,15 +660,22 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
conn.timeout = timeout_obj.connect_timeout
- is_new_proxy_conn = self.proxy is not None and not getattr(conn, 'sock', None)
+ is_new_proxy_conn = self.proxy is not None and not getattr(
+ conn, "sock", None
+ )
if is_new_proxy_conn:
self._prepare_proxy(conn)
# Make the request on the httplib connection object.
- httplib_response = self._make_request(conn, method, url,
- timeout=timeout_obj,
- body=body, headers=headers,
- chunked=chunked)
+ httplib_response = self._make_request(
+ conn,
+ method,
+ url,
+ timeout=timeout_obj,
+ body=body,
+ headers=headers,
+ chunked=chunked,
+ )
# If we're going to release the connection in ``finally:``, then
# the response doesn't need to know about the connection. Otherwise
@@ -609,14 +684,16 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
response_conn = conn if not release_conn else None
# Pass method to Response for length checking
- response_kw['request_method'] = method
+ response_kw["request_method"] = method
# Import httplib's response into our own wrapper object
- response = self.ResponseCls.from_httplib(httplib_response,
- pool=self,
- connection=response_conn,
- retries=retries,
- **response_kw)
+ response = self.ResponseCls.from_httplib(
+ httplib_response,
+ pool=self,
+ connection=response_conn,
+ retries=retries,
+ **response_kw
+ )
# Everything went great!
clean_exit = True
@@ -625,20 +702,28 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
# Timed out by queue.
raise EmptyPoolError(self, "No pool connections are available.")
- except (TimeoutError, HTTPException, SocketError, ProtocolError,
- BaseSSLError, SSLError, CertificateError) as e:
+ except (
+ TimeoutError,
+ HTTPException,
+ SocketError,
+ ProtocolError,
+ BaseSSLError,
+ SSLError,
+ CertificateError,
+ ) as e:
# Discard the connection for these exceptions. It will be
# replaced during the next _get_conn() call.
clean_exit = False
if isinstance(e, (BaseSSLError, CertificateError)):
e = SSLError(e)
elif isinstance(e, (SocketError, NewConnectionError)) and self.proxy:
- e = ProxyError('Cannot connect to proxy.', e)
+ e = ProxyError("Cannot connect to proxy.", e)
elif isinstance(e, (SocketError, HTTPException)):
- e = ProtocolError('Connection aborted.', e)
+ e = ProtocolError("Connection aborted.", e)
- retries = retries.increment(method, url, error=e, _pool=self,
- _stacktrace=sys.exc_info()[2])
+ retries = retries.increment(
+ method, url, error=e, _pool=self, _stacktrace=sys.exc_info()[2]
+ )
retries.sleep()
# Keep track of the error for the retry warning.
@@ -661,77 +746,87 @@ class HTTPConnectionPool(ConnectionPool, RequestMethods):
if not conn:
# Try again
- log.warning("Retrying (%r) after connection "
- "broken by '%r': %s", retries, err, url)
- return self.urlopen(method, url, body, headers, retries,
- redirect, assert_same_host,
- timeout=timeout, pool_timeout=pool_timeout,
- release_conn=release_conn, body_pos=body_pos,
- **response_kw)
-
- def drain_and_release_conn(response):
- try:
- # discard any remaining response body, the connection will be
- # released back to the pool once the entire response is read
- response.read()
- except (TimeoutError, HTTPException, SocketError, ProtocolError,
- BaseSSLError, SSLError):
- pass
+ log.warning(
+ "Retrying (%r) after connection broken by '%r': %s", retries, err, url
+ )
+ return self.urlopen(
+ method,
+ url,
+ body,
+ headers,
+ retries,
+ redirect,
+ assert_same_host,
+ timeout=timeout,
+ pool_timeout=pool_timeout,
+ release_conn=release_conn,
+ chunked=chunked,
+ body_pos=body_pos,
+ **response_kw
+ )
# Handle redirect?
redirect_location = redirect and response.get_redirect_location()
if redirect_location:
if response.status == 303:
- method = 'GET'
+ method = "GET"
try:
retries = retries.increment(method, url, response=response, _pool=self)
except MaxRetryError:
if retries.raise_on_redirect:
- # Drain and release the connection for this response, since
- # we're not returning it to be released manually.
- drain_and_release_conn(response)
+ response.drain_conn()
raise
return response
- # drain and return the connection to the pool before recursing
- drain_and_release_conn(response)
-
+ response.drain_conn()
retries.sleep_for_retry(response)
log.debug("Redirecting %s -> %s", url, redirect_location)
return self.urlopen(
- method, redirect_location, body, headers,
- retries=retries, redirect=redirect,
+ method,
+ redirect_location,
+ body,
+ headers,
+ retries=retries,
+ redirect=redirect,
assert_same_host=assert_same_host,
- timeout=timeout, pool_timeout=pool_timeout,
- release_conn=release_conn, body_pos=body_pos,
- **response_kw)
+ timeout=timeout,
+ pool_timeout=pool_timeout,
+ release_conn=release_conn,
+ chunked=chunked,
+ body_pos=body_pos,
+ **response_kw
+ )
# Check if we should retry the HTTP response.
- has_retry_after = bool(response.getheader('Retry-After'))
+ has_retry_after = bool(response.getheader("Retry-After"))
if retries.is_retry(method, response.status, has_retry_after):
try:
retries = retries.increment(method, url, response=response, _pool=self)
except MaxRetryError:
if retries.raise_on_status:
- # Drain and release the connection for this response, since
- # we're not returning it to be released manually.
- drain_and_release_conn(response)
+ response.drain_conn()
raise
return response
- # drain and return the connection to the pool before recursing
- drain_and_release_conn(response)
-
+ response.drain_conn()
retries.sleep(response)
log.debug("Retry: %s", url)
return self.urlopen(
- method, url, body, headers,
- retries=retries, redirect=redirect,
+ method,
+ url,
+ body,
+ headers,
+ retries=retries,
+ redirect=redirect,
assert_same_host=assert_same_host,
- timeout=timeout, pool_timeout=pool_timeout,
+ timeout=timeout,
+ pool_timeout=pool_timeout,
release_conn=release_conn,
- body_pos=body_pos, **response_kw)
+ chunked=chunked,
+ body_pos=body_pos,
+ **response_kw
+ )
return response
@@ -754,21 +849,47 @@ class HTTPSConnectionPool(HTTPConnectionPool):
the connection socket into an SSL socket.
"""
- scheme = 'https'
+ scheme = "https"
ConnectionCls = HTTPSConnection
- def __init__(self, host, port=None,
- strict=False, timeout=Timeout.DEFAULT_TIMEOUT, maxsize=1,
- block=False, headers=None, retries=None,
- _proxy=None, _proxy_headers=None,
- key_file=None, cert_file=None, cert_reqs=None,
- key_password=None, ca_certs=None, ssl_version=None,
- assert_hostname=None, assert_fingerprint=None,
- ca_cert_dir=None, **conn_kw):
+ def __init__(
+ self,
+ host,
+ port=None,
+ strict=False,
+ timeout=Timeout.DEFAULT_TIMEOUT,
+ maxsize=1,
+ block=False,
+ headers=None,
+ retries=None,
+ _proxy=None,
+ _proxy_headers=None,
+ key_file=None,
+ cert_file=None,
+ cert_reqs=None,
+ key_password=None,
+ ca_certs=None,
+ ssl_version=None,
+ assert_hostname=None,
+ assert_fingerprint=None,
+ ca_cert_dir=None,
+ **conn_kw
+ ):
- HTTPConnectionPool.__init__(self, host, port, strict, timeout, maxsize,
- block, headers, retries, _proxy, _proxy_headers,
- **conn_kw)
+ HTTPConnectionPool.__init__(
+ self,
+ host,
+ port,
+ strict,
+ timeout,
+ maxsize,
+ block,
+ headers,
+ retries,
+ _proxy,
+ _proxy_headers,
+ **conn_kw
+ )
self.key_file = key_file
self.cert_file = cert_file
@@ -787,14 +908,16 @@ class HTTPSConnectionPool(HTTPConnectionPool):
"""
if isinstance(conn, VerifiedHTTPSConnection):
- conn.set_cert(key_file=self.key_file,
- key_password=self.key_password,
- cert_file=self.cert_file,
- cert_reqs=self.cert_reqs,
- ca_certs=self.ca_certs,
- ca_cert_dir=self.ca_cert_dir,
- assert_hostname=self.assert_hostname,
- assert_fingerprint=self.assert_fingerprint)
+ conn.set_cert(
+ key_file=self.key_file,
+ key_password=self.key_password,
+ cert_file=self.cert_file,
+ cert_reqs=self.cert_reqs,
+ ca_certs=self.ca_certs,
+ ca_cert_dir=self.ca_cert_dir,
+ assert_hostname=self.assert_hostname,
+ assert_fingerprint=self.assert_fingerprint,
+ )
conn.ssl_version = self.ssl_version
return conn
@@ -811,12 +934,17 @@ class HTTPSConnectionPool(HTTPConnectionPool):
Return a fresh :class:`httplib.HTTPSConnection`.
"""
self.num_connections += 1
- log.debug("Starting new HTTPS connection (%d): %s:%s",
- self.num_connections, self.host, self.port or "443")
+ log.debug(
+ "Starting new HTTPS connection (%d): %s:%s",
+ self.num_connections,
+ self.host,
+ self.port or "443",
+ )
if not self.ConnectionCls or self.ConnectionCls is DummyConnection:
- raise SSLError("Can't connect to HTTPS URL because the SSL "
- "module is not available.")
+ raise SSLError(
+ "Can't connect to HTTPS URL because the SSL module is not available."
+ )
actual_host = self.host
actual_port = self.port
@@ -824,11 +952,16 @@ class HTTPSConnectionPool(HTTPConnectionPool):
actual_host = self.proxy.host
actual_port = self.proxy.port
- conn = self.ConnectionCls(host=actual_host, port=actual_port,
- timeout=self.timeout.connect_timeout,
- strict=self.strict, cert_file=self.cert_file,
- key_file=self.key_file, key_password=self.key_password,
- **self.conn_kw)
+ conn = self.ConnectionCls(
+ host=actual_host,
+ port=actual_port,
+ timeout=self.timeout.connect_timeout,
+ strict=self.strict,
+ cert_file=self.cert_file,
+ key_file=self.key_file,
+ key_password=self.key_password,
+ **self.conn_kw
+ )
return self._prepare_conn(conn)
@@ -839,16 +972,19 @@ class HTTPSConnectionPool(HTTPConnectionPool):
super(HTTPSConnectionPool, self)._validate_conn(conn)
# Force connect early to allow us to validate the connection.
- if not getattr(conn, 'sock', None): # AppEngine might not have `.sock`
+ if not getattr(conn, "sock", None): # AppEngine might not have `.sock`
conn.connect()
if not conn.is_verified:
- warnings.warn((
- 'Unverified HTTPS request is being made. '
- 'Adding certificate verification is strongly advised. See: '
- 'https://urllib3.readthedocs.io/en/latest/advanced-usage.html'
- '#ssl-warnings'),
- InsecureRequestWarning)
+ warnings.warn(
+ (
+ "Unverified HTTPS request is being made to host '%s'. "
+ "Adding certificate verification is strongly advised. See: "
+ "https://urllib3.readthedocs.io/en/latest/advanced-usage.html"
+ "#ssl-warnings" % conn.host
+ ),
+ InsecureRequestWarning,
+ )
def connection_from_url(url, **kw):
@@ -873,7 +1009,7 @@ def connection_from_url(url, **kw):
"""
scheme, host, port = get_host(url)
port = port or port_by_scheme.get(scheme, 80)
- if scheme == 'https':
+ if scheme == "https":
return HTTPSConnectionPool(host, port=port, **kw)
else:
return HTTPConnectionPool(host, port=port, **kw)
@@ -884,14 +1020,14 @@ def _normalize_host(host, scheme):
Normalize hosts for comparisons and use with sockets.
"""
+ host = normalize_host(host, scheme)
+
# httplib doesn't like it when we include brackets in IPv6 addresses
# Specifically, if we include brackets but also pass the port then
# httplib crazily doubles up the square brackets on the Host header.
# Instead, we need to make sure we never pass ``None`` as the port.
# However, for backward compatibility reasons we can't actually
# *assert* that. See http://bugs.python.org/issue28539
- if host.startswith('[') and host.endswith(']'):
- host = host.strip('[]')
- if scheme in NORMALIZABLE_SCHEMES:
- host = normalize_host(host)
+ if host.startswith("[") and host.endswith("]"):
+ host = host[1:-1]
return host
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-38.pyc
index 3aaa314..4bfd886 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-38.pyc
index 905d307..f205bc2 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-38.pyc
index 5c7cf28..658d573 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-38.pyc
index bc422ce..cef79f6 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-38.pyc
index 106654a..15cd451 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-38.pyc
index cd9b92c..09fb526 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-38.pyc
index 7275b68..e4e94eb 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py
index f3e0094..8765b90 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py
@@ -6,25 +6,31 @@ import os
def is_appengine():
- return (is_local_appengine() or
- is_prod_appengine() or
- is_prod_appengine_mvms())
+ return is_local_appengine() or is_prod_appengine()
def is_appengine_sandbox():
- return is_appengine() and not is_prod_appengine_mvms()
+ """Reports if the app is running in the first generation sandbox.
+
+ The second generation runtimes are technically still in a sandbox, but it
+ is much less restrictive, so generally you shouldn't need to check for it.
+ see https://cloud.google.com/appengine/docs/standard/runtimes
+ """
+ return is_appengine() and os.environ["APPENGINE_RUNTIME"] == "python27"
def is_local_appengine():
- return ('APPENGINE_RUNTIME' in os.environ and
- 'Development/' in os.environ['SERVER_SOFTWARE'])
+ return "APPENGINE_RUNTIME" in os.environ and os.environ.get(
+ "SERVER_SOFTWARE", ""
+ ).startswith("Development/")
def is_prod_appengine():
- return ('APPENGINE_RUNTIME' in os.environ and
- 'Google App Engine/' in os.environ['SERVER_SOFTWARE'] and
- not is_prod_appengine_mvms())
+ return "APPENGINE_RUNTIME" in os.environ and os.environ.get(
+ "SERVER_SOFTWARE", ""
+ ).startswith("Google App Engine/")
def is_prod_appengine_mvms():
- return os.environ.get('GAE_VM', False) == 'true'
+ """Deprecated."""
+ return False
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-38.pyc
index 8d30833..cf2d152 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-38.pyc
index 6191aed..d44d867 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-38.pyc
index eaf7a87..1b0d79b 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py
index be34215..d9b6733 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py
@@ -34,29 +34,35 @@ from __future__ import absolute_import
import platform
from ctypes.util import find_library
from ctypes import (
- c_void_p, c_int32, c_char_p, c_size_t, c_byte, c_uint32, c_ulong, c_long,
- c_bool
+ c_void_p,
+ c_int32,
+ c_char_p,
+ c_size_t,
+ c_byte,
+ c_uint32,
+ c_ulong,
+ c_long,
+ c_bool,
)
from ctypes import CDLL, POINTER, CFUNCTYPE
-security_path = find_library('Security')
+security_path = find_library("Security")
if not security_path:
- raise ImportError('The library Security could not be found')
+ raise ImportError("The library Security could not be found")
-core_foundation_path = find_library('CoreFoundation')
+core_foundation_path = find_library("CoreFoundation")
if not core_foundation_path:
- raise ImportError('The library CoreFoundation could not be found')
+ raise ImportError("The library CoreFoundation could not be found")
version = platform.mac_ver()[0]
-version_info = tuple(map(int, version.split('.')))
+version_info = tuple(map(int, version.split(".")))
if version_info < (10, 8):
raise OSError(
- 'Only OS X 10.8 and newer are supported, not %s.%s' % (
- version_info[0], version_info[1]
- )
+ "Only OS X 10.8 and newer are supported, not %s.%s"
+ % (version_info[0], version_info[1])
)
Security = CDLL(security_path, use_errno=True)
@@ -129,27 +135,19 @@ try:
Security.SecKeyGetTypeID.argtypes = []
Security.SecKeyGetTypeID.restype = CFTypeID
- Security.SecCertificateCreateWithData.argtypes = [
- CFAllocatorRef,
- CFDataRef
- ]
+ Security.SecCertificateCreateWithData.argtypes = [CFAllocatorRef, CFDataRef]
Security.SecCertificateCreateWithData.restype = SecCertificateRef
- Security.SecCertificateCopyData.argtypes = [
- SecCertificateRef
- ]
+ Security.SecCertificateCopyData.argtypes = [SecCertificateRef]
Security.SecCertificateCopyData.restype = CFDataRef
- Security.SecCopyErrorMessageString.argtypes = [
- OSStatus,
- c_void_p
- ]
+ Security.SecCopyErrorMessageString.argtypes = [OSStatus, c_void_p]
Security.SecCopyErrorMessageString.restype = CFStringRef
Security.SecIdentityCreateWithCertificate.argtypes = [
CFTypeRef,
SecCertificateRef,
- POINTER(SecIdentityRef)
+ POINTER(SecIdentityRef),
]
Security.SecIdentityCreateWithCertificate.restype = OSStatus
@@ -159,201 +157,126 @@ try:
c_void_p,
Boolean,
c_void_p,
- POINTER(SecKeychainRef)
+ POINTER(SecKeychainRef),
]
Security.SecKeychainCreate.restype = OSStatus
- Security.SecKeychainDelete.argtypes = [
- SecKeychainRef
- ]
+ Security.SecKeychainDelete.argtypes = [SecKeychainRef]
Security.SecKeychainDelete.restype = OSStatus
Security.SecPKCS12Import.argtypes = [
CFDataRef,
CFDictionaryRef,
- POINTER(CFArrayRef)
+ POINTER(CFArrayRef),
]
Security.SecPKCS12Import.restype = OSStatus
SSLReadFunc = CFUNCTYPE(OSStatus, SSLConnectionRef, c_void_p, POINTER(c_size_t))
- SSLWriteFunc = CFUNCTYPE(OSStatus, SSLConnectionRef, POINTER(c_byte), POINTER(c_size_t))
+ SSLWriteFunc = CFUNCTYPE(
+ OSStatus, SSLConnectionRef, POINTER(c_byte), POINTER(c_size_t)
+ )
- Security.SSLSetIOFuncs.argtypes = [
- SSLContextRef,
- SSLReadFunc,
- SSLWriteFunc
- ]
+ Security.SSLSetIOFuncs.argtypes = [SSLContextRef, SSLReadFunc, SSLWriteFunc]
Security.SSLSetIOFuncs.restype = OSStatus
- Security.SSLSetPeerID.argtypes = [
- SSLContextRef,
- c_char_p,
- c_size_t
- ]
+ Security.SSLSetPeerID.argtypes = [SSLContextRef, c_char_p, c_size_t]
Security.SSLSetPeerID.restype = OSStatus
- Security.SSLSetCertificate.argtypes = [
- SSLContextRef,
- CFArrayRef
- ]
+ Security.SSLSetCertificate.argtypes = [SSLContextRef, CFArrayRef]
Security.SSLSetCertificate.restype = OSStatus
- Security.SSLSetCertificateAuthorities.argtypes = [
- SSLContextRef,
- CFTypeRef,
- Boolean
- ]
+ Security.SSLSetCertificateAuthorities.argtypes = [SSLContextRef, CFTypeRef, Boolean]
Security.SSLSetCertificateAuthorities.restype = OSStatus
- Security.SSLSetConnection.argtypes = [
- SSLContextRef,
- SSLConnectionRef
- ]
+ Security.SSLSetConnection.argtypes = [SSLContextRef, SSLConnectionRef]
Security.SSLSetConnection.restype = OSStatus
- Security.SSLSetPeerDomainName.argtypes = [
- SSLContextRef,
- c_char_p,
- c_size_t
- ]
+ Security.SSLSetPeerDomainName.argtypes = [SSLContextRef, c_char_p, c_size_t]
Security.SSLSetPeerDomainName.restype = OSStatus
- Security.SSLHandshake.argtypes = [
- SSLContextRef
- ]
+ Security.SSLHandshake.argtypes = [SSLContextRef]
Security.SSLHandshake.restype = OSStatus
- Security.SSLRead.argtypes = [
- SSLContextRef,
- c_char_p,
- c_size_t,
- POINTER(c_size_t)
- ]
+ Security.SSLRead.argtypes = [SSLContextRef, c_char_p, c_size_t, POINTER(c_size_t)]
Security.SSLRead.restype = OSStatus
- Security.SSLWrite.argtypes = [
- SSLContextRef,
- c_char_p,
- c_size_t,
- POINTER(c_size_t)
- ]
+ Security.SSLWrite.argtypes = [SSLContextRef, c_char_p, c_size_t, POINTER(c_size_t)]
Security.SSLWrite.restype = OSStatus
- Security.SSLClose.argtypes = [
- SSLContextRef
- ]
+ Security.SSLClose.argtypes = [SSLContextRef]
Security.SSLClose.restype = OSStatus
- Security.SSLGetNumberSupportedCiphers.argtypes = [
- SSLContextRef,
- POINTER(c_size_t)
- ]
+ Security.SSLGetNumberSupportedCiphers.argtypes = [SSLContextRef, POINTER(c_size_t)]
Security.SSLGetNumberSupportedCiphers.restype = OSStatus
Security.SSLGetSupportedCiphers.argtypes = [
SSLContextRef,
POINTER(SSLCipherSuite),
- POINTER(c_size_t)
+ POINTER(c_size_t),
]
Security.SSLGetSupportedCiphers.restype = OSStatus
Security.SSLSetEnabledCiphers.argtypes = [
SSLContextRef,
POINTER(SSLCipherSuite),
- c_size_t
+ c_size_t,
]
Security.SSLSetEnabledCiphers.restype = OSStatus
- Security.SSLGetNumberEnabledCiphers.argtype = [
- SSLContextRef,
- POINTER(c_size_t)
- ]
+ Security.SSLGetNumberEnabledCiphers.argtype = [SSLContextRef, POINTER(c_size_t)]
Security.SSLGetNumberEnabledCiphers.restype = OSStatus
Security.SSLGetEnabledCiphers.argtypes = [
SSLContextRef,
POINTER(SSLCipherSuite),
- POINTER(c_size_t)
+ POINTER(c_size_t),
]
Security.SSLGetEnabledCiphers.restype = OSStatus
- Security.SSLGetNegotiatedCipher.argtypes = [
- SSLContextRef,
- POINTER(SSLCipherSuite)
- ]
+ Security.SSLGetNegotiatedCipher.argtypes = [SSLContextRef, POINTER(SSLCipherSuite)]
Security.SSLGetNegotiatedCipher.restype = OSStatus
Security.SSLGetNegotiatedProtocolVersion.argtypes = [
SSLContextRef,
- POINTER(SSLProtocol)
+ POINTER(SSLProtocol),
]
Security.SSLGetNegotiatedProtocolVersion.restype = OSStatus
- Security.SSLCopyPeerTrust.argtypes = [
- SSLContextRef,
- POINTER(SecTrustRef)
- ]
+ Security.SSLCopyPeerTrust.argtypes = [SSLContextRef, POINTER(SecTrustRef)]
Security.SSLCopyPeerTrust.restype = OSStatus
- Security.SecTrustSetAnchorCertificates.argtypes = [
- SecTrustRef,
- CFArrayRef
- ]
+ Security.SecTrustSetAnchorCertificates.argtypes = [SecTrustRef, CFArrayRef]
Security.SecTrustSetAnchorCertificates.restype = OSStatus
- Security.SecTrustSetAnchorCertificatesOnly.argstypes = [
- SecTrustRef,
- Boolean
- ]
+ Security.SecTrustSetAnchorCertificatesOnly.argstypes = [SecTrustRef, Boolean]
Security.SecTrustSetAnchorCertificatesOnly.restype = OSStatus
- Security.SecTrustEvaluate.argtypes = [
- SecTrustRef,
- POINTER(SecTrustResultType)
- ]
+ Security.SecTrustEvaluate.argtypes = [SecTrustRef, POINTER(SecTrustResultType)]
Security.SecTrustEvaluate.restype = OSStatus
- Security.SecTrustGetCertificateCount.argtypes = [
- SecTrustRef
- ]
+ Security.SecTrustGetCertificateCount.argtypes = [SecTrustRef]
Security.SecTrustGetCertificateCount.restype = CFIndex
- Security.SecTrustGetCertificateAtIndex.argtypes = [
- SecTrustRef,
- CFIndex
- ]
+ Security.SecTrustGetCertificateAtIndex.argtypes = [SecTrustRef, CFIndex]
Security.SecTrustGetCertificateAtIndex.restype = SecCertificateRef
Security.SSLCreateContext.argtypes = [
CFAllocatorRef,
SSLProtocolSide,
- SSLConnectionType
+ SSLConnectionType,
]
Security.SSLCreateContext.restype = SSLContextRef
- Security.SSLSetSessionOption.argtypes = [
- SSLContextRef,
- SSLSessionOption,
- Boolean
- ]
+ Security.SSLSetSessionOption.argtypes = [SSLContextRef, SSLSessionOption, Boolean]
Security.SSLSetSessionOption.restype = OSStatus
- Security.SSLSetProtocolVersionMin.argtypes = [
- SSLContextRef,
- SSLProtocol
- ]
+ Security.SSLSetProtocolVersionMin.argtypes = [SSLContextRef, SSLProtocol]
Security.SSLSetProtocolVersionMin.restype = OSStatus
- Security.SSLSetProtocolVersionMax.argtypes = [
- SSLContextRef,
- SSLProtocol
- ]
+ Security.SSLSetProtocolVersionMax.argtypes = [SSLContextRef, SSLProtocol]
Security.SSLSetProtocolVersionMax.restype = OSStatus
- Security.SecCopyErrorMessageString.argtypes = [
- OSStatus,
- c_void_p
- ]
+ Security.SecCopyErrorMessageString.argtypes = [OSStatus, c_void_p]
Security.SecCopyErrorMessageString.restype = CFStringRef
Security.SSLReadFunc = SSLReadFunc
@@ -369,64 +292,47 @@ try:
Security.OSStatus = OSStatus
Security.kSecImportExportPassphrase = CFStringRef.in_dll(
- Security, 'kSecImportExportPassphrase'
+ Security, "kSecImportExportPassphrase"
)
Security.kSecImportItemIdentity = CFStringRef.in_dll(
- Security, 'kSecImportItemIdentity'
+ Security, "kSecImportItemIdentity"
)
# CoreFoundation time!
- CoreFoundation.CFRetain.argtypes = [
- CFTypeRef
- ]
+ CoreFoundation.CFRetain.argtypes = [CFTypeRef]
CoreFoundation.CFRetain.restype = CFTypeRef
- CoreFoundation.CFRelease.argtypes = [
- CFTypeRef
- ]
+ CoreFoundation.CFRelease.argtypes = [CFTypeRef]
CoreFoundation.CFRelease.restype = None
- CoreFoundation.CFGetTypeID.argtypes = [
- CFTypeRef
- ]
+ CoreFoundation.CFGetTypeID.argtypes = [CFTypeRef]
CoreFoundation.CFGetTypeID.restype = CFTypeID
CoreFoundation.CFStringCreateWithCString.argtypes = [
CFAllocatorRef,
c_char_p,
- CFStringEncoding
+ CFStringEncoding,
]
CoreFoundation.CFStringCreateWithCString.restype = CFStringRef
- CoreFoundation.CFStringGetCStringPtr.argtypes = [
- CFStringRef,
- CFStringEncoding
- ]
+ CoreFoundation.CFStringGetCStringPtr.argtypes = [CFStringRef, CFStringEncoding]
CoreFoundation.CFStringGetCStringPtr.restype = c_char_p
CoreFoundation.CFStringGetCString.argtypes = [
CFStringRef,
c_char_p,
CFIndex,
- CFStringEncoding
+ CFStringEncoding,
]
CoreFoundation.CFStringGetCString.restype = c_bool
- CoreFoundation.CFDataCreate.argtypes = [
- CFAllocatorRef,
- c_char_p,
- CFIndex
- ]
+ CoreFoundation.CFDataCreate.argtypes = [CFAllocatorRef, c_char_p, CFIndex]
CoreFoundation.CFDataCreate.restype = CFDataRef
- CoreFoundation.CFDataGetLength.argtypes = [
- CFDataRef
- ]
+ CoreFoundation.CFDataGetLength.argtypes = [CFDataRef]
CoreFoundation.CFDataGetLength.restype = CFIndex
- CoreFoundation.CFDataGetBytePtr.argtypes = [
- CFDataRef
- ]
+ CoreFoundation.CFDataGetBytePtr.argtypes = [CFDataRef]
CoreFoundation.CFDataGetBytePtr.restype = c_void_p
CoreFoundation.CFDictionaryCreate.argtypes = [
@@ -435,14 +341,11 @@ try:
POINTER(CFTypeRef),
CFIndex,
CFDictionaryKeyCallBacks,
- CFDictionaryValueCallBacks
+ CFDictionaryValueCallBacks,
]
CoreFoundation.CFDictionaryCreate.restype = CFDictionaryRef
- CoreFoundation.CFDictionaryGetValue.argtypes = [
- CFDictionaryRef,
- CFTypeRef
- ]
+ CoreFoundation.CFDictionaryGetValue.argtypes = [CFDictionaryRef, CFTypeRef]
CoreFoundation.CFDictionaryGetValue.restype = CFTypeRef
CoreFoundation.CFArrayCreate.argtypes = [
@@ -456,36 +359,30 @@ try:
CoreFoundation.CFArrayCreateMutable.argtypes = [
CFAllocatorRef,
CFIndex,
- CFArrayCallBacks
+ CFArrayCallBacks,
]
CoreFoundation.CFArrayCreateMutable.restype = CFMutableArrayRef
- CoreFoundation.CFArrayAppendValue.argtypes = [
- CFMutableArrayRef,
- c_void_p
- ]
+ CoreFoundation.CFArrayAppendValue.argtypes = [CFMutableArrayRef, c_void_p]
CoreFoundation.CFArrayAppendValue.restype = None
- CoreFoundation.CFArrayGetCount.argtypes = [
- CFArrayRef
- ]
+ CoreFoundation.CFArrayGetCount.argtypes = [CFArrayRef]
CoreFoundation.CFArrayGetCount.restype = CFIndex
- CoreFoundation.CFArrayGetValueAtIndex.argtypes = [
- CFArrayRef,
- CFIndex
- ]
+ CoreFoundation.CFArrayGetValueAtIndex.argtypes = [CFArrayRef, CFIndex]
CoreFoundation.CFArrayGetValueAtIndex.restype = c_void_p
CoreFoundation.kCFAllocatorDefault = CFAllocatorRef.in_dll(
- CoreFoundation, 'kCFAllocatorDefault'
+ CoreFoundation, "kCFAllocatorDefault"
+ )
+ CoreFoundation.kCFTypeArrayCallBacks = c_void_p.in_dll(
+ CoreFoundation, "kCFTypeArrayCallBacks"
)
- CoreFoundation.kCFTypeArrayCallBacks = c_void_p.in_dll(CoreFoundation, 'kCFTypeArrayCallBacks')
CoreFoundation.kCFTypeDictionaryKeyCallBacks = c_void_p.in_dll(
- CoreFoundation, 'kCFTypeDictionaryKeyCallBacks'
+ CoreFoundation, "kCFTypeDictionaryKeyCallBacks"
)
CoreFoundation.kCFTypeDictionaryValueCallBacks = c_void_p.in_dll(
- CoreFoundation, 'kCFTypeDictionaryValueCallBacks'
+ CoreFoundation, "kCFTypeDictionaryValueCallBacks"
)
CoreFoundation.CFTypeRef = CFTypeRef
@@ -494,7 +391,7 @@ try:
CoreFoundation.CFDictionaryRef = CFDictionaryRef
except (AttributeError):
- raise ImportError('Error initializing ctypes')
+ raise ImportError("Error initializing ctypes")
class CFConst(object):
@@ -502,6 +399,7 @@ class CFConst(object):
A class object that acts as essentially a namespace for CoreFoundation
constants.
"""
+
kCFStringEncodingUTF8 = CFStringEncoding(0x08000100)
@@ -509,6 +407,7 @@ class SecurityConst(object):
"""
A class object that acts as essentially a namespace for Security constants.
"""
+
kSSLSessionOptionBreakOnServerAuth = 0
kSSLProtocol2 = 1
@@ -516,6 +415,7 @@ class SecurityConst(object):
kTLSProtocol1 = 4
kTLSProtocol11 = 7
kTLSProtocol12 = 8
+ # SecureTransport does not support TLS 1.3 even if there's a constant for it
kTLSProtocol13 = 10
kTLSProtocolMaxSupported = 999
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py
index b13cd9e..e60168c 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py
@@ -66,22 +66,18 @@ def _cf_string_to_unicode(value):
value_as_void_p = ctypes.cast(value, ctypes.POINTER(ctypes.c_void_p))
string = CoreFoundation.CFStringGetCStringPtr(
- value_as_void_p,
- CFConst.kCFStringEncodingUTF8
+ value_as_void_p, CFConst.kCFStringEncodingUTF8
)
if string is None:
buffer = ctypes.create_string_buffer(1024)
result = CoreFoundation.CFStringGetCString(
- value_as_void_p,
- buffer,
- 1024,
- CFConst.kCFStringEncodingUTF8
+ value_as_void_p, buffer, 1024, CFConst.kCFStringEncodingUTF8
)
if not result:
- raise OSError('Error copying C string from CFStringRef')
+ raise OSError("Error copying C string from CFStringRef")
string = buffer.value
if string is not None:
- string = string.decode('utf-8')
+ string = string.decode("utf-8")
return string
@@ -97,8 +93,8 @@ def _assert_no_error(error, exception_class=None):
output = _cf_string_to_unicode(cf_error_string)
CoreFoundation.CFRelease(cf_error_string)
- if output is None or output == u'':
- output = u'OSStatus %s' % error
+ if output is None or output == u"":
+ output = u"OSStatus %s" % error
if exception_class is None:
exception_class = ssl.SSLError
@@ -115,8 +111,7 @@ def _cert_array_from_pem(pem_bundle):
pem_bundle = pem_bundle.replace(b"\r\n", b"\n")
der_certs = [
- base64.b64decode(match.group(1))
- for match in _PEM_CERTS_RE.finditer(pem_bundle)
+ base64.b64decode(match.group(1)) for match in _PEM_CERTS_RE.finditer(pem_bundle)
]
if not der_certs:
raise ssl.SSLError("No root certificates specified")
@@ -124,7 +119,7 @@ def _cert_array_from_pem(pem_bundle):
cert_array = CoreFoundation.CFArrayCreateMutable(
CoreFoundation.kCFAllocatorDefault,
0,
- ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks)
+ ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks),
)
if not cert_array:
raise ssl.SSLError("Unable to allocate memory!")
@@ -186,21 +181,16 @@ def _temporary_keychain():
# some random bytes to password-protect the keychain we're creating, so we
# ask for 40 random bytes.
random_bytes = os.urandom(40)
- filename = base64.b16encode(random_bytes[:8]).decode('utf-8')
+ filename = base64.b16encode(random_bytes[:8]).decode("utf-8")
password = base64.b16encode(random_bytes[8:]) # Must be valid UTF-8
tempdirectory = tempfile.mkdtemp()
- keychain_path = os.path.join(tempdirectory, filename).encode('utf-8')
+ keychain_path = os.path.join(tempdirectory, filename).encode("utf-8")
# We now want to create the keychain itself.
keychain = Security.SecKeychainRef()
status = Security.SecKeychainCreate(
- keychain_path,
- len(password),
- password,
- False,
- None,
- ctypes.byref(keychain)
+ keychain_path, len(password), password, False, None, ctypes.byref(keychain)
)
_assert_no_error(status)
@@ -219,14 +209,12 @@ def _load_items_from_file(keychain, path):
identities = []
result_array = None
- with open(path, 'rb') as f:
+ with open(path, "rb") as f:
raw_filedata = f.read()
try:
filedata = CoreFoundation.CFDataCreate(
- CoreFoundation.kCFAllocatorDefault,
- raw_filedata,
- len(raw_filedata)
+ CoreFoundation.kCFAllocatorDefault, raw_filedata, len(raw_filedata)
)
result_array = CoreFoundation.CFArrayRef()
result = Security.SecItemImport(
@@ -237,7 +225,7 @@ def _load_items_from_file(keychain, path):
0, # import flags
None, # key params, can include passphrase in the future
keychain, # The keychain to insert into
- ctypes.byref(result_array) # Results
+ ctypes.byref(result_array), # Results
)
_assert_no_error(result)
@@ -247,9 +235,7 @@ def _load_items_from_file(keychain, path):
# keychain already has them!
result_count = CoreFoundation.CFArrayGetCount(result_array)
for index in range(result_count):
- item = CoreFoundation.CFArrayGetValueAtIndex(
- result_array, index
- )
+ item = CoreFoundation.CFArrayGetValueAtIndex(result_array, index)
item = ctypes.cast(item, CoreFoundation.CFTypeRef)
if _is_cert(item):
@@ -307,9 +293,7 @@ def _load_client_cert_chain(keychain, *paths):
try:
for file_path in paths:
- new_identities, new_certs = _load_items_from_file(
- keychain, file_path
- )
+ new_identities, new_certs = _load_items_from_file(keychain, file_path)
identities.extend(new_identities)
certificates.extend(new_certs)
@@ -318,9 +302,7 @@ def _load_client_cert_chain(keychain, *paths):
if not identities:
new_identity = Security.SecIdentityRef()
status = Security.SecIdentityCreateWithCertificate(
- keychain,
- certificates[0],
- ctypes.byref(new_identity)
+ keychain, certificates[0], ctypes.byref(new_identity)
)
_assert_no_error(status)
identities.append(new_identity)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/appengine.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/appengine.py
index 9b42952..d09d2be 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/appengine.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/appengine.py
@@ -50,7 +50,7 @@ from ..exceptions import (
MaxRetryError,
ProtocolError,
TimeoutError,
- SSLError
+ SSLError,
)
from ..request import RequestMethods
@@ -96,23 +96,24 @@ class AppEngineManager(RequestMethods):
Beyond those cases, it will raise normal urllib3 errors.
"""
- def __init__(self, headers=None, retries=None, validate_certificate=True,
- urlfetch_retries=True):
+ def __init__(
+ self,
+ headers=None,
+ retries=None,
+ validate_certificate=True,
+ urlfetch_retries=True,
+ ):
if not urlfetch:
raise AppEnginePlatformError(
- "URLFetch is not available in this environment.")
-
- if is_prod_appengine_mvms():
- raise AppEnginePlatformError(
- "Use normal urllib3.PoolManager instead of AppEngineManager"
- "on Managed VMs, as using URLFetch is not necessary in "
- "this environment.")
+ "URLFetch is not available in this environment."
+ )
warnings.warn(
"urllib3 is using URLFetch on Google App Engine sandbox instead "
"of sockets. To use sockets directly instead of URLFetch see "
"https://urllib3.readthedocs.io/en/latest/reference/urllib3.contrib.html.",
- AppEnginePlatformWarning)
+ AppEnginePlatformWarning,
+ )
RequestMethods.__init__(self, headers)
self.validate_certificate = validate_certificate
@@ -127,17 +128,22 @@ class AppEngineManager(RequestMethods):
# Return False to re-raise any potential exceptions
return False
- def urlopen(self, method, url, body=None, headers=None,
- retries=None, redirect=True, timeout=Timeout.DEFAULT_TIMEOUT,
- **response_kw):
+ def urlopen(
+ self,
+ method,
+ url,
+ body=None,
+ headers=None,
+ retries=None,
+ redirect=True,
+ timeout=Timeout.DEFAULT_TIMEOUT,
+ **response_kw
+ ):
retries = self._get_retries(retries, redirect)
try:
- follow_redirects = (
- redirect and
- retries.redirect != 0 and
- retries.total)
+ follow_redirects = redirect and retries.redirect != 0 and retries.total
response = urlfetch.fetch(
url,
payload=body,
@@ -152,44 +158,52 @@ class AppEngineManager(RequestMethods):
raise TimeoutError(self, e)
except urlfetch.InvalidURLError as e:
- if 'too large' in str(e):
+ if "too large" in str(e):
raise AppEnginePlatformError(
"URLFetch request too large, URLFetch only "
- "supports requests up to 10mb in size.", e)
+ "supports requests up to 10mb in size.",
+ e,
+ )
raise ProtocolError(e)
except urlfetch.DownloadError as e:
- if 'Too many redirects' in str(e):
+ if "Too many redirects" in str(e):
raise MaxRetryError(self, url, reason=e)
raise ProtocolError(e)
except urlfetch.ResponseTooLargeError as e:
raise AppEnginePlatformError(
"URLFetch response too large, URLFetch only supports"
- "responses up to 32mb in size.", e)
+ "responses up to 32mb in size.",
+ e,
+ )
except urlfetch.SSLCertificateError as e:
raise SSLError(e)
except urlfetch.InvalidMethodError as e:
raise AppEnginePlatformError(
- "URLFetch does not support method: %s" % method, e)
+ "URLFetch does not support method: %s" % method, e
+ )
http_response = self._urlfetch_response_to_http_response(
- response, retries=retries, **response_kw)
+ response, retries=retries, **response_kw
+ )
# Handle redirect?
redirect_location = redirect and http_response.get_redirect_location()
if redirect_location:
# Check for redirect response
- if (self.urlfetch_retries and retries.raise_on_redirect):
+ if self.urlfetch_retries and retries.raise_on_redirect:
raise MaxRetryError(self, url, "too many redirects")
else:
if http_response.status == 303:
- method = 'GET'
+ method = "GET"
try:
- retries = retries.increment(method, url, response=http_response, _pool=self)
+ retries = retries.increment(
+ method, url, response=http_response, _pool=self
+ )
except MaxRetryError:
if retries.raise_on_redirect:
raise MaxRetryError(self, url, "too many redirects")
@@ -199,22 +213,32 @@ class AppEngineManager(RequestMethods):
log.debug("Redirecting %s -> %s", url, redirect_location)
redirect_url = urljoin(url, redirect_location)
return self.urlopen(
- method, redirect_url, body, headers,
- retries=retries, redirect=redirect,
- timeout=timeout, **response_kw)
+ method,
+ redirect_url,
+ body,
+ headers,
+ retries=retries,
+ redirect=redirect,
+ timeout=timeout,
+ **response_kw
+ )
# Check if we should retry the HTTP response.
- has_retry_after = bool(http_response.getheader('Retry-After'))
+ has_retry_after = bool(http_response.getheader("Retry-After"))
if retries.is_retry(method, http_response.status, has_retry_after):
- retries = retries.increment(
- method, url, response=http_response, _pool=self)
+ retries = retries.increment(method, url, response=http_response, _pool=self)
log.debug("Retry: %s", url)
retries.sleep(http_response)
return self.urlopen(
- method, url,
- body=body, headers=headers,
- retries=retries, redirect=redirect,
- timeout=timeout, **response_kw)
+ method,
+ url,
+ body=body,
+ headers=headers,
+ retries=retries,
+ redirect=redirect,
+ timeout=timeout,
+ **response_kw
+ )
return http_response
@@ -223,18 +247,18 @@ class AppEngineManager(RequestMethods):
if is_prod_appengine():
# Production GAE handles deflate encoding automatically, but does
# not remove the encoding header.
- content_encoding = urlfetch_resp.headers.get('content-encoding')
+ content_encoding = urlfetch_resp.headers.get("content-encoding")
- if content_encoding == 'deflate':
- del urlfetch_resp.headers['content-encoding']
+ if content_encoding == "deflate":
+ del urlfetch_resp.headers["content-encoding"]
- transfer_encoding = urlfetch_resp.headers.get('transfer-encoding')
+ transfer_encoding = urlfetch_resp.headers.get("transfer-encoding")
# We have a full response's content,
# so let's make sure we don't report ourselves as chunked data.
- if transfer_encoding == 'chunked':
+ if transfer_encoding == "chunked":
encodings = transfer_encoding.split(",")
- encodings.remove('chunked')
- urlfetch_resp.headers['transfer-encoding'] = ','.join(encodings)
+ encodings.remove("chunked")
+ urlfetch_resp.headers["transfer-encoding"] = ",".join(encodings)
original_response = HTTPResponse(
# In order for decoding to work, we must present the content as
@@ -262,20 +286,21 @@ class AppEngineManager(RequestMethods):
warnings.warn(
"URLFetch does not support granular timeout settings, "
"reverting to total or default URLFetch timeout.",
- AppEnginePlatformWarning)
+ AppEnginePlatformWarning,
+ )
return timeout.total
return timeout
def _get_retries(self, retries, redirect):
if not isinstance(retries, Retry):
- retries = Retry.from_int(
- retries, redirect=redirect, default=self.retries)
+ retries = Retry.from_int(retries, redirect=redirect, default=self.retries)
if retries.connect or retries.read or retries.redirect:
warnings.warn(
"URLFetch only supports total retries and does not "
"recognize connect, read, or redirect retry parameters.",
- AppEnginePlatformWarning)
+ AppEnginePlatformWarning,
+ )
return retries
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py
index 8ea127c..1fd242a 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py
@@ -20,7 +20,7 @@ class NTLMConnectionPool(HTTPSConnectionPool):
Implements an NTLM authentication version of an urllib3 connection pool
"""
- scheme = 'https'
+ scheme = "https"
def __init__(self, user, pw, authurl, *args, **kwargs):
"""
@@ -31,7 +31,7 @@ class NTLMConnectionPool(HTTPSConnectionPool):
super(NTLMConnectionPool, self).__init__(*args, **kwargs)
self.authurl = authurl
self.rawuser = user
- user_parts = user.split('\\', 1)
+ user_parts = user.split("\\", 1)
self.domain = user_parts[0].upper()
self.user = user_parts[1]
self.pw = pw
@@ -40,72 +40,82 @@ class NTLMConnectionPool(HTTPSConnectionPool):
# Performs the NTLM handshake that secures the connection. The socket
# must be kept open while requests are performed.
self.num_connections += 1
- log.debug('Starting NTLM HTTPS connection no. %d: https://%s%s',
- self.num_connections, self.host, self.authurl)
+ log.debug(
+ "Starting NTLM HTTPS connection no. %d: https://%s%s",
+ self.num_connections,
+ self.host,
+ self.authurl,
+ )
- headers = {'Connection': 'Keep-Alive'}
- req_header = 'Authorization'
- resp_header = 'www-authenticate'
+ headers = {"Connection": "Keep-Alive"}
+ req_header = "Authorization"
+ resp_header = "www-authenticate"
conn = HTTPSConnection(host=self.host, port=self.port)
# Send negotiation message
- headers[req_header] = (
- 'NTLM %s' % ntlm.create_NTLM_NEGOTIATE_MESSAGE(self.rawuser))
- log.debug('Request headers: %s', headers)
- conn.request('GET', self.authurl, None, headers)
+ headers[req_header] = "NTLM %s" % ntlm.create_NTLM_NEGOTIATE_MESSAGE(
+ self.rawuser
+ )
+ log.debug("Request headers: %s", headers)
+ conn.request("GET", self.authurl, None, headers)
res = conn.getresponse()
reshdr = dict(res.getheaders())
- log.debug('Response status: %s %s', res.status, res.reason)
- log.debug('Response headers: %s', reshdr)
- log.debug('Response data: %s [...]', res.read(100))
+ log.debug("Response status: %s %s", res.status, res.reason)
+ log.debug("Response headers: %s", reshdr)
+ log.debug("Response data: %s [...]", res.read(100))
# Remove the reference to the socket, so that it can not be closed by
# the response object (we want to keep the socket open)
res.fp = None
# Server should respond with a challenge message
- auth_header_values = reshdr[resp_header].split(', ')
+ auth_header_values = reshdr[resp_header].split(", ")
auth_header_value = None
for s in auth_header_values:
- if s[:5] == 'NTLM ':
+ if s[:5] == "NTLM ":
auth_header_value = s[5:]
if auth_header_value is None:
- raise Exception('Unexpected %s response header: %s' %
- (resp_header, reshdr[resp_header]))
+ raise Exception(
+ "Unexpected %s response header: %s" % (resp_header, reshdr[resp_header])
+ )
# Send authentication message
- ServerChallenge, NegotiateFlags = \
- ntlm.parse_NTLM_CHALLENGE_MESSAGE(auth_header_value)
- auth_msg = ntlm.create_NTLM_AUTHENTICATE_MESSAGE(ServerChallenge,
- self.user,
- self.domain,
- self.pw,
- NegotiateFlags)
- headers[req_header] = 'NTLM %s' % auth_msg
- log.debug('Request headers: %s', headers)
- conn.request('GET', self.authurl, None, headers)
+ ServerChallenge, NegotiateFlags = ntlm.parse_NTLM_CHALLENGE_MESSAGE(
+ auth_header_value
+ )
+ auth_msg = ntlm.create_NTLM_AUTHENTICATE_MESSAGE(
+ ServerChallenge, self.user, self.domain, self.pw, NegotiateFlags
+ )
+ headers[req_header] = "NTLM %s" % auth_msg
+ log.debug("Request headers: %s", headers)
+ conn.request("GET", self.authurl, None, headers)
res = conn.getresponse()
- log.debug('Response status: %s %s', res.status, res.reason)
- log.debug('Response headers: %s', dict(res.getheaders()))
- log.debug('Response data: %s [...]', res.read()[:100])
+ log.debug("Response status: %s %s", res.status, res.reason)
+ log.debug("Response headers: %s", dict(res.getheaders()))
+ log.debug("Response data: %s [...]", res.read()[:100])
if res.status != 200:
if res.status == 401:
- raise Exception('Server rejected request: wrong '
- 'username or password')
- raise Exception('Wrong server response: %s %s' %
- (res.status, res.reason))
+ raise Exception("Server rejected request: wrong username or password")
+ raise Exception("Wrong server response: %s %s" % (res.status, res.reason))
res.fp = None
- log.debug('Connection established')
+ log.debug("Connection established")
return conn
- def urlopen(self, method, url, body=None, headers=None, retries=3,
- redirect=True, assert_same_host=True):
+ def urlopen(
+ self,
+ method,
+ url,
+ body=None,
+ headers=None,
+ retries=3,
+ redirect=True,
+ assert_same_host=True,
+ ):
if headers is None:
headers = {}
- headers['Connection'] = 'Keep-Alive'
- return super(NTLMConnectionPool, self).urlopen(method, url, body,
- headers, retries,
- redirect,
- assert_same_host)
+ headers["Connection"] = "Keep-Alive"
+ return super(NTLMConnectionPool, self).urlopen(
+ method, url, body, headers, retries, redirect, assert_same_host
+ )
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py
index abfc319..d8fe062 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py
@@ -47,6 +47,7 @@ import OpenSSL.SSL
from cryptography import x509
from cryptography.hazmat.backends.openssl import backend as openssl_backend
from cryptography.hazmat.backends.openssl.x509 import _Certificate
+
try:
from cryptography.x509 import UnsupportedExtension
except ImportError:
@@ -54,6 +55,7 @@ except ImportError:
class UnsupportedExtension(Exception):
pass
+
from socket import timeout, error as SocketError
from io import BytesIO
@@ -71,7 +73,7 @@ import sys
from .. import util
-__all__ = ['inject_into_urllib3', 'extract_from_urllib3']
+__all__ = ["inject_into_urllib3", "extract_from_urllib3"]
# SNI always works.
HAS_SNI = True
@@ -82,25 +84,23 @@ _openssl_versions = {
ssl.PROTOCOL_TLSv1: OpenSSL.SSL.TLSv1_METHOD,
}
-if hasattr(ssl, 'PROTOCOL_SSLv3') and hasattr(OpenSSL.SSL, 'SSLv3_METHOD'):
+if hasattr(ssl, "PROTOCOL_SSLv3") and hasattr(OpenSSL.SSL, "SSLv3_METHOD"):
_openssl_versions[ssl.PROTOCOL_SSLv3] = OpenSSL.SSL.SSLv3_METHOD
-if hasattr(ssl, 'PROTOCOL_TLSv1_1') and hasattr(OpenSSL.SSL, 'TLSv1_1_METHOD'):
+if hasattr(ssl, "PROTOCOL_TLSv1_1") and hasattr(OpenSSL.SSL, "TLSv1_1_METHOD"):
_openssl_versions[ssl.PROTOCOL_TLSv1_1] = OpenSSL.SSL.TLSv1_1_METHOD
-if hasattr(ssl, 'PROTOCOL_TLSv1_2') and hasattr(OpenSSL.SSL, 'TLSv1_2_METHOD'):
+if hasattr(ssl, "PROTOCOL_TLSv1_2") and hasattr(OpenSSL.SSL, "TLSv1_2_METHOD"):
_openssl_versions[ssl.PROTOCOL_TLSv1_2] = OpenSSL.SSL.TLSv1_2_METHOD
_stdlib_to_openssl_verify = {
ssl.CERT_NONE: OpenSSL.SSL.VERIFY_NONE,
ssl.CERT_OPTIONAL: OpenSSL.SSL.VERIFY_PEER,
- ssl.CERT_REQUIRED:
- OpenSSL.SSL.VERIFY_PEER + OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
+ ssl.CERT_REQUIRED: OpenSSL.SSL.VERIFY_PEER
+ + OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
}
-_openssl_to_stdlib_verify = dict(
- (v, k) for k, v in _stdlib_to_openssl_verify.items()
-)
+_openssl_to_stdlib_verify = dict((v, k) for k, v in _stdlib_to_openssl_verify.items())
# OpenSSL will only write 16K at a time
SSL_WRITE_BLOCKSIZE = 16384
@@ -113,7 +113,7 @@ log = logging.getLogger(__name__)
def inject_into_urllib3():
- 'Monkey-patch urllib3 with PyOpenSSL-backed SSL-support.'
+ "Monkey-patch urllib3 with PyOpenSSL-backed SSL-support."
_validate_dependencies_met()
@@ -126,7 +126,7 @@ def inject_into_urllib3():
def extract_from_urllib3():
- 'Undo monkey-patching by :func:`inject_into_urllib3`.'
+ "Undo monkey-patching by :func:`inject_into_urllib3`."
util.SSLContext = orig_util_SSLContext
util.ssl_.SSLContext = orig_util_SSLContext
@@ -143,17 +143,23 @@ def _validate_dependencies_met():
"""
# Method added in `cryptography==1.1`; not available in older versions
from cryptography.x509.extensions import Extensions
+
if getattr(Extensions, "get_extension_for_class", None) is None:
- raise ImportError("'cryptography' module missing required functionality. "
- "Try upgrading to v1.3.4 or newer.")
+ raise ImportError(
+ "'cryptography' module missing required functionality. "
+ "Try upgrading to v1.3.4 or newer."
+ )
# pyOpenSSL 0.14 and above use cryptography for OpenSSL bindings. The _x509
# attribute is only present on those versions.
from OpenSSL.crypto import X509
+
x509 = X509()
if getattr(x509, "_x509", None) is None:
- raise ImportError("'pyOpenSSL' module missing required functionality. "
- "Try upgrading to v0.14 or newer.")
+ raise ImportError(
+ "'pyOpenSSL' module missing required functionality. "
+ "Try upgrading to v0.14 or newer."
+ )
def _dnsname_to_stdlib(name):
@@ -169,6 +175,7 @@ def _dnsname_to_stdlib(name):
If the name cannot be idna-encoded then we return None signalling that
the name given should be skipped.
"""
+
def idna_encode(name):
"""
Borrowed wholesale from the Python Cryptography Project. It turns out
@@ -178,23 +185,23 @@ def _dnsname_to_stdlib(name):
from pip._vendor import idna
try:
- for prefix in [u'*.', u'.']:
+ for prefix in [u"*.", u"."]:
if name.startswith(prefix):
- name = name[len(prefix):]
- return prefix.encode('ascii') + idna.encode(name)
+ name = name[len(prefix) :]
+ return prefix.encode("ascii") + idna.encode(name)
return idna.encode(name)
except idna.core.IDNAError:
return None
# Don't send IPv6 addresses through the IDNA encoder.
- if ':' in name:
+ if ":" in name:
return name
name = idna_encode(name)
if name is None:
return None
elif sys.version_info >= (3, 0):
- name = name.decode('utf-8')
+ name = name.decode("utf-8")
return name
@@ -213,14 +220,16 @@ def get_subj_alt_name(peer_cert):
# We want to find the SAN extension. Ask Cryptography to locate it (it's
# faster than looping in Python)
try:
- ext = cert.extensions.get_extension_for_class(
- x509.SubjectAlternativeName
- ).value
+ ext = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName).value
except x509.ExtensionNotFound:
# No such extension, return the empty list.
return []
- except (x509.DuplicateExtension, UnsupportedExtension,
- x509.UnsupportedGeneralNameType, UnicodeError) as e:
+ except (
+ x509.DuplicateExtension,
+ UnsupportedExtension,
+ x509.UnsupportedGeneralNameType,
+ UnicodeError,
+ ) as e:
# A problem has been found with the quality of the certificate. Assume
# no SAN field is present.
log.warning(
@@ -239,23 +248,23 @@ def get_subj_alt_name(peer_cert):
# does with certificates, and so we need to attempt to do the same.
# We also want to skip over names which cannot be idna encoded.
names = [
- ('DNS', name) for name in map(_dnsname_to_stdlib, ext.get_values_for_type(x509.DNSName))
+ ("DNS", name)
+ for name in map(_dnsname_to_stdlib, ext.get_values_for_type(x509.DNSName))
if name is not None
]
names.extend(
- ('IP Address', str(name))
- for name in ext.get_values_for_type(x509.IPAddress)
+ ("IP Address", str(name)) for name in ext.get_values_for_type(x509.IPAddress)
)
return names
class WrappedSocket(object):
- '''API-compatibility wrapper for Python OpenSSL's Connection-class.
+ """API-compatibility wrapper for Python OpenSSL's Connection-class.
Note: _makefile_refs, _drop() and _reuse() are needed for the garbage
collector of pypy.
- '''
+ """
def __init__(self, connection, socket, suppress_ragged_eofs=True):
self.connection = connection
@@ -278,18 +287,18 @@ class WrappedSocket(object):
try:
data = self.connection.recv(*args, **kwargs)
except OpenSSL.SSL.SysCallError as e:
- if self.suppress_ragged_eofs and e.args == (-1, 'Unexpected EOF'):
- return b''
+ if self.suppress_ragged_eofs and e.args == (-1, "Unexpected EOF"):
+ return b""
else:
raise SocketError(str(e))
except OpenSSL.SSL.ZeroReturnError:
if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN:
- return b''
+ return b""
else:
raise
except OpenSSL.SSL.WantReadError:
if not util.wait_for_read(self.socket, self.socket.gettimeout()):
- raise timeout('The read operation timed out')
+ raise timeout("The read operation timed out")
else:
return self.recv(*args, **kwargs)
@@ -303,7 +312,7 @@ class WrappedSocket(object):
try:
return self.connection.recv_into(*args, **kwargs)
except OpenSSL.SSL.SysCallError as e:
- if self.suppress_ragged_eofs and e.args == (-1, 'Unexpected EOF'):
+ if self.suppress_ragged_eofs and e.args == (-1, "Unexpected EOF"):
return 0
else:
raise SocketError(str(e))
@@ -314,7 +323,7 @@ class WrappedSocket(object):
raise
except OpenSSL.SSL.WantReadError:
if not util.wait_for_read(self.socket, self.socket.gettimeout()):
- raise timeout('The read operation timed out')
+ raise timeout("The read operation timed out")
else:
return self.recv_into(*args, **kwargs)
@@ -339,7 +348,9 @@ class WrappedSocket(object):
def sendall(self, data):
total_sent = 0
while total_sent < len(data):
- sent = self._send_until_done(data[total_sent:total_sent + SSL_WRITE_BLOCKSIZE])
+ sent = self._send_until_done(
+ data[total_sent : total_sent + SSL_WRITE_BLOCKSIZE]
+ )
total_sent += sent
def shutdown(self):
@@ -363,15 +374,11 @@ class WrappedSocket(object):
return x509
if binary_form:
- return OpenSSL.crypto.dump_certificate(
- OpenSSL.crypto.FILETYPE_ASN1,
- x509)
+ return OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_ASN1, x509)
return {
- 'subject': (
- (('commonName', x509.get_subject().CN),),
- ),
- 'subjectAltName': get_subj_alt_name(x509)
+ "subject": ((("commonName", x509.get_subject().CN),),),
+ "subjectAltName": get_subj_alt_name(x509),
}
def version(self):
@@ -388,9 +395,12 @@ class WrappedSocket(object):
if _fileobject: # Platform-specific: Python 2
+
def makefile(self, mode, bufsize=-1):
self._makefile_refs += 1
return _fileobject(self, mode, bufsize, close=True)
+
+
else: # Platform-specific: Python 3
makefile = backport_makefile
@@ -403,6 +413,7 @@ class PyOpenSSLContext(object):
for translating the interface of the standard library ``SSLContext`` object
to calls into PyOpenSSL.
"""
+
def __init__(self, protocol):
self.protocol = _openssl_versions[protocol]
self._ctx = OpenSSL.SSL.Context(self.protocol)
@@ -424,43 +435,48 @@ class PyOpenSSLContext(object):
@verify_mode.setter
def verify_mode(self, value):
- self._ctx.set_verify(
- _stdlib_to_openssl_verify[value],
- _verify_callback
- )
+ self._ctx.set_verify(_stdlib_to_openssl_verify[value], _verify_callback)
def set_default_verify_paths(self):
self._ctx.set_default_verify_paths()
def set_ciphers(self, ciphers):
if isinstance(ciphers, six.text_type):
- ciphers = ciphers.encode('utf-8')
+ ciphers = ciphers.encode("utf-8")
self._ctx.set_cipher_list(ciphers)
def load_verify_locations(self, cafile=None, capath=None, cadata=None):
if cafile is not None:
- cafile = cafile.encode('utf-8')
+ cafile = cafile.encode("utf-8")
if capath is not None:
- capath = capath.encode('utf-8')
- self._ctx.load_verify_locations(cafile, capath)
- if cadata is not None:
- self._ctx.load_verify_locations(BytesIO(cadata))
+ capath = capath.encode("utf-8")
+ try:
+ self._ctx.load_verify_locations(cafile, capath)
+ if cadata is not None:
+ self._ctx.load_verify_locations(BytesIO(cadata))
+ except OpenSSL.SSL.Error as e:
+ raise ssl.SSLError("unable to load trusted certificates: %r" % e)
def load_cert_chain(self, certfile, keyfile=None, password=None):
self._ctx.use_certificate_chain_file(certfile)
if password is not None:
if not isinstance(password, six.binary_type):
- password = password.encode('utf-8')
+ password = password.encode("utf-8")
self._ctx.set_passwd_cb(lambda *_: password)
self._ctx.use_privatekey_file(keyfile or certfile)
- def wrap_socket(self, sock, server_side=False,
- do_handshake_on_connect=True, suppress_ragged_eofs=True,
- server_hostname=None):
+ def wrap_socket(
+ self,
+ sock,
+ server_side=False,
+ do_handshake_on_connect=True,
+ suppress_ragged_eofs=True,
+ server_hostname=None,
+ ):
cnx = OpenSSL.SSL.Connection(self._ctx, sock)
if isinstance(server_hostname, six.text_type): # Platform-specific: Python 3
- server_hostname = server_hostname.encode('utf-8')
+ server_hostname = server_hostname.encode("utf-8")
if server_hostname is not None:
cnx.set_tlsext_host_name(server_hostname)
@@ -472,10 +488,10 @@ class PyOpenSSLContext(object):
cnx.do_handshake()
except OpenSSL.SSL.WantReadError:
if not util.wait_for_read(sock, sock.gettimeout()):
- raise timeout('select timed out')
+ raise timeout("select timed out")
continue
except OpenSSL.SSL.Error as e:
- raise ssl.SSLError('bad handshake: %r' % e)
+ raise ssl.SSLError("bad handshake: %r" % e)
break
return WrappedSocket(cnx, sock)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/securetransport.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/securetransport.py
index 4dc4848..a6b7e94 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/securetransport.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/securetransport.py
@@ -62,12 +62,12 @@ import threading
import weakref
from .. import util
-from ._securetransport.bindings import (
- Security, SecurityConst, CoreFoundation
-)
+from ._securetransport.bindings import Security, SecurityConst, CoreFoundation
from ._securetransport.low_level import (
- _assert_no_error, _cert_array_from_pem, _temporary_keychain,
- _load_client_cert_chain
+ _assert_no_error,
+ _cert_array_from_pem,
+ _temporary_keychain,
+ _load_client_cert_chain,
)
try: # Platform-specific: Python 2
@@ -76,7 +76,7 @@ except ImportError: # Platform-specific: Python 3
_fileobject = None
from ..packages.backports.makefile import backport_makefile
-__all__ = ['inject_into_urllib3', 'extract_from_urllib3']
+__all__ = ["inject_into_urllib3", "extract_from_urllib3"]
# SNI always works
HAS_SNI = True
@@ -144,31 +144,36 @@ CIPHER_SUITES = [
]
# Basically this is simple: for PROTOCOL_SSLv23 we turn it into a low of
-# TLSv1 and a high of TLSv1.3. For everything else, we pin to that version.
-# TLSv1 to 1.2 are supported on macOS 10.8+ and TLSv1.3 is macOS 10.13+
+# TLSv1 and a high of TLSv1.2. For everything else, we pin to that version.
+# TLSv1 to 1.2 are supported on macOS 10.8+
_protocol_to_min_max = {
- util.PROTOCOL_TLS: (SecurityConst.kTLSProtocol1, SecurityConst.kTLSProtocolMaxSupported),
+ util.PROTOCOL_TLS: (SecurityConst.kTLSProtocol1, SecurityConst.kTLSProtocol12)
}
if hasattr(ssl, "PROTOCOL_SSLv2"):
_protocol_to_min_max[ssl.PROTOCOL_SSLv2] = (
- SecurityConst.kSSLProtocol2, SecurityConst.kSSLProtocol2
+ SecurityConst.kSSLProtocol2,
+ SecurityConst.kSSLProtocol2,
)
if hasattr(ssl, "PROTOCOL_SSLv3"):
_protocol_to_min_max[ssl.PROTOCOL_SSLv3] = (
- SecurityConst.kSSLProtocol3, SecurityConst.kSSLProtocol3
+ SecurityConst.kSSLProtocol3,
+ SecurityConst.kSSLProtocol3,
)
if hasattr(ssl, "PROTOCOL_TLSv1"):
_protocol_to_min_max[ssl.PROTOCOL_TLSv1] = (
- SecurityConst.kTLSProtocol1, SecurityConst.kTLSProtocol1
+ SecurityConst.kTLSProtocol1,
+ SecurityConst.kTLSProtocol1,
)
if hasattr(ssl, "PROTOCOL_TLSv1_1"):
_protocol_to_min_max[ssl.PROTOCOL_TLSv1_1] = (
- SecurityConst.kTLSProtocol11, SecurityConst.kTLSProtocol11
+ SecurityConst.kTLSProtocol11,
+ SecurityConst.kTLSProtocol11,
)
if hasattr(ssl, "PROTOCOL_TLSv1_2"):
_protocol_to_min_max[ssl.PROTOCOL_TLSv1_2] = (
- SecurityConst.kTLSProtocol12, SecurityConst.kTLSProtocol12
+ SecurityConst.kTLSProtocol12,
+ SecurityConst.kTLSProtocol12,
)
@@ -218,7 +223,7 @@ def _read_callback(connection_id, data_buffer, data_length_pointer):
while read_count < requested_length:
if timeout is None or timeout >= 0:
if not util.wait_for_read(base_socket, timeout):
- raise socket.error(errno.EAGAIN, 'timed out')
+ raise socket.error(errno.EAGAIN, "timed out")
remaining = requested_length - read_count
buffer = (ctypes.c_char * remaining).from_address(
@@ -274,7 +279,7 @@ def _write_callback(connection_id, data_buffer, data_length_pointer):
while sent < bytes_to_write:
if timeout is None or timeout >= 0:
if not util.wait_for_write(base_socket, timeout):
- raise socket.error(errno.EAGAIN, 'timed out')
+ raise socket.error(errno.EAGAIN, "timed out")
chunk_sent = base_socket.send(data)
sent += chunk_sent
@@ -316,6 +321,7 @@ class WrappedSocket(object):
Note: _makefile_refs, _drop(), and _reuse() are needed for the garbage
collector of PyPy.
"""
+
def __init__(self, socket):
self.socket = socket
self.context = None
@@ -380,7 +386,7 @@ class WrappedSocket(object):
# We want data in memory, so load it up.
if os.path.isfile(trust_bundle):
- with open(trust_bundle, 'rb') as f:
+ with open(trust_bundle, "rb") as f:
trust_bundle = f.read()
cert_array = None
@@ -394,9 +400,7 @@ class WrappedSocket(object):
# created for this connection, shove our CAs into it, tell ST to
# ignore everything else it knows, and then ask if it can build a
# chain. This is a buuuunch of code.
- result = Security.SSLCopyPeerTrust(
- self.context, ctypes.byref(trust)
- )
+ result = Security.SSLCopyPeerTrust(self.context, ctypes.byref(trust))
_assert_no_error(result)
if not trust:
raise ssl.SSLError("Failed to copy trust reference")
@@ -408,9 +412,7 @@ class WrappedSocket(object):
_assert_no_error(result)
trust_result = Security.SecTrustResultType()
- result = Security.SecTrustEvaluate(
- trust, ctypes.byref(trust_result)
- )
+ result = Security.SecTrustEvaluate(trust, ctypes.byref(trust_result))
_assert_no_error(result)
finally:
if trust:
@@ -422,23 +424,24 @@ class WrappedSocket(object):
# Ok, now we can look at what the result was.
successes = (
SecurityConst.kSecTrustResultUnspecified,
- SecurityConst.kSecTrustResultProceed
+ SecurityConst.kSecTrustResultProceed,
)
if trust_result.value not in successes:
raise ssl.SSLError(
- "certificate verify failed, error code: %d" %
- trust_result.value
+ "certificate verify failed, error code: %d" % trust_result.value
)
- def handshake(self,
- server_hostname,
- verify,
- trust_bundle,
- min_version,
- max_version,
- client_cert,
- client_key,
- client_key_passphrase):
+ def handshake(
+ self,
+ server_hostname,
+ verify,
+ trust_bundle,
+ min_version,
+ max_version,
+ client_cert,
+ client_key,
+ client_key_passphrase,
+ ):
"""
Actually performs the TLS handshake. This is run automatically by
wrapped socket, and shouldn't be needed in user code.
@@ -468,7 +471,7 @@ class WrappedSocket(object):
# If we have a server hostname, we should set that too.
if server_hostname:
if not isinstance(server_hostname, bytes):
- server_hostname = server_hostname.encode('utf-8')
+ server_hostname = server_hostname.encode("utf-8")
result = Security.SSLSetPeerDomainName(
self.context, server_hostname, len(server_hostname)
@@ -482,13 +485,7 @@ class WrappedSocket(object):
result = Security.SSLSetProtocolVersionMin(self.context, min_version)
_assert_no_error(result)
- # TLS 1.3 isn't necessarily enabled by the OS
- # so we have to detect when we error out and try
- # setting TLS 1.3 if it's allowed. kTLSProtocolMaxSupported
- # was added in macOS 10.13 along with kTLSProtocol13.
result = Security.SSLSetProtocolVersionMax(self.context, max_version)
- if result != 0 and max_version == SecurityConst.kTLSProtocolMaxSupported:
- result = Security.SSLSetProtocolVersionMax(self.context, SecurityConst.kTLSProtocol12)
_assert_no_error(result)
# If there's a trust DB, we need to use it. We do that by telling
@@ -497,9 +494,7 @@ class WrappedSocket(object):
# authing in that case.
if not verify or trust_bundle is not None:
result = Security.SSLSetSessionOption(
- self.context,
- SecurityConst.kSSLSessionOptionBreakOnServerAuth,
- True
+ self.context, SecurityConst.kSSLSessionOptionBreakOnServerAuth, True
)
_assert_no_error(result)
@@ -509,9 +504,7 @@ class WrappedSocket(object):
self._client_cert_chain = _load_client_cert_chain(
self._keychain, client_cert, client_key
)
- result = Security.SSLSetCertificate(
- self.context, self._client_cert_chain
- )
+ result = Security.SSLSetCertificate(self.context, self._client_cert_chain)
_assert_no_error(result)
while True:
@@ -562,7 +555,7 @@ class WrappedSocket(object):
# There are some result codes that we want to treat as "not always
# errors". Specifically, those are errSSLWouldBlock,
# errSSLClosedGraceful, and errSSLClosedNoNotify.
- if (result == SecurityConst.errSSLWouldBlock):
+ if result == SecurityConst.errSSLWouldBlock:
# If we didn't process any bytes, then this was just a time out.
# However, we can get errSSLWouldBlock in situations when we *did*
# read some data, and in those cases we should just read "short"
@@ -570,7 +563,10 @@ class WrappedSocket(object):
if processed_bytes.value == 0:
# Timed out, no data read.
raise socket.timeout("recv timed out")
- elif result in (SecurityConst.errSSLClosedGraceful, SecurityConst.errSSLClosedNoNotify):
+ elif result in (
+ SecurityConst.errSSLClosedGraceful,
+ SecurityConst.errSSLClosedNoNotify,
+ ):
# The remote peer has closed this connection. We should do so as
# well. Note that we don't actually return here because in
# principle this could actually be fired along with return data.
@@ -609,7 +605,7 @@ class WrappedSocket(object):
def sendall(self, data):
total_sent = 0
while total_sent < len(data):
- sent = self.send(data[total_sent:total_sent + SSL_WRITE_BLOCKSIZE])
+ sent = self.send(data[total_sent : total_sent + SSL_WRITE_BLOCKSIZE])
total_sent += sent
def shutdown(self):
@@ -656,18 +652,14 @@ class WrappedSocket(object):
# instead to just flag to urllib3 that it shouldn't do its own hostname
# validation when using SecureTransport.
if not binary_form:
- raise ValueError(
- "SecureTransport only supports dumping binary certs"
- )
+ raise ValueError("SecureTransport only supports dumping binary certs")
trust = Security.SecTrustRef()
certdata = None
der_bytes = None
try:
# Grab the trust store.
- result = Security.SSLCopyPeerTrust(
- self.context, ctypes.byref(trust)
- )
+ result = Security.SSLCopyPeerTrust(self.context, ctypes.byref(trust))
_assert_no_error(result)
if not trust:
# Probably we haven't done the handshake yet. No biggie.
@@ -699,22 +691,24 @@ class WrappedSocket(object):
def version(self):
protocol = Security.SSLProtocol()
- result = Security.SSLGetNegotiatedProtocolVersion(self.context, ctypes.byref(protocol))
+ result = Security.SSLGetNegotiatedProtocolVersion(
+ self.context, ctypes.byref(protocol)
+ )
_assert_no_error(result)
if protocol.value == SecurityConst.kTLSProtocol13:
- return 'TLSv1.3'
+ raise ssl.SSLError("SecureTransport does not support TLS 1.3")
elif protocol.value == SecurityConst.kTLSProtocol12:
- return 'TLSv1.2'
+ return "TLSv1.2"
elif protocol.value == SecurityConst.kTLSProtocol11:
- return 'TLSv1.1'
+ return "TLSv1.1"
elif protocol.value == SecurityConst.kTLSProtocol1:
- return 'TLSv1'
+ return "TLSv1"
elif protocol.value == SecurityConst.kSSLProtocol3:
- return 'SSLv3'
+ return "SSLv3"
elif protocol.value == SecurityConst.kSSLProtocol2:
- return 'SSLv2'
+ return "SSLv2"
else:
- raise ssl.SSLError('Unknown TLS version: %r' % protocol)
+ raise ssl.SSLError("Unknown TLS version: %r" % protocol)
def _reuse(self):
self._makefile_refs += 1
@@ -727,16 +721,21 @@ class WrappedSocket(object):
if _fileobject: # Platform-specific: Python 2
+
def makefile(self, mode, bufsize=-1):
self._makefile_refs += 1
return _fileobject(self, mode, bufsize, close=True)
+
+
else: # Platform-specific: Python 3
+
def makefile(self, mode="r", buffering=None, *args, **kwargs):
# We disable buffering with SecureTransport because it conflicts with
# the buffering that ST does internally (see issue #1153 for more).
buffering = 0
return backport_makefile(self, mode, buffering, *args, **kwargs)
+
WrappedSocket.makefile = makefile
@@ -746,6 +745,7 @@ class SecureTransportContext(object):
interface of the standard library ``SSLContext`` object to calls into
SecureTransport.
"""
+
def __init__(self, protocol):
self._min_version, self._max_version = _protocol_to_min_max[protocol]
self._options = 0
@@ -812,16 +812,17 @@ class SecureTransportContext(object):
def set_ciphers(self, ciphers):
# For now, we just require the default cipher string.
if ciphers != util.ssl_.DEFAULT_CIPHERS:
- raise ValueError(
- "SecureTransport doesn't support custom cipher strings"
- )
+ raise ValueError("SecureTransport doesn't support custom cipher strings")
def load_verify_locations(self, cafile=None, capath=None, cadata=None):
# OK, we only really support cadata and cafile.
if capath is not None:
- raise ValueError(
- "SecureTransport does not support cert directories"
- )
+ raise ValueError("SecureTransport does not support cert directories")
+
+ # Raise if cafile does not exist.
+ if cafile is not None:
+ with open(cafile):
+ pass
self._trust_bundle = cafile or cadata
@@ -830,9 +831,14 @@ class SecureTransportContext(object):
self._client_key = keyfile
self._client_cert_passphrase = password
- def wrap_socket(self, sock, server_side=False,
- do_handshake_on_connect=True, suppress_ragged_eofs=True,
- server_hostname=None):
+ def wrap_socket(
+ self,
+ sock,
+ server_side=False,
+ do_handshake_on_connect=True,
+ suppress_ragged_eofs=True,
+ server_hostname=None,
+ ):
# So, what do we do here? Firstly, we assert some properties. This is a
# stripped down shim, so there is some functionality we don't support.
# See PEP 543 for the real deal.
@@ -846,8 +852,13 @@ class SecureTransportContext(object):
# Now we can handshake
wrapped_socket.handshake(
- server_hostname, self._verify, self._trust_bundle,
- self._min_version, self._max_version, self._client_cert,
- self._client_key, self._client_key_passphrase
+ server_hostname,
+ self._verify,
+ self._trust_bundle,
+ self._min_version,
+ self._max_version,
+ self._client_cert,
+ self._client_key,
+ self._client_key_passphrase,
)
return wrapped_socket
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/socks.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/socks.py
index 636d261..9e97f7a 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/socks.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/contrib/socks.py
@@ -42,23 +42,20 @@ except ImportError:
import warnings
from ..exceptions import DependencyWarning
- warnings.warn((
- 'SOCKS support in urllib3 requires the installation of optional '
- 'dependencies: specifically, PySocks. For more information, see '
- 'https://urllib3.readthedocs.io/en/latest/contrib.html#socks-proxies'
+ warnings.warn(
+ (
+ "SOCKS support in urllib3 requires the installation of optional "
+ "dependencies: specifically, PySocks. For more information, see "
+ "https://urllib3.readthedocs.io/en/latest/contrib.html#socks-proxies"
),
- DependencyWarning
+ DependencyWarning,
)
raise
from socket import error as SocketError, timeout as SocketTimeout
-from ..connection import (
- HTTPConnection, HTTPSConnection
-)
-from ..connectionpool import (
- HTTPConnectionPool, HTTPSConnectionPool
-)
+from ..connection import HTTPConnection, HTTPSConnection
+from ..connectionpool import HTTPConnectionPool, HTTPSConnectionPool
from ..exceptions import ConnectTimeoutError, NewConnectionError
from ..poolmanager import PoolManager
from ..util.url import parse_url
@@ -73,8 +70,9 @@ class SOCKSConnection(HTTPConnection):
"""
A plain-text HTTP connection that connects via a SOCKS proxy.
"""
+
def __init__(self, *args, **kwargs):
- self._socks_options = kwargs.pop('_socks_options')
+ self._socks_options = kwargs.pop("_socks_options")
super(SOCKSConnection, self).__init__(*args, **kwargs)
def _new_conn(self):
@@ -83,28 +81,30 @@ class SOCKSConnection(HTTPConnection):
"""
extra_kw = {}
if self.source_address:
- extra_kw['source_address'] = self.source_address
+ extra_kw["source_address"] = self.source_address
if self.socket_options:
- extra_kw['socket_options'] = self.socket_options
+ extra_kw["socket_options"] = self.socket_options
try:
conn = socks.create_connection(
(self.host, self.port),
- proxy_type=self._socks_options['socks_version'],
- proxy_addr=self._socks_options['proxy_host'],
- proxy_port=self._socks_options['proxy_port'],
- proxy_username=self._socks_options['username'],
- proxy_password=self._socks_options['password'],
- proxy_rdns=self._socks_options['rdns'],
+ proxy_type=self._socks_options["socks_version"],
+ proxy_addr=self._socks_options["proxy_host"],
+ proxy_port=self._socks_options["proxy_port"],
+ proxy_username=self._socks_options["username"],
+ proxy_password=self._socks_options["password"],
+ proxy_rdns=self._socks_options["rdns"],
timeout=self.timeout,
**extra_kw
)
except SocketTimeout:
raise ConnectTimeoutError(
- self, "Connection to %s timed out. (connect timeout=%s)" %
- (self.host, self.timeout))
+ self,
+ "Connection to %s timed out. (connect timeout=%s)"
+ % (self.host, self.timeout),
+ )
except socks.ProxyError as e:
# This is fragile as hell, but it seems to be the only way to raise
@@ -114,23 +114,22 @@ class SOCKSConnection(HTTPConnection):
if isinstance(error, SocketTimeout):
raise ConnectTimeoutError(
self,
- "Connection to %s timed out. (connect timeout=%s)" %
- (self.host, self.timeout)
+ "Connection to %s timed out. (connect timeout=%s)"
+ % (self.host, self.timeout),
)
else:
raise NewConnectionError(
- self,
- "Failed to establish a new connection: %s" % error
+ self, "Failed to establish a new connection: %s" % error
)
else:
raise NewConnectionError(
- self,
- "Failed to establish a new connection: %s" % e
+ self, "Failed to establish a new connection: %s" % e
)
except SocketError as e: # Defensive: PySocks should catch all these.
raise NewConnectionError(
- self, "Failed to establish a new connection: %s" % e)
+ self, "Failed to establish a new connection: %s" % e
+ )
return conn
@@ -156,47 +155,53 @@ class SOCKSProxyManager(PoolManager):
A version of the urllib3 ProxyManager that routes connections via the
defined SOCKS proxy.
"""
+
pool_classes_by_scheme = {
- 'http': SOCKSHTTPConnectionPool,
- 'https': SOCKSHTTPSConnectionPool,
+ "http": SOCKSHTTPConnectionPool,
+ "https": SOCKSHTTPSConnectionPool,
}
- def __init__(self, proxy_url, username=None, password=None,
- num_pools=10, headers=None, **connection_pool_kw):
+ def __init__(
+ self,
+ proxy_url,
+ username=None,
+ password=None,
+ num_pools=10,
+ headers=None,
+ **connection_pool_kw
+ ):
parsed = parse_url(proxy_url)
if username is None and password is None and parsed.auth is not None:
- split = parsed.auth.split(':')
+ split = parsed.auth.split(":")
if len(split) == 2:
username, password = split
- if parsed.scheme == 'socks5':
+ if parsed.scheme == "socks5":
socks_version = socks.PROXY_TYPE_SOCKS5
rdns = False
- elif parsed.scheme == 'socks5h':
+ elif parsed.scheme == "socks5h":
socks_version = socks.PROXY_TYPE_SOCKS5
rdns = True
- elif parsed.scheme == 'socks4':
+ elif parsed.scheme == "socks4":
socks_version = socks.PROXY_TYPE_SOCKS4
rdns = False
- elif parsed.scheme == 'socks4a':
+ elif parsed.scheme == "socks4a":
socks_version = socks.PROXY_TYPE_SOCKS4
rdns = True
else:
- raise ValueError(
- "Unable to determine SOCKS version from %s" % proxy_url
- )
+ raise ValueError("Unable to determine SOCKS version from %s" % proxy_url)
self.proxy_url = proxy_url
socks_options = {
- 'socks_version': socks_version,
- 'proxy_host': parsed.host,
- 'proxy_port': parsed.port,
- 'username': username,
- 'password': password,
- 'rdns': rdns
+ "socks_version": socks_version,
+ "proxy_host": parsed.host,
+ "proxy_port": parsed.port,
+ "username": username,
+ "password": password,
+ "rdns": rdns,
}
- connection_pool_kw['_socks_options'] = socks_options
+ connection_pool_kw["_socks_options"] = socks_options
super(SOCKSProxyManager, self).__init__(
num_pools, headers, **connection_pool_kw
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/exceptions.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/exceptions.py
index 7bbaa98..5cc4d8a 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/exceptions.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/exceptions.py
@@ -1,7 +1,6 @@
from __future__ import absolute_import
-from .packages.six.moves.http_client import (
- IncompleteRead as httplib_IncompleteRead
-)
+from .packages.six.moves.http_client import IncompleteRead as httplib_IncompleteRead
+
# Base Exceptions
@@ -17,6 +16,7 @@ class HTTPWarning(Warning):
class PoolError(HTTPError):
"Base exception for errors caused within a pool."
+
def __init__(self, pool, message):
self.pool = pool
HTTPError.__init__(self, "%s: %s" % (pool, message))
@@ -28,6 +28,7 @@ class PoolError(HTTPError):
class RequestError(PoolError):
"Base exception for PoolErrors that have associated URLs."
+
def __init__(self, pool, url, message):
self.url = url
PoolError.__init__(self, pool, message)
@@ -44,7 +45,10 @@ class SSLError(HTTPError):
class ProxyError(HTTPError):
"Raised when the connection to a proxy fails."
- pass
+
+ def __init__(self, message, error, *args):
+ super(ProxyError, self).__init__(message, error, *args)
+ self.original_error = error
class DecodeError(HTTPError):
@@ -63,6 +67,7 @@ ConnectionError = ProtocolError
# Leaf Exceptions
+
class MaxRetryError(RequestError):
"""Raised when the maximum number of retries is exceeded.
@@ -76,8 +81,7 @@ class MaxRetryError(RequestError):
def __init__(self, pool, url, reason=None):
self.reason = reason
- message = "Max retries exceeded with url: %s (Caused by %r)" % (
- url, reason)
+ message = "Max retries exceeded with url: %s (Caused by %r)" % (url, reason)
RequestError.__init__(self, pool, url, message)
@@ -93,6 +97,7 @@ class HostChangedError(RequestError):
class TimeoutStateError(HTTPError):
""" Raised when passing an invalid state to a timeout """
+
pass
@@ -102,6 +107,7 @@ class TimeoutError(HTTPError):
Catching this error will catch both :exc:`ReadTimeoutErrors
` and :exc:`ConnectTimeoutErrors `.
"""
+
pass
@@ -149,8 +155,8 @@ class LocationParseError(LocationValueError):
class ResponseError(HTTPError):
"Used as a container for an error reason supplied in a MaxRetryError."
- GENERIC_ERROR = 'too many error responses'
- SPECIFIC_ERROR = 'too many {status_code} error responses'
+ GENERIC_ERROR = "too many error responses"
+ SPECIFIC_ERROR = "too many {status_code} error responses"
class SecurityWarning(HTTPWarning):
@@ -188,6 +194,21 @@ class DependencyWarning(HTTPWarning):
Warned when an attempt is made to import a module with missing optional
dependencies.
"""
+
+ pass
+
+
+class InvalidProxyConfigurationWarning(HTTPWarning):
+ """
+ Warned when using an HTTPS proxy and an HTTPS URL. Currently
+ urllib3 doesn't support HTTPS proxies and the proxy will be
+ contacted via HTTP instead. This warning can be fixed by
+ changing your HTTPS proxy URL into an HTTP proxy URL.
+
+ If you encounter this warning read this:
+ https://github.com/urllib3/urllib3/issues/1850
+ """
+
pass
@@ -201,6 +222,7 @@ class BodyNotHttplibCompatible(HTTPError):
Body should be httplib.HTTPResponse like (have an fp attribute which
returns raw chunks) for read_chunked().
"""
+
pass
@@ -212,12 +234,15 @@ class IncompleteRead(HTTPError, httplib_IncompleteRead):
for `partial` to avoid creating large objects on streamed
reads.
"""
+
def __init__(self, partial, expected):
super(IncompleteRead, self).__init__(partial, expected)
def __repr__(self):
- return ('IncompleteRead(%i bytes read, '
- '%i more expected)' % (self.partial, self.expected))
+ return "IncompleteRead(%i bytes read, %i more expected)" % (
+ self.partial,
+ self.expected,
+ )
class InvalidHeader(HTTPError):
@@ -236,8 +261,9 @@ class ProxySchemeUnknown(AssertionError, ValueError):
class HeaderParsingError(HTTPError):
"Raised by assert_header_parsing, but we convert it to a log.warning statement."
+
def __init__(self, defects, unparsed_data):
- message = '%s, unparsed data: %r' % (defects or 'Unknown', unparsed_data)
+ message = "%s, unparsed data: %r" % (defects or "Unknown", unparsed_data)
super(HeaderParsingError, self).__init__(message)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/fields.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/fields.py
index 6a9a5a7..8715b22 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/fields.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/fields.py
@@ -6,7 +6,7 @@ import re
from .packages import six
-def guess_content_type(filename, default='application/octet-stream'):
+def guess_content_type(filename, default="application/octet-stream"):
"""
Guess the "Content-Type" of a file.
@@ -41,22 +41,22 @@ def format_header_param_rfc2231(name, value):
if not any(ch in value for ch in '"\\\r\n'):
result = u'%s="%s"' % (name, value)
try:
- result.encode('ascii')
+ result.encode("ascii")
except (UnicodeEncodeError, UnicodeDecodeError):
pass
else:
return result
- if not six.PY3: # Python 2:
- value = value.encode('utf-8')
+ if six.PY2: # Python 2:
+ value = value.encode("utf-8")
# encode_rfc2231 accepts an encoded string and returns an ascii-encoded
# string in Python 2 but accepts and returns unicode strings in Python 3
- value = email.utils.encode_rfc2231(value, 'utf-8')
- value = '%s*=%s' % (name, value)
+ value = email.utils.encode_rfc2231(value, "utf-8")
+ value = "%s*=%s" % (name, value)
- if not six.PY3: # Python 2:
- value = value.decode('utf-8')
+ if six.PY2: # Python 2:
+ value = value.decode("utf-8")
return value
@@ -69,23 +69,21 @@ _HTML5_REPLACEMENTS = {
}
# All control characters from 0x00 to 0x1F *except* 0x1B.
-_HTML5_REPLACEMENTS.update({
- six.unichr(cc): u"%{:02X}".format(cc)
- for cc
- in range(0x00, 0x1F+1)
- if cc not in (0x1B,)
-})
+_HTML5_REPLACEMENTS.update(
+ {
+ six.unichr(cc): u"%{:02X}".format(cc)
+ for cc in range(0x00, 0x1F + 1)
+ if cc not in (0x1B,)
+ }
+)
def _replace_multiple(value, needles_and_replacements):
-
def replacer(match):
return needles_and_replacements[match.group(0)]
pattern = re.compile(
- r"|".join([
- re.escape(needle) for needle in needles_and_replacements.keys()
- ])
+ r"|".join([re.escape(needle) for needle in needles_and_replacements.keys()])
)
result = pattern.sub(replacer, value)
@@ -140,13 +138,15 @@ class RequestField(object):
An optional callable that is used to encode and format the headers. By
default, this is :func:`format_header_param_html5`.
"""
+
def __init__(
- self,
- name,
- data,
- filename=None,
- headers=None,
- header_formatter=format_header_param_html5):
+ self,
+ name,
+ data,
+ filename=None,
+ headers=None,
+ header_formatter=format_header_param_html5,
+ ):
self._name = name
self._filename = filename
self.data = data
@@ -156,11 +156,7 @@ class RequestField(object):
self.header_formatter = header_formatter
@classmethod
- def from_tuples(
- cls,
- fieldname,
- value,
- header_formatter=format_header_param_html5):
+ def from_tuples(cls, fieldname, value, header_formatter=format_header_param_html5):
"""
A :class:`~urllib3.fields.RequestField` factory from old-style tuple parameters.
@@ -189,7 +185,8 @@ class RequestField(object):
data = value
request_param = cls(
- fieldname, data, filename=filename, header_formatter=header_formatter)
+ fieldname, data, filename=filename, header_formatter=header_formatter
+ )
request_param.make_multipart(content_type=content_type)
return request_param
@@ -227,7 +224,7 @@ class RequestField(object):
if value is not None:
parts.append(self._render_part(name, value))
- return u'; '.join(parts)
+ return u"; ".join(parts)
def render_headers(self):
"""
@@ -235,21 +232,22 @@ class RequestField(object):
"""
lines = []
- sort_keys = ['Content-Disposition', 'Content-Type', 'Content-Location']
+ sort_keys = ["Content-Disposition", "Content-Type", "Content-Location"]
for sort_key in sort_keys:
if self.headers.get(sort_key, False):
- lines.append(u'%s: %s' % (sort_key, self.headers[sort_key]))
+ lines.append(u"%s: %s" % (sort_key, self.headers[sort_key]))
for header_name, header_value in self.headers.items():
if header_name not in sort_keys:
if header_value:
- lines.append(u'%s: %s' % (header_name, header_value))
+ lines.append(u"%s: %s" % (header_name, header_value))
- lines.append(u'\r\n')
- return u'\r\n'.join(lines)
+ lines.append(u"\r\n")
+ return u"\r\n".join(lines)
- def make_multipart(self, content_disposition=None, content_type=None,
- content_location=None):
+ def make_multipart(
+ self, content_disposition=None, content_type=None, content_location=None
+ ):
"""
Makes this request field into a multipart request field.
@@ -262,11 +260,14 @@ class RequestField(object):
The 'Content-Location' of the request body.
"""
- self.headers['Content-Disposition'] = content_disposition or u'form-data'
- self.headers['Content-Disposition'] += u'; '.join([
- u'', self._render_parts(
- ((u'name', self._name), (u'filename', self._filename))
- )
- ])
- self.headers['Content-Type'] = content_type
- self.headers['Content-Location'] = content_location
+ self.headers["Content-Disposition"] = content_disposition or u"form-data"
+ self.headers["Content-Disposition"] += u"; ".join(
+ [
+ u"",
+ self._render_parts(
+ ((u"name", self._name), (u"filename", self._filename))
+ ),
+ ]
+ )
+ self.headers["Content-Type"] = content_type
+ self.headers["Content-Location"] = content_location
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/filepost.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/filepost.py
index 78f1e19..b7b0099 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/filepost.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/filepost.py
@@ -9,7 +9,7 @@ from .packages import six
from .packages.six import b
from .fields import RequestField
-writer = codecs.lookup('utf-8')[3]
+writer = codecs.lookup("utf-8")[3]
def choose_boundary():
@@ -17,8 +17,8 @@ def choose_boundary():
Our embarrassingly-simple replacement for mimetools.choose_boundary.
"""
boundary = binascii.hexlify(os.urandom(16))
- if six.PY3:
- boundary = boundary.decode('ascii')
+ if not six.PY2:
+ boundary = boundary.decode("ascii")
return boundary
@@ -76,7 +76,7 @@ def encode_multipart_formdata(fields, boundary=None):
boundary = choose_boundary()
for field in iter_field_objects(fields):
- body.write(b('--%s\r\n' % (boundary)))
+ body.write(b("--%s\r\n" % (boundary)))
writer(body).write(field.render_headers())
data = field.data
@@ -89,10 +89,10 @@ def encode_multipart_formdata(fields, boundary=None):
else:
body.write(data)
- body.write(b'\r\n')
+ body.write(b"\r\n")
- body.write(b('--%s--\r\n' % (boundary)))
+ body.write(b("--%s--\r\n" % (boundary)))
- content_type = str('multipart/form-data; boundary=%s' % boundary)
+ content_type = str("multipart/form-data; boundary=%s" % boundary)
return body.getvalue(), content_type
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/__init__.py
index 170e974..fce4caa 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/__init__.py
@@ -2,4 +2,4 @@ from __future__ import absolute_import
from . import ssl_match_hostname
-__all__ = ('ssl_match_hostname', )
+__all__ = ("ssl_match_hostname",)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-38.pyc
index 67a4aa1..2742d60 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-38.pyc
index fb74ae0..33242ec 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-38.pyc
index 04cbd7a..4965668 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-38.pyc
index b724c9a..4e45dca 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py
index 740db37..a3156a6 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py
@@ -11,15 +11,14 @@ import io
from socket import SocketIO
-def backport_makefile(self, mode="r", buffering=None, encoding=None,
- errors=None, newline=None):
+def backport_makefile(
+ self, mode="r", buffering=None, encoding=None, errors=None, newline=None
+):
"""
Backport of ``socket.makefile`` from Python 3.5.
"""
if not set(mode) <= {"r", "w", "b"}:
- raise ValueError(
- "invalid mode %r (only r, w, b allowed)" % (mode,)
- )
+ raise ValueError("invalid mode %r (only r, w, b allowed)" % (mode,))
writing = "w" in mode
reading = "r" in mode or not writing
assert reading or writing
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__init__.py
deleted file mode 100644
index 371c6dd..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__init__.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2014 Rackspace
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""
-An implementation of semantics and validations described in RFC 3986.
-
-See http://rfc3986.readthedocs.io/ for detailed documentation.
-
-:copyright: (c) 2014 Rackspace
-:license: Apache v2.0, see LICENSE for details
-"""
-
-from .api import iri_reference
-from .api import IRIReference
-from .api import is_valid_uri
-from .api import normalize_uri
-from .api import uri_reference
-from .api import URIReference
-from .api import urlparse
-from .parseresult import ParseResult
-
-__title__ = 'rfc3986'
-__author__ = 'Ian Stapleton Cordasco'
-__author_email__ = 'graffatcolmingov@gmail.com'
-__license__ = 'Apache v2.0'
-__copyright__ = 'Copyright 2014 Rackspace'
-__version__ = '1.3.2'
-
-__all__ = (
- 'ParseResult',
- 'URIReference',
- 'IRIReference',
- 'is_valid_uri',
- 'normalize_uri',
- 'uri_reference',
- 'iri_reference',
- 'urlparse',
- '__title__',
- '__author__',
- '__author_email__',
- '__license__',
- '__copyright__',
- '__version__',
-)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/__init__.cpython-38.pyc
deleted file mode 100644
index 2357f49..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/__init__.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/_mixin.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/_mixin.cpython-38.pyc
deleted file mode 100644
index 0ef2cda..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/_mixin.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/abnf_regexp.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/abnf_regexp.cpython-38.pyc
deleted file mode 100644
index 63392ef..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/abnf_regexp.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/api.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/api.cpython-38.pyc
deleted file mode 100644
index 599bfc5..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/api.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/builder.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/builder.cpython-38.pyc
deleted file mode 100644
index 30929b6..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/builder.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/compat.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/compat.cpython-38.pyc
deleted file mode 100644
index c6e32c1..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/compat.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/exceptions.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/exceptions.cpython-38.pyc
deleted file mode 100644
index 8c74dda..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/exceptions.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/iri.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/iri.cpython-38.pyc
deleted file mode 100644
index bcd6587..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/iri.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/misc.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/misc.cpython-38.pyc
deleted file mode 100644
index aa06563..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/misc.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/normalizers.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/normalizers.cpython-38.pyc
deleted file mode 100644
index efac6db..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/normalizers.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/parseresult.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/parseresult.cpython-38.pyc
deleted file mode 100644
index 47da673..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/parseresult.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/uri.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/uri.cpython-38.pyc
deleted file mode 100644
index 8e2f623..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/uri.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/validators.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/validators.cpython-38.pyc
deleted file mode 100644
index 2e14f57..0000000
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/__pycache__/validators.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/_mixin.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/_mixin.py
deleted file mode 100644
index 543925c..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/_mixin.py
+++ /dev/null
@@ -1,353 +0,0 @@
-"""Module containing the implementation of the URIMixin class."""
-import warnings
-
-from . import exceptions as exc
-from . import misc
-from . import normalizers
-from . import validators
-
-
-class URIMixin(object):
- """Mixin with all shared methods for URIs and IRIs."""
-
- __hash__ = tuple.__hash__
-
- def authority_info(self):
- """Return a dictionary with the ``userinfo``, ``host``, and ``port``.
-
- If the authority is not valid, it will raise a
- :class:`~rfc3986.exceptions.InvalidAuthority` Exception.
-
- :returns:
- ``{'userinfo': 'username:password', 'host': 'www.example.com',
- 'port': '80'}``
- :rtype: dict
- :raises rfc3986.exceptions.InvalidAuthority:
- If the authority is not ``None`` and can not be parsed.
- """
- if not self.authority:
- return {'userinfo': None, 'host': None, 'port': None}
-
- match = self._match_subauthority()
-
- if match is None:
- # In this case, we have an authority that was parsed from the URI
- # Reference, but it cannot be further parsed by our
- # misc.SUBAUTHORITY_MATCHER. In this case it must not be a valid
- # authority.
- raise exc.InvalidAuthority(self.authority.encode(self.encoding))
-
- # We had a match, now let's ensure that it is actually a valid host
- # address if it is IPv4
- matches = match.groupdict()
- host = matches.get('host')
-
- if (host and misc.IPv4_MATCHER.match(host) and not
- validators.valid_ipv4_host_address(host)):
- # If we have a host, it appears to be IPv4 and it does not have
- # valid bytes, it is an InvalidAuthority.
- raise exc.InvalidAuthority(self.authority.encode(self.encoding))
-
- return matches
-
- def _match_subauthority(self):
- return misc.SUBAUTHORITY_MATCHER.match(self.authority)
-
- @property
- def host(self):
- """If present, a string representing the host."""
- try:
- authority = self.authority_info()
- except exc.InvalidAuthority:
- return None
- return authority['host']
-
- @property
- def port(self):
- """If present, the port extracted from the authority."""
- try:
- authority = self.authority_info()
- except exc.InvalidAuthority:
- return None
- return authority['port']
-
- @property
- def userinfo(self):
- """If present, the userinfo extracted from the authority."""
- try:
- authority = self.authority_info()
- except exc.InvalidAuthority:
- return None
- return authority['userinfo']
-
- def is_absolute(self):
- """Determine if this URI Reference is an absolute URI.
-
- See http://tools.ietf.org/html/rfc3986#section-4.3 for explanation.
-
- :returns: ``True`` if it is an absolute URI, ``False`` otherwise.
- :rtype: bool
- """
- return bool(misc.ABSOLUTE_URI_MATCHER.match(self.unsplit()))
-
- def is_valid(self, **kwargs):
- """Determine if the URI is valid.
-
- .. deprecated:: 1.1.0
-
- Use the :class:`~rfc3986.validators.Validator` object instead.
-
- :param bool require_scheme: Set to ``True`` if you wish to require the
- presence of the scheme component.
- :param bool require_authority: Set to ``True`` if you wish to require
- the presence of the authority component.
- :param bool require_path: Set to ``True`` if you wish to require the
- presence of the path component.
- :param bool require_query: Set to ``True`` if you wish to require the
- presence of the query component.
- :param bool require_fragment: Set to ``True`` if you wish to require
- the presence of the fragment component.
- :returns: ``True`` if the URI is valid. ``False`` otherwise.
- :rtype: bool
- """
- warnings.warn("Please use rfc3986.validators.Validator instead. "
- "This method will be eventually removed.",
- DeprecationWarning)
- validators = [
- (self.scheme_is_valid, kwargs.get('require_scheme', False)),
- (self.authority_is_valid, kwargs.get('require_authority', False)),
- (self.path_is_valid, kwargs.get('require_path', False)),
- (self.query_is_valid, kwargs.get('require_query', False)),
- (self.fragment_is_valid, kwargs.get('require_fragment', False)),
- ]
- return all(v(r) for v, r in validators)
-
- def authority_is_valid(self, require=False):
- """Determine if the authority component is valid.
-
- .. deprecated:: 1.1.0
-
- Use the :class:`~rfc3986.validators.Validator` object instead.
-
- :param bool require:
- Set to ``True`` to require the presence of this component.
- :returns:
- ``True`` if the authority is valid. ``False`` otherwise.
- :rtype:
- bool
- """
- warnings.warn("Please use rfc3986.validators.Validator instead. "
- "This method will be eventually removed.",
- DeprecationWarning)
- try:
- self.authority_info()
- except exc.InvalidAuthority:
- return False
-
- return validators.authority_is_valid(
- self.authority,
- host=self.host,
- require=require,
- )
-
- def scheme_is_valid(self, require=False):
- """Determine if the scheme component is valid.
-
- .. deprecated:: 1.1.0
-
- Use the :class:`~rfc3986.validators.Validator` object instead.
-
- :param str require: Set to ``True`` to require the presence of this
- component.
- :returns: ``True`` if the scheme is valid. ``False`` otherwise.
- :rtype: bool
- """
- warnings.warn("Please use rfc3986.validators.Validator instead. "
- "This method will be eventually removed.",
- DeprecationWarning)
- return validators.scheme_is_valid(self.scheme, require)
-
- def path_is_valid(self, require=False):
- """Determine if the path component is valid.
-
- .. deprecated:: 1.1.0
-
- Use the :class:`~rfc3986.validators.Validator` object instead.
-
- :param str require: Set to ``True`` to require the presence of this
- component.
- :returns: ``True`` if the path is valid. ``False`` otherwise.
- :rtype: bool
- """
- warnings.warn("Please use rfc3986.validators.Validator instead. "
- "This method will be eventually removed.",
- DeprecationWarning)
- return validators.path_is_valid(self.path, require)
-
- def query_is_valid(self, require=False):
- """Determine if the query component is valid.
-
- .. deprecated:: 1.1.0
-
- Use the :class:`~rfc3986.validators.Validator` object instead.
-
- :param str require: Set to ``True`` to require the presence of this
- component.
- :returns: ``True`` if the query is valid. ``False`` otherwise.
- :rtype: bool
- """
- warnings.warn("Please use rfc3986.validators.Validator instead. "
- "This method will be eventually removed.",
- DeprecationWarning)
- return validators.query_is_valid(self.query, require)
-
- def fragment_is_valid(self, require=False):
- """Determine if the fragment component is valid.
-
- .. deprecated:: 1.1.0
-
- Use the Validator object instead.
-
- :param str require: Set to ``True`` to require the presence of this
- component.
- :returns: ``True`` if the fragment is valid. ``False`` otherwise.
- :rtype: bool
- """
- warnings.warn("Please use rfc3986.validators.Validator instead. "
- "This method will be eventually removed.",
- DeprecationWarning)
- return validators.fragment_is_valid(self.fragment, require)
-
- def normalized_equality(self, other_ref):
- """Compare this URIReference to another URIReference.
-
- :param URIReference other_ref: (required), The reference with which
- we're comparing.
- :returns: ``True`` if the references are equal, ``False`` otherwise.
- :rtype: bool
- """
- return tuple(self.normalize()) == tuple(other_ref.normalize())
-
- def resolve_with(self, base_uri, strict=False):
- """Use an absolute URI Reference to resolve this relative reference.
-
- Assuming this is a relative reference that you would like to resolve,
- use the provided base URI to resolve it.
-
- See http://tools.ietf.org/html/rfc3986#section-5 for more information.
-
- :param base_uri: Either a string or URIReference. It must be an
- absolute URI or it will raise an exception.
- :returns: A new URIReference which is the result of resolving this
- reference using ``base_uri``.
- :rtype: :class:`URIReference`
- :raises rfc3986.exceptions.ResolutionError:
- If the ``base_uri`` is not an absolute URI.
- """
- if not isinstance(base_uri, URIMixin):
- base_uri = type(self).from_string(base_uri)
-
- if not base_uri.is_absolute():
- raise exc.ResolutionError(base_uri)
-
- # This is optional per
- # http://tools.ietf.org/html/rfc3986#section-5.2.1
- base_uri = base_uri.normalize()
-
- # The reference we're resolving
- resolving = self
-
- if not strict and resolving.scheme == base_uri.scheme:
- resolving = resolving.copy_with(scheme=None)
-
- # http://tools.ietf.org/html/rfc3986#page-32
- if resolving.scheme is not None:
- target = resolving.copy_with(
- path=normalizers.normalize_path(resolving.path)
- )
- else:
- if resolving.authority is not None:
- target = resolving.copy_with(
- scheme=base_uri.scheme,
- path=normalizers.normalize_path(resolving.path)
- )
- else:
- if resolving.path is None:
- if resolving.query is not None:
- query = resolving.query
- else:
- query = base_uri.query
- target = resolving.copy_with(
- scheme=base_uri.scheme,
- authority=base_uri.authority,
- path=base_uri.path,
- query=query
- )
- else:
- if resolving.path.startswith('/'):
- path = normalizers.normalize_path(resolving.path)
- else:
- path = normalizers.normalize_path(
- misc.merge_paths(base_uri, resolving.path)
- )
- target = resolving.copy_with(
- scheme=base_uri.scheme,
- authority=base_uri.authority,
- path=path,
- query=resolving.query
- )
- return target
-
- def unsplit(self):
- """Create a URI string from the components.
-
- :returns: The URI Reference reconstituted as a string.
- :rtype: str
- """
- # See http://tools.ietf.org/html/rfc3986#section-5.3
- result_list = []
- if self.scheme:
- result_list.extend([self.scheme, ':'])
- if self.authority:
- result_list.extend(['//', self.authority])
- if self.path:
- result_list.append(self.path)
- if self.query is not None:
- result_list.extend(['?', self.query])
- if self.fragment is not None:
- result_list.extend(['#', self.fragment])
- return ''.join(result_list)
-
- def copy_with(self, scheme=misc.UseExisting, authority=misc.UseExisting,
- path=misc.UseExisting, query=misc.UseExisting,
- fragment=misc.UseExisting):
- """Create a copy of this reference with the new components.
-
- :param str scheme:
- (optional) The scheme to use for the new reference.
- :param str authority:
- (optional) The authority to use for the new reference.
- :param str path:
- (optional) The path to use for the new reference.
- :param str query:
- (optional) The query to use for the new reference.
- :param str fragment:
- (optional) The fragment to use for the new reference.
- :returns:
- New URIReference with provided components.
- :rtype:
- URIReference
- """
- attributes = {
- 'scheme': scheme,
- 'authority': authority,
- 'path': path,
- 'query': query,
- 'fragment': fragment,
- }
- for key, value in list(attributes.items()):
- if value is misc.UseExisting:
- del attributes[key]
- uri = self._replace(**attributes)
- uri.encoding = self.encoding
- return uri
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/abnf_regexp.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/abnf_regexp.py
deleted file mode 100644
index 24c9c3d..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/abnf_regexp.py
+++ /dev/null
@@ -1,267 +0,0 @@
-# -*- coding: utf-8 -*-
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Module for the regular expressions crafted from ABNF."""
-
-import sys
-
-# https://tools.ietf.org/html/rfc3986#page-13
-GEN_DELIMS = GENERIC_DELIMITERS = ":/?#[]@"
-GENERIC_DELIMITERS_SET = set(GENERIC_DELIMITERS)
-# https://tools.ietf.org/html/rfc3986#page-13
-SUB_DELIMS = SUB_DELIMITERS = "!$&'()*+,;="
-SUB_DELIMITERS_SET = set(SUB_DELIMITERS)
-# Escape the '*' for use in regular expressions
-SUB_DELIMITERS_RE = r"!$&'()\*+,;="
-RESERVED_CHARS_SET = GENERIC_DELIMITERS_SET.union(SUB_DELIMITERS_SET)
-ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
-DIGIT = '0123456789'
-# https://tools.ietf.org/html/rfc3986#section-2.3
-UNRESERVED = UNRESERVED_CHARS = ALPHA + DIGIT + r'._!-'
-UNRESERVED_CHARS_SET = set(UNRESERVED_CHARS)
-NON_PCT_ENCODED_SET = RESERVED_CHARS_SET.union(UNRESERVED_CHARS_SET)
-# We need to escape the '-' in this case:
-UNRESERVED_RE = r'A-Za-z0-9._~\-'
-
-# Percent encoded character values
-PERCENT_ENCODED = PCT_ENCODED = '%[A-Fa-f0-9]{2}'
-PCHAR = '([' + UNRESERVED_RE + SUB_DELIMITERS_RE + ':@]|%s)' % PCT_ENCODED
-
-# NOTE(sigmavirus24): We're going to use more strict regular expressions
-# than appear in Appendix B for scheme. This will prevent over-eager
-# consuming of items that aren't schemes.
-SCHEME_RE = '[a-zA-Z][a-zA-Z0-9+.-]*'
-_AUTHORITY_RE = '[^/?#]*'
-_PATH_RE = '[^?#]*'
-_QUERY_RE = '[^#]*'
-_FRAGMENT_RE = '.*'
-
-# Extracted from http://tools.ietf.org/html/rfc3986#appendix-B
-COMPONENT_PATTERN_DICT = {
- 'scheme': SCHEME_RE,
- 'authority': _AUTHORITY_RE,
- 'path': _PATH_RE,
- 'query': _QUERY_RE,
- 'fragment': _FRAGMENT_RE,
-}
-
-# See http://tools.ietf.org/html/rfc3986#appendix-B
-# In this case, we name each of the important matches so we can use
-# SRE_Match#groupdict to parse the values out if we so choose. This is also
-# modified to ignore other matches that are not important to the parsing of
-# the reference so we can also simply use SRE_Match#groups.
-URL_PARSING_RE = (
- r'(?:(?P{scheme}):)?(?://(?P{authority}))?'
- r'(?P{path})(?:\?(?P{query}))?'
- r'(?:#(?P{fragment}))?'
-).format(**COMPONENT_PATTERN_DICT)
-
-
-# #########################
-# Authority Matcher Section
-# #########################
-
-# Host patterns, see: http://tools.ietf.org/html/rfc3986#section-3.2.2
-# The pattern for a regular name, e.g., www.google.com, api.github.com
-REGULAR_NAME_RE = REG_NAME = '((?:{0}|[{1}])*)'.format(
- '%[0-9A-Fa-f]{2}', SUB_DELIMITERS_RE + UNRESERVED_RE
-)
-# The pattern for an IPv4 address, e.g., 192.168.255.255, 127.0.0.1,
-IPv4_RE = r'([0-9]{1,3}\.){3}[0-9]{1,3}'
-# Hexadecimal characters used in each piece of an IPv6 address
-HEXDIG_RE = '[0-9A-Fa-f]{1,4}'
-# Least-significant 32 bits of an IPv6 address
-LS32_RE = '({hex}:{hex}|{ipv4})'.format(hex=HEXDIG_RE, ipv4=IPv4_RE)
-# Substitutions into the following patterns for IPv6 patterns defined
-# http://tools.ietf.org/html/rfc3986#page-20
-_subs = {'hex': HEXDIG_RE, 'ls32': LS32_RE}
-
-# Below: h16 = hexdig, see: https://tools.ietf.org/html/rfc5234 for details
-# about ABNF (Augmented Backus-Naur Form) use in the comments
-variations = [
- # 6( h16 ":" ) ls32
- '(%(hex)s:){6}%(ls32)s' % _subs,
- # "::" 5( h16 ":" ) ls32
- '::(%(hex)s:){5}%(ls32)s' % _subs,
- # [ h16 ] "::" 4( h16 ":" ) ls32
- '(%(hex)s)?::(%(hex)s:){4}%(ls32)s' % _subs,
- # [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
- '((%(hex)s:)?%(hex)s)?::(%(hex)s:){3}%(ls32)s' % _subs,
- # [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
- '((%(hex)s:){0,2}%(hex)s)?::(%(hex)s:){2}%(ls32)s' % _subs,
- # [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
- '((%(hex)s:){0,3}%(hex)s)?::%(hex)s:%(ls32)s' % _subs,
- # [ *4( h16 ":" ) h16 ] "::" ls32
- '((%(hex)s:){0,4}%(hex)s)?::%(ls32)s' % _subs,
- # [ *5( h16 ":" ) h16 ] "::" h16
- '((%(hex)s:){0,5}%(hex)s)?::%(hex)s' % _subs,
- # [ *6( h16 ":" ) h16 ] "::"
- '((%(hex)s:){0,6}%(hex)s)?::' % _subs,
-]
-
-IPv6_RE = '(({0})|({1})|({2})|({3})|({4})|({5})|({6})|({7})|({8}))'.format(
- *variations
-)
-
-IPv_FUTURE_RE = r'v[0-9A-Fa-f]+\.[%s]+' % (
- UNRESERVED_RE + SUB_DELIMITERS_RE + ':'
-)
-
-# RFC 6874 Zone ID ABNF
-ZONE_ID = '(?:[' + UNRESERVED_RE + ']|' + PCT_ENCODED + ')+'
-
-IPv6_ADDRZ_RFC4007_RE = IPv6_RE + '(?:(?:%25|%)' + ZONE_ID + ')?'
-IPv6_ADDRZ_RE = IPv6_RE + '(?:%25' + ZONE_ID + ')?'
-
-IP_LITERAL_RE = r'\[({0}|{1})\]'.format(
- IPv6_ADDRZ_RFC4007_RE,
- IPv_FUTURE_RE,
-)
-
-# Pattern for matching the host piece of the authority
-HOST_RE = HOST_PATTERN = '({0}|{1}|{2})'.format(
- REG_NAME,
- IPv4_RE,
- IP_LITERAL_RE,
-)
-USERINFO_RE = '^([' + UNRESERVED_RE + SUB_DELIMITERS_RE + ':]|%s)+' % (
- PCT_ENCODED
-)
-PORT_RE = '[0-9]{1,5}'
-
-# ####################
-# Path Matcher Section
-# ####################
-
-# See http://tools.ietf.org/html/rfc3986#section-3.3 for more information
-# about the path patterns defined below.
-segments = {
- 'segment': PCHAR + '*',
- # Non-zero length segment
- 'segment-nz': PCHAR + '+',
- # Non-zero length segment without ":"
- 'segment-nz-nc': PCHAR.replace(':', '') + '+'
-}
-
-# Path types taken from Section 3.3 (linked above)
-PATH_EMPTY = '^$'
-PATH_ROOTLESS = '%(segment-nz)s(/%(segment)s)*' % segments
-PATH_NOSCHEME = '%(segment-nz-nc)s(/%(segment)s)*' % segments
-PATH_ABSOLUTE = '/(%s)?' % PATH_ROOTLESS
-PATH_ABEMPTY = '(/%(segment)s)*' % segments
-PATH_RE = '^(%s|%s|%s|%s|%s)$' % (
- PATH_ABEMPTY, PATH_ABSOLUTE, PATH_NOSCHEME, PATH_ROOTLESS, PATH_EMPTY
-)
-
-FRAGMENT_RE = QUERY_RE = (
- '^([/?:@' + UNRESERVED_RE + SUB_DELIMITERS_RE + ']|%s)*$' % PCT_ENCODED
-)
-
-# ##########################
-# Relative reference matcher
-# ##########################
-
-# See http://tools.ietf.org/html/rfc3986#section-4.2 for details
-RELATIVE_PART_RE = '(//%s%s|%s|%s|%s)' % (
- COMPONENT_PATTERN_DICT['authority'],
- PATH_ABEMPTY,
- PATH_ABSOLUTE,
- PATH_NOSCHEME,
- PATH_EMPTY,
-)
-
-# See http://tools.ietf.org/html/rfc3986#section-3 for definition
-HIER_PART_RE = '(//%s%s|%s|%s|%s)' % (
- COMPONENT_PATTERN_DICT['authority'],
- PATH_ABEMPTY,
- PATH_ABSOLUTE,
- PATH_ROOTLESS,
- PATH_EMPTY,
-)
-
-# ###############
-# IRIs / RFC 3987
-# ###############
-
-# Only wide-unicode gets the high-ranges of UCSCHAR
-if sys.maxunicode > 0xFFFF: # pragma: no cover
- IPRIVATE = u'\uE000-\uF8FF\U000F0000-\U000FFFFD\U00100000-\U0010FFFD'
- UCSCHAR_RE = (
- u'\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF'
- u'\U00010000-\U0001FFFD\U00020000-\U0002FFFD'
- u'\U00030000-\U0003FFFD\U00040000-\U0004FFFD'
- u'\U00050000-\U0005FFFD\U00060000-\U0006FFFD'
- u'\U00070000-\U0007FFFD\U00080000-\U0008FFFD'
- u'\U00090000-\U0009FFFD\U000A0000-\U000AFFFD'
- u'\U000B0000-\U000BFFFD\U000C0000-\U000CFFFD'
- u'\U000D0000-\U000DFFFD\U000E1000-\U000EFFFD'
- )
-else: # pragma: no cover
- IPRIVATE = u'\uE000-\uF8FF'
- UCSCHAR_RE = (
- u'\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF'
- )
-
-IUNRESERVED_RE = u'A-Za-z0-9\\._~\\-' + UCSCHAR_RE
-IPCHAR = u'([' + IUNRESERVED_RE + SUB_DELIMITERS_RE + u':@]|%s)' % PCT_ENCODED
-
-isegments = {
- 'isegment': IPCHAR + u'*',
- # Non-zero length segment
- 'isegment-nz': IPCHAR + u'+',
- # Non-zero length segment without ":"
- 'isegment-nz-nc': IPCHAR.replace(':', '') + u'+'
-}
-
-IPATH_ROOTLESS = u'%(isegment-nz)s(/%(isegment)s)*' % isegments
-IPATH_NOSCHEME = u'%(isegment-nz-nc)s(/%(isegment)s)*' % isegments
-IPATH_ABSOLUTE = u'/(?:%s)?' % IPATH_ROOTLESS
-IPATH_ABEMPTY = u'(?:/%(isegment)s)*' % isegments
-IPATH_RE = u'^(?:%s|%s|%s|%s|%s)$' % (
- IPATH_ABEMPTY, IPATH_ABSOLUTE, IPATH_NOSCHEME, IPATH_ROOTLESS, PATH_EMPTY
-)
-
-IREGULAR_NAME_RE = IREG_NAME = u'(?:{0}|[{1}])*'.format(
- u'%[0-9A-Fa-f]{2}', SUB_DELIMITERS_RE + IUNRESERVED_RE
-)
-
-IHOST_RE = IHOST_PATTERN = u'({0}|{1}|{2})'.format(
- IREG_NAME,
- IPv4_RE,
- IP_LITERAL_RE,
-)
-
-IUSERINFO_RE = u'^(?:[' + IUNRESERVED_RE + SUB_DELIMITERS_RE + u':]|%s)+' % (
- PCT_ENCODED
-)
-
-IFRAGMENT_RE = (u'^(?:[/?:@' + IUNRESERVED_RE + SUB_DELIMITERS_RE
- + u']|%s)*$' % PCT_ENCODED)
-IQUERY_RE = (u'^(?:[/?:@' + IUNRESERVED_RE + SUB_DELIMITERS_RE
- + IPRIVATE + u']|%s)*$' % PCT_ENCODED)
-
-IRELATIVE_PART_RE = u'(//%s%s|%s|%s|%s)' % (
- COMPONENT_PATTERN_DICT['authority'],
- IPATH_ABEMPTY,
- IPATH_ABSOLUTE,
- IPATH_NOSCHEME,
- PATH_EMPTY,
-)
-
-IHIER_PART_RE = u'(//%s%s|%s|%s|%s)' % (
- COMPONENT_PATTERN_DICT['authority'],
- IPATH_ABEMPTY,
- IPATH_ABSOLUTE,
- IPATH_ROOTLESS,
- PATH_EMPTY,
-)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/api.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/api.py
deleted file mode 100644
index ddc4a1c..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/api.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2014 Rackspace
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""
-Module containing the simple and functional API for rfc3986.
-
-This module defines functions and provides access to the public attributes
-and classes of rfc3986.
-"""
-
-from .iri import IRIReference
-from .parseresult import ParseResult
-from .uri import URIReference
-
-
-def uri_reference(uri, encoding='utf-8'):
- """Parse a URI string into a URIReference.
-
- This is a convenience function. You could achieve the same end by using
- ``URIReference.from_string(uri)``.
-
- :param str uri: The URI which needs to be parsed into a reference.
- :param str encoding: The encoding of the string provided
- :returns: A parsed URI
- :rtype: :class:`URIReference`
- """
- return URIReference.from_string(uri, encoding)
-
-
-def iri_reference(iri, encoding='utf-8'):
- """Parse a IRI string into an IRIReference.
-
- This is a convenience function. You could achieve the same end by using
- ``IRIReference.from_string(iri)``.
-
- :param str iri: The IRI which needs to be parsed into a reference.
- :param str encoding: The encoding of the string provided
- :returns: A parsed IRI
- :rtype: :class:`IRIReference`
- """
- return IRIReference.from_string(iri, encoding)
-
-
-def is_valid_uri(uri, encoding='utf-8', **kwargs):
- """Determine if the URI given is valid.
-
- This is a convenience function. You could use either
- ``uri_reference(uri).is_valid()`` or
- ``URIReference.from_string(uri).is_valid()`` to achieve the same result.
-
- :param str uri: The URI to be validated.
- :param str encoding: The encoding of the string provided
- :param bool require_scheme: Set to ``True`` if you wish to require the
- presence of the scheme component.
- :param bool require_authority: Set to ``True`` if you wish to require the
- presence of the authority component.
- :param bool require_path: Set to ``True`` if you wish to require the
- presence of the path component.
- :param bool require_query: Set to ``True`` if you wish to require the
- presence of the query component.
- :param bool require_fragment: Set to ``True`` if you wish to require the
- presence of the fragment component.
- :returns: ``True`` if the URI is valid, ``False`` otherwise.
- :rtype: bool
- """
- return URIReference.from_string(uri, encoding).is_valid(**kwargs)
-
-
-def normalize_uri(uri, encoding='utf-8'):
- """Normalize the given URI.
-
- This is a convenience function. You could use either
- ``uri_reference(uri).normalize().unsplit()`` or
- ``URIReference.from_string(uri).normalize().unsplit()`` instead.
-
- :param str uri: The URI to be normalized.
- :param str encoding: The encoding of the string provided
- :returns: The normalized URI.
- :rtype: str
- """
- normalized_reference = URIReference.from_string(uri, encoding).normalize()
- return normalized_reference.unsplit()
-
-
-def urlparse(uri, encoding='utf-8'):
- """Parse a given URI and return a ParseResult.
-
- This is a partial replacement of the standard library's urlparse function.
-
- :param str uri: The URI to be parsed.
- :param str encoding: The encoding of the string provided.
- :returns: A parsed URI
- :rtype: :class:`~rfc3986.parseresult.ParseResult`
- """
- return ParseResult.from_string(uri, encoding, strict=False)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/builder.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/builder.py
deleted file mode 100644
index 7934279..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/builder.py
+++ /dev/null
@@ -1,298 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017 Ian Stapleton Cordasco
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Module containing the logic for the URIBuilder object."""
-from . import compat
-from . import normalizers
-from . import uri
-
-
-class URIBuilder(object):
- """Object to aid in building up a URI Reference from parts.
-
- .. note::
-
- This object should be instantiated by the user, but it's recommended
- that it is not provided with arguments. Instead, use the available
- method to populate the fields.
-
- """
-
- def __init__(self, scheme=None, userinfo=None, host=None, port=None,
- path=None, query=None, fragment=None):
- """Initialize our URI builder.
-
- :param str scheme:
- (optional)
- :param str userinfo:
- (optional)
- :param str host:
- (optional)
- :param int port:
- (optional)
- :param str path:
- (optional)
- :param str query:
- (optional)
- :param str fragment:
- (optional)
- """
- self.scheme = scheme
- self.userinfo = userinfo
- self.host = host
- self.port = port
- self.path = path
- self.query = query
- self.fragment = fragment
-
- def __repr__(self):
- """Provide a convenient view of our builder object."""
- formatstr = ('URIBuilder(scheme={b.scheme}, userinfo={b.userinfo}, '
- 'host={b.host}, port={b.port}, path={b.path}, '
- 'query={b.query}, fragment={b.fragment})')
- return formatstr.format(b=self)
-
- def add_scheme(self, scheme):
- """Add a scheme to our builder object.
-
- After normalizing, this will generate a new URIBuilder instance with
- the specified scheme and all other attributes the same.
-
- .. code-block:: python
-
- >>> URIBuilder().add_scheme('HTTPS')
- URIBuilder(scheme='https', userinfo=None, host=None, port=None,
- path=None, query=None, fragment=None)
-
- """
- scheme = normalizers.normalize_scheme(scheme)
- return URIBuilder(
- scheme=scheme,
- userinfo=self.userinfo,
- host=self.host,
- port=self.port,
- path=self.path,
- query=self.query,
- fragment=self.fragment,
- )
-
- def add_credentials(self, username, password):
- """Add credentials as the userinfo portion of the URI.
-
- .. code-block:: python
-
- >>> URIBuilder().add_credentials('root', 's3crete')
- URIBuilder(scheme=None, userinfo='root:s3crete', host=None,
- port=None, path=None, query=None, fragment=None)
-
- >>> URIBuilder().add_credentials('root', None)
- URIBuilder(scheme=None, userinfo='root', host=None,
- port=None, path=None, query=None, fragment=None)
- """
- if username is None:
- raise ValueError('Username cannot be None')
- userinfo = normalizers.normalize_username(username)
-
- if password is not None:
- userinfo = '{}:{}'.format(
- userinfo,
- normalizers.normalize_password(password),
- )
-
- return URIBuilder(
- scheme=self.scheme,
- userinfo=userinfo,
- host=self.host,
- port=self.port,
- path=self.path,
- query=self.query,
- fragment=self.fragment,
- )
-
- def add_host(self, host):
- """Add hostname to the URI.
-
- .. code-block:: python
-
- >>> URIBuilder().add_host('google.com')
- URIBuilder(scheme=None, userinfo=None, host='google.com',
- port=None, path=None, query=None, fragment=None)
-
- """
- return URIBuilder(
- scheme=self.scheme,
- userinfo=self.userinfo,
- host=normalizers.normalize_host(host),
- port=self.port,
- path=self.path,
- query=self.query,
- fragment=self.fragment,
- )
-
- def add_port(self, port):
- """Add port to the URI.
-
- .. code-block:: python
-
- >>> URIBuilder().add_port(80)
- URIBuilder(scheme=None, userinfo=None, host=None, port='80',
- path=None, query=None, fragment=None)
-
- >>> URIBuilder().add_port(443)
- URIBuilder(scheme=None, userinfo=None, host=None, port='443',
- path=None, query=None, fragment=None)
-
- """
- port_int = int(port)
- if port_int < 0:
- raise ValueError(
- 'ports are not allowed to be negative. You provided {}'.format(
- port_int,
- )
- )
- if port_int > 65535:
- raise ValueError(
- 'ports are not allowed to be larger than 65535. '
- 'You provided {}'.format(
- port_int,
- )
- )
-
- return URIBuilder(
- scheme=self.scheme,
- userinfo=self.userinfo,
- host=self.host,
- port='{}'.format(port_int),
- path=self.path,
- query=self.query,
- fragment=self.fragment,
- )
-
- def add_path(self, path):
- """Add a path to the URI.
-
- .. code-block:: python
-
- >>> URIBuilder().add_path('sigmavirus24/rfc3985')
- URIBuilder(scheme=None, userinfo=None, host=None, port=None,
- path='/sigmavirus24/rfc3986', query=None, fragment=None)
-
- >>> URIBuilder().add_path('/checkout.php')
- URIBuilder(scheme=None, userinfo=None, host=None, port=None,
- path='/checkout.php', query=None, fragment=None)
-
- """
- if not path.startswith('/'):
- path = '/{}'.format(path)
-
- return URIBuilder(
- scheme=self.scheme,
- userinfo=self.userinfo,
- host=self.host,
- port=self.port,
- path=normalizers.normalize_path(path),
- query=self.query,
- fragment=self.fragment,
- )
-
- def add_query_from(self, query_items):
- """Generate and add a query a dictionary or list of tuples.
-
- .. code-block:: python
-
- >>> URIBuilder().add_query_from({'a': 'b c'})
- URIBuilder(scheme=None, userinfo=None, host=None, port=None,
- path=None, query='a=b+c', fragment=None)
-
- >>> URIBuilder().add_query_from([('a', 'b c')])
- URIBuilder(scheme=None, userinfo=None, host=None, port=None,
- path=None, query='a=b+c', fragment=None)
-
- """
- query = normalizers.normalize_query(compat.urlencode(query_items))
-
- return URIBuilder(
- scheme=self.scheme,
- userinfo=self.userinfo,
- host=self.host,
- port=self.port,
- path=self.path,
- query=query,
- fragment=self.fragment,
- )
-
- def add_query(self, query):
- """Add a pre-formated query string to the URI.
-
- .. code-block:: python
-
- >>> URIBuilder().add_query('a=b&c=d')
- URIBuilder(scheme=None, userinfo=None, host=None, port=None,
- path=None, query='a=b&c=d', fragment=None)
-
- """
- return URIBuilder(
- scheme=self.scheme,
- userinfo=self.userinfo,
- host=self.host,
- port=self.port,
- path=self.path,
- query=normalizers.normalize_query(query),
- fragment=self.fragment,
- )
-
- def add_fragment(self, fragment):
- """Add a fragment to the URI.
-
- .. code-block:: python
-
- >>> URIBuilder().add_fragment('section-2.6.1')
- URIBuilder(scheme=None, userinfo=None, host=None, port=None,
- path=None, query=None, fragment='section-2.6.1')
-
- """
- return URIBuilder(
- scheme=self.scheme,
- userinfo=self.userinfo,
- host=self.host,
- port=self.port,
- path=self.path,
- query=self.query,
- fragment=normalizers.normalize_fragment(fragment),
- )
-
- def finalize(self):
- """Create a URIReference from our builder.
-
- .. code-block:: python
-
- >>> URIBuilder().add_scheme('https').add_host('github.com'
- ... ).add_path('sigmavirus24/rfc3986').finalize().unsplit()
- 'https://github.com/sigmavirus24/rfc3986'
-
- >>> URIBuilder().add_scheme('https').add_host('github.com'
- ... ).add_path('sigmavirus24/rfc3986').add_credentials(
- ... 'sigmavirus24', 'not-re@l').finalize().unsplit()
- 'https://sigmavirus24:not-re%40l@github.com/sigmavirus24/rfc3986'
-
- """
- return uri.URIReference(
- self.scheme,
- normalizers.normalize_authority(
- (self.userinfo, self.host, self.port)
- ),
- self.path,
- self.query,
- self.fragment,
- )
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/compat.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/compat.py
deleted file mode 100644
index 8968c38..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/compat.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2014 Rackspace
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Compatibility module for Python 2 and 3 support."""
-import sys
-
-try:
- from urllib.parse import quote as urlquote
-except ImportError: # Python 2.x
- from urllib import quote as urlquote
-
-try:
- from urllib.parse import urlencode
-except ImportError: # Python 2.x
- from urllib import urlencode
-
-__all__ = (
- 'to_bytes',
- 'to_str',
- 'urlquote',
- 'urlencode',
-)
-
-PY3 = (3, 0) <= sys.version_info < (4, 0)
-PY2 = (2, 6) <= sys.version_info < (2, 8)
-
-
-if PY3:
- unicode = str # Python 3.x
-
-
-def to_str(b, encoding='utf-8'):
- """Ensure that b is text in the specified encoding."""
- if hasattr(b, 'decode') and not isinstance(b, unicode):
- b = b.decode(encoding)
- return b
-
-
-def to_bytes(s, encoding='utf-8'):
- """Ensure that s is converted to bytes from the encoding."""
- if hasattr(s, 'encode') and not isinstance(s, bytes):
- s = s.encode(encoding)
- return s
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/exceptions.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/exceptions.py
deleted file mode 100644
index da8ca7c..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/exceptions.py
+++ /dev/null
@@ -1,118 +0,0 @@
-# -*- coding: utf-8 -*-
-"""Exceptions module for rfc3986."""
-
-from . import compat
-
-
-class RFC3986Exception(Exception):
- """Base class for all rfc3986 exception classes."""
-
- pass
-
-
-class InvalidAuthority(RFC3986Exception):
- """Exception when the authority string is invalid."""
-
- def __init__(self, authority):
- """Initialize the exception with the invalid authority."""
- super(InvalidAuthority, self).__init__(
- u"The authority ({0}) is not valid.".format(
- compat.to_str(authority)))
-
-
-class InvalidPort(RFC3986Exception):
- """Exception when the port is invalid."""
-
- def __init__(self, port):
- """Initialize the exception with the invalid port."""
- super(InvalidPort, self).__init__(
- 'The port ("{0}") is not valid.'.format(port))
-
-
-class ResolutionError(RFC3986Exception):
- """Exception to indicate a failure to resolve a URI."""
-
- def __init__(self, uri):
- """Initialize the error with the failed URI."""
- super(ResolutionError, self).__init__(
- "{0} is not an absolute URI.".format(uri.unsplit()))
-
-
-class ValidationError(RFC3986Exception):
- """Exception raised during Validation of a URI."""
-
- pass
-
-
-class MissingComponentError(ValidationError):
- """Exception raised when a required component is missing."""
-
- def __init__(self, uri, *component_names):
- """Initialize the error with the missing component name."""
- verb = 'was'
- if len(component_names) > 1:
- verb = 'were'
-
- self.uri = uri
- self.components = sorted(component_names)
- components = ', '.join(self.components)
- super(MissingComponentError, self).__init__(
- "{} {} required but missing".format(components, verb),
- uri,
- self.components,
- )
-
-
-class UnpermittedComponentError(ValidationError):
- """Exception raised when a component has an unpermitted value."""
-
- def __init__(self, component_name, component_value, allowed_values):
- """Initialize the error with the unpermitted component."""
- super(UnpermittedComponentError, self).__init__(
- "{} was required to be one of {!r} but was {!r}".format(
- component_name, list(sorted(allowed_values)), component_value,
- ),
- component_name,
- component_value,
- allowed_values,
- )
- self.component_name = component_name
- self.component_value = component_value
- self.allowed_values = allowed_values
-
-
-class PasswordForbidden(ValidationError):
- """Exception raised when a URL has a password in the userinfo section."""
-
- def __init__(self, uri):
- """Initialize the error with the URI that failed validation."""
- unsplit = getattr(uri, 'unsplit', lambda: uri)
- super(PasswordForbidden, self).__init__(
- '"{}" contained a password when validation forbade it'.format(
- unsplit()
- )
- )
- self.uri = uri
-
-
-class InvalidComponentsError(ValidationError):
- """Exception raised when one or more components are invalid."""
-
- def __init__(self, uri, *component_names):
- """Initialize the error with the invalid component name(s)."""
- verb = 'was'
- if len(component_names) > 1:
- verb = 'were'
-
- self.uri = uri
- self.components = sorted(component_names)
- components = ', '.join(self.components)
- super(InvalidComponentsError, self).__init__(
- "{} {} found to be invalid".format(components, verb),
- uri,
- self.components,
- )
-
-
-class MissingDependencyError(RFC3986Exception):
- """Exception raised when an IRI is encoded without the 'idna' module."""
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/iri.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/iri.py
deleted file mode 100644
index 416cae4..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/iri.py
+++ /dev/null
@@ -1,147 +0,0 @@
-"""Module containing the implementation of the IRIReference class."""
-# -*- coding: utf-8 -*-
-# Copyright (c) 2014 Rackspace
-# Copyright (c) 2015 Ian Stapleton Cordasco
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-from collections import namedtuple
-
-from . import compat
-from . import exceptions
-from . import misc
-from . import normalizers
-from . import uri
-
-
-try:
- from pip._vendor import idna
-except ImportError: # pragma: no cover
- idna = None
-
-
-class IRIReference(namedtuple('IRIReference', misc.URI_COMPONENTS),
- uri.URIMixin):
- """Immutable object representing a parsed IRI Reference.
-
- Can be encoded into an URIReference object via the procedure
- specified in RFC 3987 Section 3.1
-
- .. note::
- The IRI submodule is a new interface and may possibly change in
- the future. Check for changes to the interface when upgrading.
- """
-
- slots = ()
-
- def __new__(cls, scheme, authority, path, query, fragment,
- encoding='utf-8'):
- """Create a new IRIReference."""
- ref = super(IRIReference, cls).__new__(
- cls,
- scheme or None,
- authority or None,
- path or None,
- query,
- fragment)
- ref.encoding = encoding
- return ref
-
- def __eq__(self, other):
- """Compare this reference to another."""
- other_ref = other
- if isinstance(other, tuple):
- other_ref = self.__class__(*other)
- elif not isinstance(other, IRIReference):
- try:
- other_ref = self.__class__.from_string(other)
- except TypeError:
- raise TypeError(
- 'Unable to compare {0}() to {1}()'.format(
- type(self).__name__, type(other).__name__))
-
- # See http://tools.ietf.org/html/rfc3986#section-6.2
- return tuple(self) == tuple(other_ref)
-
- def _match_subauthority(self):
- return misc.ISUBAUTHORITY_MATCHER.match(self.authority)
-
- @classmethod
- def from_string(cls, iri_string, encoding='utf-8'):
- """Parse a IRI reference from the given unicode IRI string.
-
- :param str iri_string: Unicode IRI to be parsed into a reference.
- :param str encoding: The encoding of the string provided
- :returns: :class:`IRIReference` or subclass thereof
- """
- iri_string = compat.to_str(iri_string, encoding)
-
- split_iri = misc.IRI_MATCHER.match(iri_string).groupdict()
- return cls(
- split_iri['scheme'], split_iri['authority'],
- normalizers.encode_component(split_iri['path'], encoding),
- normalizers.encode_component(split_iri['query'], encoding),
- normalizers.encode_component(split_iri['fragment'], encoding),
- encoding,
- )
-
- def encode(self, idna_encoder=None): # noqa: C901
- """Encode an IRIReference into a URIReference instance.
-
- If the ``idna`` module is installed or the ``rfc3986[idna]``
- extra is used then unicode characters in the IRI host
- component will be encoded with IDNA2008.
-
- :param idna_encoder:
- Function that encodes each part of the host component
- If not given will raise an exception if the IRI
- contains a host component.
- :rtype: uri.URIReference
- :returns: A URI reference
- """
- authority = self.authority
- if authority:
- if idna_encoder is None:
- if idna is None: # pragma: no cover
- raise exceptions.MissingDependencyError(
- "Could not import the 'idna' module "
- "and the IRI hostname requires encoding"
- )
-
- def idna_encoder(name):
- if any(ord(c) > 128 for c in name):
- try:
- return idna.encode(name.lower(),
- strict=True,
- std3_rules=True)
- except idna.IDNAError:
- raise exceptions.InvalidAuthority(self.authority)
- return name
-
- authority = ""
- if self.host:
- authority = ".".join([compat.to_str(idna_encoder(part))
- for part in self.host.split(".")])
-
- if self.userinfo is not None:
- authority = (normalizers.encode_component(
- self.userinfo, self.encoding) + '@' + authority)
-
- if self.port is not None:
- authority += ":" + str(self.port)
-
- return uri.URIReference(self.scheme,
- authority,
- path=self.path,
- query=self.query,
- fragment=self.fragment,
- encoding=self.encoding)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/misc.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/misc.py
deleted file mode 100644
index b735e04..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/misc.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2014 Rackspace
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""
-Module containing compiled regular expressions and constants.
-
-This module contains important constants, patterns, and compiled regular
-expressions for parsing and validating URIs and their components.
-"""
-
-import re
-
-from . import abnf_regexp
-
-# These are enumerated for the named tuple used as a superclass of
-# URIReference
-URI_COMPONENTS = ['scheme', 'authority', 'path', 'query', 'fragment']
-
-important_characters = {
- 'generic_delimiters': abnf_regexp.GENERIC_DELIMITERS,
- 'sub_delimiters': abnf_regexp.SUB_DELIMITERS,
- # We need to escape the '*' in this case
- 're_sub_delimiters': abnf_regexp.SUB_DELIMITERS_RE,
- 'unreserved_chars': abnf_regexp.UNRESERVED_CHARS,
- # We need to escape the '-' in this case:
- 're_unreserved': abnf_regexp.UNRESERVED_RE,
-}
-
-# For details about delimiters and reserved characters, see:
-# http://tools.ietf.org/html/rfc3986#section-2.2
-GENERIC_DELIMITERS = abnf_regexp.GENERIC_DELIMITERS_SET
-SUB_DELIMITERS = abnf_regexp.SUB_DELIMITERS_SET
-RESERVED_CHARS = abnf_regexp.RESERVED_CHARS_SET
-# For details about unreserved characters, see:
-# http://tools.ietf.org/html/rfc3986#section-2.3
-UNRESERVED_CHARS = abnf_regexp.UNRESERVED_CHARS_SET
-NON_PCT_ENCODED = abnf_regexp.NON_PCT_ENCODED_SET
-
-URI_MATCHER = re.compile(abnf_regexp.URL_PARSING_RE)
-
-SUBAUTHORITY_MATCHER = re.compile((
- '^(?:(?P{0})@)?' # userinfo
- '(?P{1})' # host
- ':?(?P{2})?$' # port
- ).format(abnf_regexp.USERINFO_RE,
- abnf_regexp.HOST_PATTERN,
- abnf_regexp.PORT_RE))
-
-
-HOST_MATCHER = re.compile('^' + abnf_regexp.HOST_RE + '$')
-IPv4_MATCHER = re.compile('^' + abnf_regexp.IPv4_RE + '$')
-IPv6_MATCHER = re.compile(r'^\[' + abnf_regexp.IPv6_ADDRZ_RFC4007_RE + r'\]$')
-
-# Used by host validator
-IPv6_NO_RFC4007_MATCHER = re.compile(r'^\[%s\]$' % (
- abnf_regexp.IPv6_ADDRZ_RE
-))
-
-# Matcher used to validate path components
-PATH_MATCHER = re.compile(abnf_regexp.PATH_RE)
-
-
-# ##################################
-# Query and Fragment Matcher Section
-# ##################################
-
-QUERY_MATCHER = re.compile(abnf_regexp.QUERY_RE)
-
-FRAGMENT_MATCHER = QUERY_MATCHER
-
-# Scheme validation, see: http://tools.ietf.org/html/rfc3986#section-3.1
-SCHEME_MATCHER = re.compile('^{0}$'.format(abnf_regexp.SCHEME_RE))
-
-RELATIVE_REF_MATCHER = re.compile(r'^%s(\?%s)?(#%s)?$' % (
- abnf_regexp.RELATIVE_PART_RE,
- abnf_regexp.QUERY_RE,
- abnf_regexp.FRAGMENT_RE,
-))
-
-# See http://tools.ietf.org/html/rfc3986#section-4.3
-ABSOLUTE_URI_MATCHER = re.compile(r'^%s:%s(\?%s)?$' % (
- abnf_regexp.COMPONENT_PATTERN_DICT['scheme'],
- abnf_regexp.HIER_PART_RE,
- abnf_regexp.QUERY_RE[1:-1],
-))
-
-# ###############
-# IRIs / RFC 3987
-# ###############
-
-IRI_MATCHER = re.compile(abnf_regexp.URL_PARSING_RE, re.UNICODE)
-
-ISUBAUTHORITY_MATCHER = re.compile((
- u'^(?:(?P{0})@)?' # iuserinfo
- u'(?P{1})' # ihost
- u':?(?P{2})?$' # port
- ).format(abnf_regexp.IUSERINFO_RE,
- abnf_regexp.IHOST_RE,
- abnf_regexp.PORT_RE), re.UNICODE)
-
-
-# Path merger as defined in http://tools.ietf.org/html/rfc3986#section-5.2.3
-def merge_paths(base_uri, relative_path):
- """Merge a base URI's path with a relative URI's path."""
- if base_uri.path is None and base_uri.authority is not None:
- return '/' + relative_path
- else:
- path = base_uri.path or ''
- index = path.rfind('/')
- return path[:index] + '/' + relative_path
-
-
-UseExisting = object()
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/normalizers.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/normalizers.py
deleted file mode 100644
index 2eb1bb3..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/normalizers.py
+++ /dev/null
@@ -1,167 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2014 Rackspace
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Module with functions to normalize components."""
-import re
-
-from . import compat
-from . import misc
-
-
-def normalize_scheme(scheme):
- """Normalize the scheme component."""
- return scheme.lower()
-
-
-def normalize_authority(authority):
- """Normalize an authority tuple to a string."""
- userinfo, host, port = authority
- result = ''
- if userinfo:
- result += normalize_percent_characters(userinfo) + '@'
- if host:
- result += normalize_host(host)
- if port:
- result += ':' + port
- return result
-
-
-def normalize_username(username):
- """Normalize a username to make it safe to include in userinfo."""
- return compat.urlquote(username)
-
-
-def normalize_password(password):
- """Normalize a password to make safe for userinfo."""
- return compat.urlquote(password)
-
-
-def normalize_host(host):
- """Normalize a host string."""
- if misc.IPv6_MATCHER.match(host):
- percent = host.find('%')
- if percent != -1:
- percent_25 = host.find('%25')
-
- # Replace RFC 4007 IPv6 Zone ID delimiter '%' with '%25'
- # from RFC 6874. If the host is '[%25]' then we
- # assume RFC 4007 and normalize to '[%2525]'
- if percent_25 == -1 or percent < percent_25 or \
- (percent == percent_25 and percent_25 == len(host) - 4):
- host = host.replace('%', '%25', 1)
-
- # Don't normalize the casing of the Zone ID
- return host[:percent].lower() + host[percent:]
-
- return host.lower()
-
-
-def normalize_path(path):
- """Normalize the path string."""
- if not path:
- return path
-
- path = normalize_percent_characters(path)
- return remove_dot_segments(path)
-
-
-def normalize_query(query):
- """Normalize the query string."""
- if not query:
- return query
- return normalize_percent_characters(query)
-
-
-def normalize_fragment(fragment):
- """Normalize the fragment string."""
- if not fragment:
- return fragment
- return normalize_percent_characters(fragment)
-
-
-PERCENT_MATCHER = re.compile('%[A-Fa-f0-9]{2}')
-
-
-def normalize_percent_characters(s):
- """All percent characters should be upper-cased.
-
- For example, ``"%3afoo%DF%ab"`` should be turned into ``"%3Afoo%DF%AB"``.
- """
- matches = set(PERCENT_MATCHER.findall(s))
- for m in matches:
- if not m.isupper():
- s = s.replace(m, m.upper())
- return s
-
-
-def remove_dot_segments(s):
- """Remove dot segments from the string.
-
- See also Section 5.2.4 of :rfc:`3986`.
- """
- # See http://tools.ietf.org/html/rfc3986#section-5.2.4 for pseudo-code
- segments = s.split('/') # Turn the path into a list of segments
- output = [] # Initialize the variable to use to store output
-
- for segment in segments:
- # '.' is the current directory, so ignore it, it is superfluous
- if segment == '.':
- continue
- # Anything other than '..', should be appended to the output
- elif segment != '..':
- output.append(segment)
- # In this case segment == '..', if we can, we should pop the last
- # element
- elif output:
- output.pop()
-
- # If the path starts with '/' and the output is empty or the first string
- # is non-empty
- if s.startswith('/') and (not output or output[0]):
- output.insert(0, '')
-
- # If the path starts with '/.' or '/..' ensure we add one more empty
- # string to add a trailing '/'
- if s.endswith(('/.', '/..')):
- output.append('')
-
- return '/'.join(output)
-
-
-def encode_component(uri_component, encoding):
- """Encode the specific component in the provided encoding."""
- if uri_component is None:
- return uri_component
-
- # Try to see if the component we're encoding is already percent-encoded
- # so we can skip all '%' characters but still encode all others.
- percent_encodings = len(PERCENT_MATCHER.findall(
- compat.to_str(uri_component, encoding)))
-
- uri_bytes = compat.to_bytes(uri_component, encoding)
- is_percent_encoded = percent_encodings == uri_bytes.count(b'%')
-
- encoded_uri = bytearray()
-
- for i in range(0, len(uri_bytes)):
- # Will return a single character bytestring on both Python 2 & 3
- byte = uri_bytes[i:i+1]
- byte_ord = ord(byte)
- if ((is_percent_encoded and byte == b'%')
- or (byte_ord < 128 and byte.decode() in misc.NON_PCT_ENCODED)):
- encoded_uri.extend(byte)
- continue
- encoded_uri.extend('%{0:02x}'.format(byte_ord).encode().upper())
-
- return encoded_uri.decode(encoding)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/parseresult.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/parseresult.py
deleted file mode 100644
index 0a73456..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/parseresult.py
+++ /dev/null
@@ -1,385 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2015 Ian Stapleton Cordasco
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Module containing the urlparse compatibility logic."""
-from collections import namedtuple
-
-from . import compat
-from . import exceptions
-from . import misc
-from . import normalizers
-from . import uri
-
-__all__ = ('ParseResult', 'ParseResultBytes')
-
-PARSED_COMPONENTS = ('scheme', 'userinfo', 'host', 'port', 'path', 'query',
- 'fragment')
-
-
-class ParseResultMixin(object):
- def _generate_authority(self, attributes):
- # I swear I did not align the comparisons below. That's just how they
- # happened to align based on pep8 and attribute lengths.
- userinfo, host, port = (attributes[p]
- for p in ('userinfo', 'host', 'port'))
- if (self.userinfo != userinfo or
- self.host != host or
- self.port != port):
- if port:
- port = '{0}'.format(port)
- return normalizers.normalize_authority(
- (compat.to_str(userinfo, self.encoding),
- compat.to_str(host, self.encoding),
- port)
- )
- return self.authority
-
- def geturl(self):
- """Shim to match the standard library method."""
- return self.unsplit()
-
- @property
- def hostname(self):
- """Shim to match the standard library."""
- return self.host
-
- @property
- def netloc(self):
- """Shim to match the standard library."""
- return self.authority
-
- @property
- def params(self):
- """Shim to match the standard library."""
- return self.query
-
-
-class ParseResult(namedtuple('ParseResult', PARSED_COMPONENTS),
- ParseResultMixin):
- """Implementation of urlparse compatibility class.
-
- This uses the URIReference logic to handle compatibility with the
- urlparse.ParseResult class.
- """
-
- slots = ()
-
- def __new__(cls, scheme, userinfo, host, port, path, query, fragment,
- uri_ref, encoding='utf-8'):
- """Create a new ParseResult."""
- parse_result = super(ParseResult, cls).__new__(
- cls,
- scheme or None,
- userinfo or None,
- host,
- port or None,
- path or None,
- query,
- fragment)
- parse_result.encoding = encoding
- parse_result.reference = uri_ref
- return parse_result
-
- @classmethod
- def from_parts(cls, scheme=None, userinfo=None, host=None, port=None,
- path=None, query=None, fragment=None, encoding='utf-8'):
- """Create a ParseResult instance from its parts."""
- authority = ''
- if userinfo is not None:
- authority += userinfo + '@'
- if host is not None:
- authority += host
- if port is not None:
- authority += ':{0}'.format(port)
- uri_ref = uri.URIReference(scheme=scheme,
- authority=authority,
- path=path,
- query=query,
- fragment=fragment,
- encoding=encoding).normalize()
- userinfo, host, port = authority_from(uri_ref, strict=True)
- return cls(scheme=uri_ref.scheme,
- userinfo=userinfo,
- host=host,
- port=port,
- path=uri_ref.path,
- query=uri_ref.query,
- fragment=uri_ref.fragment,
- uri_ref=uri_ref,
- encoding=encoding)
-
- @classmethod
- def from_string(cls, uri_string, encoding='utf-8', strict=True,
- lazy_normalize=True):
- """Parse a URI from the given unicode URI string.
-
- :param str uri_string: Unicode URI to be parsed into a reference.
- :param str encoding: The encoding of the string provided
- :param bool strict: Parse strictly according to :rfc:`3986` if True.
- If False, parse similarly to the standard library's urlparse
- function.
- :returns: :class:`ParseResult` or subclass thereof
- """
- reference = uri.URIReference.from_string(uri_string, encoding)
- if not lazy_normalize:
- reference = reference.normalize()
- userinfo, host, port = authority_from(reference, strict)
-
- return cls(scheme=reference.scheme,
- userinfo=userinfo,
- host=host,
- port=port,
- path=reference.path,
- query=reference.query,
- fragment=reference.fragment,
- uri_ref=reference,
- encoding=encoding)
-
- @property
- def authority(self):
- """Return the normalized authority."""
- return self.reference.authority
-
- def copy_with(self, scheme=misc.UseExisting, userinfo=misc.UseExisting,
- host=misc.UseExisting, port=misc.UseExisting,
- path=misc.UseExisting, query=misc.UseExisting,
- fragment=misc.UseExisting):
- """Create a copy of this instance replacing with specified parts."""
- attributes = zip(PARSED_COMPONENTS,
- (scheme, userinfo, host, port, path, query, fragment))
- attrs_dict = {}
- for name, value in attributes:
- if value is misc.UseExisting:
- value = getattr(self, name)
- attrs_dict[name] = value
- authority = self._generate_authority(attrs_dict)
- ref = self.reference.copy_with(scheme=attrs_dict['scheme'],
- authority=authority,
- path=attrs_dict['path'],
- query=attrs_dict['query'],
- fragment=attrs_dict['fragment'])
- return ParseResult(uri_ref=ref, encoding=self.encoding, **attrs_dict)
-
- def encode(self, encoding=None):
- """Convert to an instance of ParseResultBytes."""
- encoding = encoding or self.encoding
- attrs = dict(
- zip(PARSED_COMPONENTS,
- (attr.encode(encoding) if hasattr(attr, 'encode') else attr
- for attr in self)))
- return ParseResultBytes(
- uri_ref=self.reference,
- encoding=encoding,
- **attrs
- )
-
- def unsplit(self, use_idna=False):
- """Create a URI string from the components.
-
- :returns: The parsed URI reconstituted as a string.
- :rtype: str
- """
- parse_result = self
- if use_idna and self.host:
- hostbytes = self.host.encode('idna')
- host = hostbytes.decode(self.encoding)
- parse_result = self.copy_with(host=host)
- return parse_result.reference.unsplit()
-
-
-class ParseResultBytes(namedtuple('ParseResultBytes', PARSED_COMPONENTS),
- ParseResultMixin):
- """Compatibility shim for the urlparse.ParseResultBytes object."""
-
- def __new__(cls, scheme, userinfo, host, port, path, query, fragment,
- uri_ref, encoding='utf-8', lazy_normalize=True):
- """Create a new ParseResultBytes instance."""
- parse_result = super(ParseResultBytes, cls).__new__(
- cls,
- scheme or None,
- userinfo or None,
- host,
- port or None,
- path or None,
- query or None,
- fragment or None)
- parse_result.encoding = encoding
- parse_result.reference = uri_ref
- parse_result.lazy_normalize = lazy_normalize
- return parse_result
-
- @classmethod
- def from_parts(cls, scheme=None, userinfo=None, host=None, port=None,
- path=None, query=None, fragment=None, encoding='utf-8',
- lazy_normalize=True):
- """Create a ParseResult instance from its parts."""
- authority = ''
- if userinfo is not None:
- authority += userinfo + '@'
- if host is not None:
- authority += host
- if port is not None:
- authority += ':{0}'.format(int(port))
- uri_ref = uri.URIReference(scheme=scheme,
- authority=authority,
- path=path,
- query=query,
- fragment=fragment,
- encoding=encoding)
- if not lazy_normalize:
- uri_ref = uri_ref.normalize()
- to_bytes = compat.to_bytes
- userinfo, host, port = authority_from(uri_ref, strict=True)
- return cls(scheme=to_bytes(scheme, encoding),
- userinfo=to_bytes(userinfo, encoding),
- host=to_bytes(host, encoding),
- port=port,
- path=to_bytes(path, encoding),
- query=to_bytes(query, encoding),
- fragment=to_bytes(fragment, encoding),
- uri_ref=uri_ref,
- encoding=encoding,
- lazy_normalize=lazy_normalize)
-
- @classmethod
- def from_string(cls, uri_string, encoding='utf-8', strict=True,
- lazy_normalize=True):
- """Parse a URI from the given unicode URI string.
-
- :param str uri_string: Unicode URI to be parsed into a reference.
- :param str encoding: The encoding of the string provided
- :param bool strict: Parse strictly according to :rfc:`3986` if True.
- If False, parse similarly to the standard library's urlparse
- function.
- :returns: :class:`ParseResultBytes` or subclass thereof
- """
- reference = uri.URIReference.from_string(uri_string, encoding)
- if not lazy_normalize:
- reference = reference.normalize()
- userinfo, host, port = authority_from(reference, strict)
-
- to_bytes = compat.to_bytes
- return cls(scheme=to_bytes(reference.scheme, encoding),
- userinfo=to_bytes(userinfo, encoding),
- host=to_bytes(host, encoding),
- port=port,
- path=to_bytes(reference.path, encoding),
- query=to_bytes(reference.query, encoding),
- fragment=to_bytes(reference.fragment, encoding),
- uri_ref=reference,
- encoding=encoding,
- lazy_normalize=lazy_normalize)
-
- @property
- def authority(self):
- """Return the normalized authority."""
- return self.reference.authority.encode(self.encoding)
-
- def copy_with(self, scheme=misc.UseExisting, userinfo=misc.UseExisting,
- host=misc.UseExisting, port=misc.UseExisting,
- path=misc.UseExisting, query=misc.UseExisting,
- fragment=misc.UseExisting, lazy_normalize=True):
- """Create a copy of this instance replacing with specified parts."""
- attributes = zip(PARSED_COMPONENTS,
- (scheme, userinfo, host, port, path, query, fragment))
- attrs_dict = {}
- for name, value in attributes:
- if value is misc.UseExisting:
- value = getattr(self, name)
- if not isinstance(value, bytes) and hasattr(value, 'encode'):
- value = value.encode(self.encoding)
- attrs_dict[name] = value
- authority = self._generate_authority(attrs_dict)
- to_str = compat.to_str
- ref = self.reference.copy_with(
- scheme=to_str(attrs_dict['scheme'], self.encoding),
- authority=to_str(authority, self.encoding),
- path=to_str(attrs_dict['path'], self.encoding),
- query=to_str(attrs_dict['query'], self.encoding),
- fragment=to_str(attrs_dict['fragment'], self.encoding)
- )
- if not lazy_normalize:
- ref = ref.normalize()
- return ParseResultBytes(
- uri_ref=ref,
- encoding=self.encoding,
- lazy_normalize=lazy_normalize,
- **attrs_dict
- )
-
- def unsplit(self, use_idna=False):
- """Create a URI bytes object from the components.
-
- :returns: The parsed URI reconstituted as a string.
- :rtype: bytes
- """
- parse_result = self
- if use_idna and self.host:
- # self.host is bytes, to encode to idna, we need to decode it
- # first
- host = self.host.decode(self.encoding)
- hostbytes = host.encode('idna')
- parse_result = self.copy_with(host=hostbytes)
- if self.lazy_normalize:
- parse_result = parse_result.copy_with(lazy_normalize=False)
- uri = parse_result.reference.unsplit()
- return uri.encode(self.encoding)
-
-
-def split_authority(authority):
- # Initialize our expected return values
- userinfo = host = port = None
- # Initialize an extra var we may need to use
- extra_host = None
- # Set-up rest in case there is no userinfo portion
- rest = authority
-
- if '@' in authority:
- userinfo, rest = authority.rsplit('@', 1)
-
- # Handle IPv6 host addresses
- if rest.startswith('['):
- host, rest = rest.split(']', 1)
- host += ']'
-
- if ':' in rest:
- extra_host, port = rest.split(':', 1)
- elif not host and rest:
- host = rest
-
- if extra_host and not host:
- host = extra_host
-
- return userinfo, host, port
-
-
-def authority_from(reference, strict):
- try:
- subauthority = reference.authority_info()
- except exceptions.InvalidAuthority:
- if strict:
- raise
- userinfo, host, port = split_authority(reference.authority)
- else:
- # Thanks to Richard Barrell for this idea:
- # https://twitter.com/0x2ba22e11/status/617338811975139328
- userinfo, host, port = (subauthority.get(p)
- for p in ('userinfo', 'host', 'port'))
-
- if port:
- try:
- port = int(port)
- except ValueError:
- raise exceptions.InvalidPort(port)
- return userinfo, host, port
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/uri.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/uri.py
deleted file mode 100644
index d1d7150..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/uri.py
+++ /dev/null
@@ -1,153 +0,0 @@
-"""Module containing the implementation of the URIReference class."""
-# -*- coding: utf-8 -*-
-# Copyright (c) 2014 Rackspace
-# Copyright (c) 2015 Ian Stapleton Cordasco
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-from collections import namedtuple
-
-from . import compat
-from . import misc
-from . import normalizers
-from ._mixin import URIMixin
-
-
-class URIReference(namedtuple('URIReference', misc.URI_COMPONENTS), URIMixin):
- """Immutable object representing a parsed URI Reference.
-
- .. note::
-
- This class is not intended to be directly instantiated by the user.
-
- This object exposes attributes for the following components of a
- URI:
-
- - scheme
- - authority
- - path
- - query
- - fragment
-
- .. attribute:: scheme
-
- The scheme that was parsed for the URI Reference. For example,
- ``http``, ``https``, ``smtp``, ``imap``, etc.
-
- .. attribute:: authority
-
- Component of the URI that contains the user information, host,
- and port sub-components. For example,
- ``google.com``, ``127.0.0.1:5000``, ``username@[::1]``,
- ``username:password@example.com:443``, etc.
-
- .. attribute:: path
-
- The path that was parsed for the given URI Reference. For example,
- ``/``, ``/index.php``, etc.
-
- .. attribute:: query
-
- The query component for a given URI Reference. For example, ``a=b``,
- ``a=b%20c``, ``a=b+c``, ``a=b,c=d,e=%20f``, etc.
-
- .. attribute:: fragment
-
- The fragment component of a URI. For example, ``section-3.1``.
-
- This class also provides extra attributes for easier access to information
- like the subcomponents of the authority component.
-
- .. attribute:: userinfo
-
- The user information parsed from the authority.
-
- .. attribute:: host
-
- The hostname, IPv4, or IPv6 adddres parsed from the authority.
-
- .. attribute:: port
-
- The port parsed from the authority.
- """
-
- slots = ()
-
- def __new__(cls, scheme, authority, path, query, fragment,
- encoding='utf-8'):
- """Create a new URIReference."""
- ref = super(URIReference, cls).__new__(
- cls,
- scheme or None,
- authority or None,
- path or None,
- query,
- fragment)
- ref.encoding = encoding
- return ref
-
- __hash__ = tuple.__hash__
-
- def __eq__(self, other):
- """Compare this reference to another."""
- other_ref = other
- if isinstance(other, tuple):
- other_ref = URIReference(*other)
- elif not isinstance(other, URIReference):
- try:
- other_ref = URIReference.from_string(other)
- except TypeError:
- raise TypeError(
- 'Unable to compare URIReference() to {0}()'.format(
- type(other).__name__))
-
- # See http://tools.ietf.org/html/rfc3986#section-6.2
- naive_equality = tuple(self) == tuple(other_ref)
- return naive_equality or self.normalized_equality(other_ref)
-
- def normalize(self):
- """Normalize this reference as described in Section 6.2.2.
-
- This is not an in-place normalization. Instead this creates a new
- URIReference.
-
- :returns: A new reference object with normalized components.
- :rtype: URIReference
- """
- # See http://tools.ietf.org/html/rfc3986#section-6.2.2 for logic in
- # this method.
- return URIReference(normalizers.normalize_scheme(self.scheme or ''),
- normalizers.normalize_authority(
- (self.userinfo, self.host, self.port)),
- normalizers.normalize_path(self.path or ''),
- normalizers.normalize_query(self.query),
- normalizers.normalize_fragment(self.fragment),
- self.encoding)
-
- @classmethod
- def from_string(cls, uri_string, encoding='utf-8'):
- """Parse a URI reference from the given unicode URI string.
-
- :param str uri_string: Unicode URI to be parsed into a reference.
- :param str encoding: The encoding of the string provided
- :returns: :class:`URIReference` or subclass thereof
- """
- uri_string = compat.to_str(uri_string, encoding)
-
- split_uri = misc.URI_MATCHER.match(uri_string).groupdict()
- return cls(
- split_uri['scheme'], split_uri['authority'],
- normalizers.encode_component(split_uri['path'], encoding),
- normalizers.encode_component(split_uri['query'], encoding),
- normalizers.encode_component(split_uri['fragment'], encoding),
- encoding,
- )
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/validators.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/validators.py
deleted file mode 100644
index 7fc9721..0000000
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/rfc3986/validators.py
+++ /dev/null
@@ -1,450 +0,0 @@
-# -*- coding: utf-8 -*-
-# Copyright (c) 2017 Ian Stapleton Cordasco
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-# implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-"""Module containing the validation logic for rfc3986."""
-from . import exceptions
-from . import misc
-from . import normalizers
-
-
-class Validator(object):
- """Object used to configure validation of all objects in rfc3986.
-
- .. versionadded:: 1.0
-
- Example usage::
-
- >>> from rfc3986 import api, validators
- >>> uri = api.uri_reference('https://github.com/')
- >>> validator = validators.Validator().require_presence_of(
- ... 'scheme', 'host', 'path',
- ... ).allow_schemes(
- ... 'http', 'https',
- ... ).allow_hosts(
- ... '127.0.0.1', 'github.com',
- ... )
- >>> validator.validate(uri)
- >>> invalid_uri = rfc3986.uri_reference('imap://mail.google.com')
- >>> validator.validate(invalid_uri)
- Traceback (most recent call last):
- ...
- rfc3986.exceptions.MissingComponentError: ('path was required but
- missing', URIReference(scheme=u'imap', authority=u'mail.google.com',
- path=None, query=None, fragment=None), ['path'])
-
- """
-
- COMPONENT_NAMES = frozenset([
- 'scheme',
- 'userinfo',
- 'host',
- 'port',
- 'path',
- 'query',
- 'fragment',
- ])
-
- def __init__(self):
- """Initialize our default validations."""
- self.allowed_schemes = set()
- self.allowed_hosts = set()
- self.allowed_ports = set()
- self.allow_password = True
- self.required_components = {
- 'scheme': False,
- 'userinfo': False,
- 'host': False,
- 'port': False,
- 'path': False,
- 'query': False,
- 'fragment': False,
- }
- self.validated_components = self.required_components.copy()
-
- def allow_schemes(self, *schemes):
- """Require the scheme to be one of the provided schemes.
-
- .. versionadded:: 1.0
-
- :param schemes:
- Schemes, without ``://`` that are allowed.
- :returns:
- The validator instance.
- :rtype:
- Validator
- """
- for scheme in schemes:
- self.allowed_schemes.add(normalizers.normalize_scheme(scheme))
- return self
-
- def allow_hosts(self, *hosts):
- """Require the host to be one of the provided hosts.
-
- .. versionadded:: 1.0
-
- :param hosts:
- Hosts that are allowed.
- :returns:
- The validator instance.
- :rtype:
- Validator
- """
- for host in hosts:
- self.allowed_hosts.add(normalizers.normalize_host(host))
- return self
-
- def allow_ports(self, *ports):
- """Require the port to be one of the provided ports.
-
- .. versionadded:: 1.0
-
- :param ports:
- Ports that are allowed.
- :returns:
- The validator instance.
- :rtype:
- Validator
- """
- for port in ports:
- port_int = int(port, base=10)
- if 0 <= port_int <= 65535:
- self.allowed_ports.add(port)
- return self
-
- def allow_use_of_password(self):
- """Allow passwords to be present in the URI.
-
- .. versionadded:: 1.0
-
- :returns:
- The validator instance.
- :rtype:
- Validator
- """
- self.allow_password = True
- return self
-
- def forbid_use_of_password(self):
- """Prevent passwords from being included in the URI.
-
- .. versionadded:: 1.0
-
- :returns:
- The validator instance.
- :rtype:
- Validator
- """
- self.allow_password = False
- return self
-
- def check_validity_of(self, *components):
- """Check the validity of the components provided.
-
- This can be specified repeatedly.
-
- .. versionadded:: 1.1
-
- :param components:
- Names of components from :attr:`Validator.COMPONENT_NAMES`.
- :returns:
- The validator instance.
- :rtype:
- Validator
- """
- components = [c.lower() for c in components]
- for component in components:
- if component not in self.COMPONENT_NAMES:
- raise ValueError(
- '"{}" is not a valid component'.format(component)
- )
- self.validated_components.update({
- component: True for component in components
- })
- return self
-
- def require_presence_of(self, *components):
- """Require the components provided.
-
- This can be specified repeatedly.
-
- .. versionadded:: 1.0
-
- :param components:
- Names of components from :attr:`Validator.COMPONENT_NAMES`.
- :returns:
- The validator instance.
- :rtype:
- Validator
- """
- components = [c.lower() for c in components]
- for component in components:
- if component not in self.COMPONENT_NAMES:
- raise ValueError(
- '"{}" is not a valid component'.format(component)
- )
- self.required_components.update({
- component: True for component in components
- })
- return self
-
- def validate(self, uri):
- """Check a URI for conditions specified on this validator.
-
- .. versionadded:: 1.0
-
- :param uri:
- Parsed URI to validate.
- :type uri:
- rfc3986.uri.URIReference
- :raises MissingComponentError:
- When a required component is missing.
- :raises UnpermittedComponentError:
- When a component is not one of those allowed.
- :raises PasswordForbidden:
- When a password is present in the userinfo component but is
- not permitted by configuration.
- :raises InvalidComponentsError:
- When a component was found to be invalid.
- """
- if not self.allow_password:
- check_password(uri)
-
- required_components = [
- component
- for component, required in self.required_components.items()
- if required
- ]
- validated_components = [
- component
- for component, required in self.validated_components.items()
- if required
- ]
- if required_components:
- ensure_required_components_exist(uri, required_components)
- if validated_components:
- ensure_components_are_valid(uri, validated_components)
-
- ensure_one_of(self.allowed_schemes, uri, 'scheme')
- ensure_one_of(self.allowed_hosts, uri, 'host')
- ensure_one_of(self.allowed_ports, uri, 'port')
-
-
-def check_password(uri):
- """Assert that there is no password present in the uri."""
- userinfo = uri.userinfo
- if not userinfo:
- return
- credentials = userinfo.split(':', 1)
- if len(credentials) <= 1:
- return
- raise exceptions.PasswordForbidden(uri)
-
-
-def ensure_one_of(allowed_values, uri, attribute):
- """Assert that the uri's attribute is one of the allowed values."""
- value = getattr(uri, attribute)
- if value is not None and allowed_values and value not in allowed_values:
- raise exceptions.UnpermittedComponentError(
- attribute, value, allowed_values,
- )
-
-
-def ensure_required_components_exist(uri, required_components):
- """Assert that all required components are present in the URI."""
- missing_components = sorted([
- component
- for component in required_components
- if getattr(uri, component) is None
- ])
- if missing_components:
- raise exceptions.MissingComponentError(uri, *missing_components)
-
-
-def is_valid(value, matcher, require):
- """Determine if a value is valid based on the provided matcher.
-
- :param str value:
- Value to validate.
- :param matcher:
- Compiled regular expression to use to validate the value.
- :param require:
- Whether or not the value is required.
- """
- if require:
- return (value is not None
- and matcher.match(value))
-
- # require is False and value is not None
- return value is None or matcher.match(value)
-
-
-def authority_is_valid(authority, host=None, require=False):
- """Determine if the authority string is valid.
-
- :param str authority:
- The authority to validate.
- :param str host:
- (optional) The host portion of the authority to validate.
- :param bool require:
- (optional) Specify if authority must not be None.
- :returns:
- ``True`` if valid, ``False`` otherwise
- :rtype:
- bool
- """
- validated = is_valid(authority, misc.SUBAUTHORITY_MATCHER, require)
- if validated and host is not None:
- return host_is_valid(host, require)
- return validated
-
-
-def host_is_valid(host, require=False):
- """Determine if the host string is valid.
-
- :param str host:
- The host to validate.
- :param bool require:
- (optional) Specify if host must not be None.
- :returns:
- ``True`` if valid, ``False`` otherwise
- :rtype:
- bool
- """
- validated = is_valid(host, misc.HOST_MATCHER, require)
- if validated and host is not None and misc.IPv4_MATCHER.match(host):
- return valid_ipv4_host_address(host)
- elif validated and host is not None and misc.IPv6_MATCHER.match(host):
- return misc.IPv6_NO_RFC4007_MATCHER.match(host) is not None
- return validated
-
-
-def scheme_is_valid(scheme, require=False):
- """Determine if the scheme is valid.
-
- :param str scheme:
- The scheme string to validate.
- :param bool require:
- (optional) Set to ``True`` to require the presence of a scheme.
- :returns:
- ``True`` if the scheme is valid. ``False`` otherwise.
- :rtype:
- bool
- """
- return is_valid(scheme, misc.SCHEME_MATCHER, require)
-
-
-def path_is_valid(path, require=False):
- """Determine if the path component is valid.
-
- :param str path:
- The path string to validate.
- :param bool require:
- (optional) Set to ``True`` to require the presence of a path.
- :returns:
- ``True`` if the path is valid. ``False`` otherwise.
- :rtype:
- bool
- """
- return is_valid(path, misc.PATH_MATCHER, require)
-
-
-def query_is_valid(query, require=False):
- """Determine if the query component is valid.
-
- :param str query:
- The query string to validate.
- :param bool require:
- (optional) Set to ``True`` to require the presence of a query.
- :returns:
- ``True`` if the query is valid. ``False`` otherwise.
- :rtype:
- bool
- """
- return is_valid(query, misc.QUERY_MATCHER, require)
-
-
-def fragment_is_valid(fragment, require=False):
- """Determine if the fragment component is valid.
-
- :param str fragment:
- The fragment string to validate.
- :param bool require:
- (optional) Set to ``True`` to require the presence of a fragment.
- :returns:
- ``True`` if the fragment is valid. ``False`` otherwise.
- :rtype:
- bool
- """
- return is_valid(fragment, misc.FRAGMENT_MATCHER, require)
-
-
-def valid_ipv4_host_address(host):
- """Determine if the given host is a valid IPv4 address."""
- # If the host exists, and it might be IPv4, check each byte in the
- # address.
- return all([0 <= int(byte, base=10) <= 255 for byte in host.split('.')])
-
-
-_COMPONENT_VALIDATORS = {
- 'scheme': scheme_is_valid,
- 'path': path_is_valid,
- 'query': query_is_valid,
- 'fragment': fragment_is_valid,
-}
-
-_SUBAUTHORITY_VALIDATORS = set(['userinfo', 'host', 'port'])
-
-
-def subauthority_component_is_valid(uri, component):
- """Determine if the userinfo, host, and port are valid."""
- try:
- subauthority_dict = uri.authority_info()
- except exceptions.InvalidAuthority:
- return False
-
- # If we can parse the authority into sub-components and we're not
- # validating the port, we can assume it's valid.
- if component == 'host':
- return host_is_valid(subauthority_dict['host'])
- elif component != 'port':
- return True
-
- try:
- port = int(subauthority_dict['port'])
- except TypeError:
- # If the port wasn't provided it'll be None and int(None) raises a
- # TypeError
- return True
-
- return (0 <= port <= 65535)
-
-
-def ensure_components_are_valid(uri, validated_components):
- """Assert that all components are valid in the URI."""
- invalid_components = set([])
- for component in validated_components:
- if component in _SUBAUTHORITY_VALIDATORS:
- if not subauthority_component_is_valid(uri, component):
- invalid_components.add(component)
- # Python's peephole optimizer means that while this continue *is*
- # actually executed, coverage.py cannot detect that. See also,
- # https://bitbucket.org/ned/coveragepy/issues/198/continue-marked-as-not-covered
- continue # nocov: Python 2.7, 3.3, 3.4
-
- validator = _COMPONENT_VALIDATORS[component]
- if not validator(getattr(uri, component)):
- invalid_components.add(component)
-
- if invalid_components:
- raise exceptions.InvalidComponentsError(uri, *invalid_components)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/six.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/six.py
index 190c023..3144240 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/six.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/six.py
@@ -1,6 +1,4 @@
-"""Utilities for writing code that runs on Python 2 and 3"""
-
-# Copyright (c) 2010-2015 Benjamin Peterson
+# Copyright (c) 2010-2019 Benjamin Peterson
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
@@ -20,6 +18,8 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
+"""Utilities for writing code that runs on Python 2 and 3"""
+
from __future__ import absolute_import
import functools
@@ -29,7 +29,7 @@ import sys
import types
__author__ = "Benjamin Peterson "
-__version__ = "1.10.0"
+__version__ = "1.12.0"
# Useful for very coarse version differentiation.
@@ -38,15 +38,15 @@ PY3 = sys.version_info[0] == 3
PY34 = sys.version_info[0:2] >= (3, 4)
if PY3:
- string_types = str,
- integer_types = int,
- class_types = type,
+ string_types = (str,)
+ integer_types = (int,)
+ class_types = (type,)
text_type = str
binary_type = bytes
MAXSIZE = sys.maxsize
else:
- string_types = basestring,
+ string_types = (basestring,)
integer_types = (int, long)
class_types = (type, types.ClassType)
text_type = unicode
@@ -58,9 +58,9 @@ else:
else:
# It's possible to have sizeof(long) != sizeof(Py_ssize_t).
class X(object):
-
def __len__(self):
return 1 << 31
+
try:
len(X())
except OverflowError:
@@ -84,7 +84,6 @@ def _import_module(name):
class _LazyDescr(object):
-
def __init__(self, name):
self.name = name
@@ -101,7 +100,6 @@ class _LazyDescr(object):
class MovedModule(_LazyDescr):
-
def __init__(self, name, old, new=None):
super(MovedModule, self).__init__(name)
if PY3:
@@ -122,7 +120,6 @@ class MovedModule(_LazyDescr):
class _LazyModule(types.ModuleType):
-
def __init__(self, name):
super(_LazyModule, self).__init__(name)
self.__doc__ = self.__class__.__doc__
@@ -137,7 +134,6 @@ class _LazyModule(types.ModuleType):
class MovedAttribute(_LazyDescr):
-
def __init__(self, name, old_mod, new_mod, old_attr=None, new_attr=None):
super(MovedAttribute, self).__init__(name)
if PY3:
@@ -221,28 +217,36 @@ class _SixMetaPathImporter(object):
Required, if is_package is implemented"""
self.__get_module(fullname) # eventually raises ImportError
return None
+
get_source = get_code # same as get_code
+
_importer = _SixMetaPathImporter(__name__)
class _MovedItems(_LazyModule):
"""Lazy loading of moved objects"""
+
__path__ = [] # mark as package
_moved_attributes = [
MovedAttribute("cStringIO", "cStringIO", "io", "StringIO"),
MovedAttribute("filter", "itertools", "builtins", "ifilter", "filter"),
- MovedAttribute("filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"),
+ MovedAttribute(
+ "filterfalse", "itertools", "itertools", "ifilterfalse", "filterfalse"
+ ),
MovedAttribute("input", "__builtin__", "builtins", "raw_input", "input"),
MovedAttribute("intern", "__builtin__", "sys"),
MovedAttribute("map", "itertools", "builtins", "imap", "map"),
MovedAttribute("getcwd", "os", "os", "getcwdu", "getcwd"),
MovedAttribute("getcwdb", "os", "os", "getcwd", "getcwdb"),
+ MovedAttribute("getoutput", "commands", "subprocess"),
MovedAttribute("range", "__builtin__", "builtins", "xrange", "range"),
- MovedAttribute("reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"),
+ MovedAttribute(
+ "reload_module", "__builtin__", "importlib" if PY34 else "imp", "reload"
+ ),
MovedAttribute("reduce", "__builtin__", "functools"),
MovedAttribute("shlex_quote", "pipes", "shlex", "quote"),
MovedAttribute("StringIO", "StringIO", "io"),
@@ -251,7 +255,9 @@ _moved_attributes = [
MovedAttribute("UserString", "UserString", "collections"),
MovedAttribute("xrange", "__builtin__", "builtins", "xrange", "range"),
MovedAttribute("zip", "itertools", "builtins", "izip", "zip"),
- MovedAttribute("zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"),
+ MovedAttribute(
+ "zip_longest", "itertools", "itertools", "izip_longest", "zip_longest"
+ ),
MovedModule("builtins", "__builtin__"),
MovedModule("configparser", "ConfigParser"),
MovedModule("copyreg", "copy_reg"),
@@ -262,10 +268,13 @@ _moved_attributes = [
MovedModule("html_entities", "htmlentitydefs", "html.entities"),
MovedModule("html_parser", "HTMLParser", "html.parser"),
MovedModule("http_client", "httplib", "http.client"),
- MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
- MovedModule("email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"),
- MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
MovedModule("email_mime_base", "email.MIMEBase", "email.mime.base"),
+ MovedModule("email_mime_image", "email.MIMEImage", "email.mime.image"),
+ MovedModule("email_mime_multipart", "email.MIMEMultipart", "email.mime.multipart"),
+ MovedModule(
+ "email_mime_nonmultipart", "email.MIMENonMultipart", "email.mime.nonmultipart"
+ ),
+ MovedModule("email_mime_text", "email.MIMEText", "email.mime.text"),
MovedModule("BaseHTTPServer", "BaseHTTPServer", "http.server"),
MovedModule("CGIHTTPServer", "CGIHTTPServer", "http.server"),
MovedModule("SimpleHTTPServer", "SimpleHTTPServer", "http.server"),
@@ -283,15 +292,12 @@ _moved_attributes = [
MovedModule("tkinter_ttk", "ttk", "tkinter.ttk"),
MovedModule("tkinter_constants", "Tkconstants", "tkinter.constants"),
MovedModule("tkinter_dnd", "Tkdnd", "tkinter.dnd"),
- MovedModule("tkinter_colorchooser", "tkColorChooser",
- "tkinter.colorchooser"),
- MovedModule("tkinter_commondialog", "tkCommonDialog",
- "tkinter.commondialog"),
+ MovedModule("tkinter_colorchooser", "tkColorChooser", "tkinter.colorchooser"),
+ MovedModule("tkinter_commondialog", "tkCommonDialog", "tkinter.commondialog"),
MovedModule("tkinter_tkfiledialog", "tkFileDialog", "tkinter.filedialog"),
MovedModule("tkinter_font", "tkFont", "tkinter.font"),
MovedModule("tkinter_messagebox", "tkMessageBox", "tkinter.messagebox"),
- MovedModule("tkinter_tksimpledialog", "tkSimpleDialog",
- "tkinter.simpledialog"),
+ MovedModule("tkinter_tksimpledialog", "tkSimpleDialog", "tkinter.simpledialog"),
MovedModule("urllib_parse", __name__ + ".moves.urllib_parse", "urllib.parse"),
MovedModule("urllib_error", __name__ + ".moves.urllib_error", "urllib.error"),
MovedModule("urllib", __name__ + ".moves.urllib", __name__ + ".moves.urllib"),
@@ -301,9 +307,7 @@ _moved_attributes = [
]
# Add windows specific modules.
if sys.platform == "win32":
- _moved_attributes += [
- MovedModule("winreg", "_winreg"),
- ]
+ _moved_attributes += [MovedModule("winreg", "_winreg")]
for attr in _moved_attributes:
setattr(_MovedItems, attr.name, attr)
@@ -337,10 +341,14 @@ _urllib_parse_moved_attributes = [
MovedAttribute("quote_plus", "urllib", "urllib.parse"),
MovedAttribute("unquote", "urllib", "urllib.parse"),
MovedAttribute("unquote_plus", "urllib", "urllib.parse"),
+ MovedAttribute(
+ "unquote_to_bytes", "urllib", "urllib.parse", "unquote", "unquote_to_bytes"
+ ),
MovedAttribute("urlencode", "urllib", "urllib.parse"),
MovedAttribute("splitquery", "urllib", "urllib.parse"),
MovedAttribute("splittag", "urllib", "urllib.parse"),
MovedAttribute("splituser", "urllib", "urllib.parse"),
+ MovedAttribute("splitvalue", "urllib", "urllib.parse"),
MovedAttribute("uses_fragment", "urlparse", "urllib.parse"),
MovedAttribute("uses_netloc", "urlparse", "urllib.parse"),
MovedAttribute("uses_params", "urlparse", "urllib.parse"),
@@ -353,8 +361,11 @@ del attr
Module_six_moves_urllib_parse._moved_attributes = _urllib_parse_moved_attributes
-_importer._add_module(Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"),
- "moves.urllib_parse", "moves.urllib.parse")
+_importer._add_module(
+ Module_six_moves_urllib_parse(__name__ + ".moves.urllib_parse"),
+ "moves.urllib_parse",
+ "moves.urllib.parse",
+)
class Module_six_moves_urllib_error(_LazyModule):
@@ -373,8 +384,11 @@ del attr
Module_six_moves_urllib_error._moved_attributes = _urllib_error_moved_attributes
-_importer._add_module(Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"),
- "moves.urllib_error", "moves.urllib.error")
+_importer._add_module(
+ Module_six_moves_urllib_error(__name__ + ".moves.urllib.error"),
+ "moves.urllib_error",
+ "moves.urllib.error",
+)
class Module_six_moves_urllib_request(_LazyModule):
@@ -416,6 +430,8 @@ _urllib_request_moved_attributes = [
MovedAttribute("URLopener", "urllib", "urllib.request"),
MovedAttribute("FancyURLopener", "urllib", "urllib.request"),
MovedAttribute("proxy_bypass", "urllib", "urllib.request"),
+ MovedAttribute("parse_http_list", "urllib2", "urllib.request"),
+ MovedAttribute("parse_keqv_list", "urllib2", "urllib.request"),
]
for attr in _urllib_request_moved_attributes:
setattr(Module_six_moves_urllib_request, attr.name, attr)
@@ -423,8 +439,11 @@ del attr
Module_six_moves_urllib_request._moved_attributes = _urllib_request_moved_attributes
-_importer._add_module(Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"),
- "moves.urllib_request", "moves.urllib.request")
+_importer._add_module(
+ Module_six_moves_urllib_request(__name__ + ".moves.urllib.request"),
+ "moves.urllib_request",
+ "moves.urllib.request",
+)
class Module_six_moves_urllib_response(_LazyModule):
@@ -444,8 +463,11 @@ del attr
Module_six_moves_urllib_response._moved_attributes = _urllib_response_moved_attributes
-_importer._add_module(Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"),
- "moves.urllib_response", "moves.urllib.response")
+_importer._add_module(
+ Module_six_moves_urllib_response(__name__ + ".moves.urllib.response"),
+ "moves.urllib_response",
+ "moves.urllib.response",
+)
class Module_six_moves_urllib_robotparser(_LazyModule):
@@ -454,21 +476,27 @@ class Module_six_moves_urllib_robotparser(_LazyModule):
_urllib_robotparser_moved_attributes = [
- MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser"),
+ MovedAttribute("RobotFileParser", "robotparser", "urllib.robotparser")
]
for attr in _urllib_robotparser_moved_attributes:
setattr(Module_six_moves_urllib_robotparser, attr.name, attr)
del attr
-Module_six_moves_urllib_robotparser._moved_attributes = _urllib_robotparser_moved_attributes
+Module_six_moves_urllib_robotparser._moved_attributes = (
+ _urllib_robotparser_moved_attributes
+)
-_importer._add_module(Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"),
- "moves.urllib_robotparser", "moves.urllib.robotparser")
+_importer._add_module(
+ Module_six_moves_urllib_robotparser(__name__ + ".moves.urllib.robotparser"),
+ "moves.urllib_robotparser",
+ "moves.urllib.robotparser",
+)
class Module_six_moves_urllib(types.ModuleType):
"""Create a six.moves.urllib namespace that resembles the Python 3 namespace"""
+
__path__ = [] # mark as package
parse = _importer._get_module("moves.urllib_parse")
error = _importer._get_module("moves.urllib_error")
@@ -477,10 +505,12 @@ class Module_six_moves_urllib(types.ModuleType):
robotparser = _importer._get_module("moves.urllib_robotparser")
def __dir__(self):
- return ['parse', 'error', 'request', 'response', 'robotparser']
+ return ["parse", "error", "request", "response", "robotparser"]
-_importer._add_module(Module_six_moves_urllib(__name__ + ".moves.urllib"),
- "moves.urllib")
+
+_importer._add_module(
+ Module_six_moves_urllib(__name__ + ".moves.urllib"), "moves.urllib"
+)
def add_move(move):
@@ -520,19 +550,24 @@ else:
try:
advance_iterator = next
except NameError:
+
def advance_iterator(it):
return it.next()
+
+
next = advance_iterator
try:
callable = callable
except NameError:
+
def callable(obj):
return any("__call__" in klass.__dict__ for klass in type(obj).__mro__)
if PY3:
+
def get_unbound_function(unbound):
return unbound
@@ -543,6 +578,7 @@ if PY3:
Iterator = object
else:
+
def get_unbound_function(unbound):
return unbound.im_func
@@ -553,13 +589,13 @@ else:
return types.MethodType(func, None, cls)
class Iterator(object):
-
def next(self):
return type(self).__next__(self)
callable = callable
-_add_doc(get_unbound_function,
- """Get the function out of a possibly unbound function""")
+_add_doc(
+ get_unbound_function, """Get the function out of a possibly unbound function"""
+)
get_method_function = operator.attrgetter(_meth_func)
@@ -571,6 +607,7 @@ get_function_globals = operator.attrgetter(_func_globals)
if PY3:
+
def iterkeys(d, **kw):
return iter(d.keys(**kw))
@@ -589,6 +626,7 @@ if PY3:
viewitems = operator.methodcaller("items")
else:
+
def iterkeys(d, **kw):
return d.iterkeys(**kw)
@@ -609,28 +647,33 @@ else:
_add_doc(iterkeys, "Return an iterator over the keys of a dictionary.")
_add_doc(itervalues, "Return an iterator over the values of a dictionary.")
-_add_doc(iteritems,
- "Return an iterator over the (key, value) pairs of a dictionary.")
-_add_doc(iterlists,
- "Return an iterator over the (key, [values]) pairs of a dictionary.")
+_add_doc(iteritems, "Return an iterator over the (key, value) pairs of a dictionary.")
+_add_doc(
+ iterlists, "Return an iterator over the (key, [values]) pairs of a dictionary."
+)
if PY3:
+
def b(s):
return s.encode("latin-1")
def u(s):
return s
+
unichr = chr
import struct
+
int2byte = struct.Struct(">B").pack
del struct
byte2int = operator.itemgetter(0)
indexbytes = operator.getitem
iterbytes = iter
import io
+
StringIO = io.StringIO
BytesIO = io.BytesIO
+ del io
_assertCountEqual = "assertCountEqual"
if sys.version_info[1] <= 1:
_assertRaisesRegex = "assertRaisesRegexp"
@@ -639,12 +682,15 @@ if PY3:
_assertRaisesRegex = "assertRaisesRegex"
_assertRegex = "assertRegex"
else:
+
def b(s):
return s
+
# Workaround for standalone backslash
def u(s):
- return unicode(s.replace(r'\\', r'\\\\'), "unicode_escape")
+ return unicode(s.replace(r"\\", r"\\\\"), "unicode_escape")
+
unichr = unichr
int2byte = chr
@@ -653,8 +699,10 @@ else:
def indexbytes(buf, i):
return ord(buf[i])
+
iterbytes = functools.partial(itertools.imap, ord)
import StringIO
+
StringIO = BytesIO = StringIO.StringIO
_assertCountEqual = "assertItemsEqual"
_assertRaisesRegex = "assertRaisesRegexp"
@@ -679,13 +727,19 @@ if PY3:
exec_ = getattr(moves.builtins, "exec")
def reraise(tp, value, tb=None):
- if value is None:
- value = tp()
- if value.__traceback__ is not tb:
- raise value.with_traceback(tb)
- raise value
+ try:
+ if value is None:
+ value = tp()
+ if value.__traceback__ is not tb:
+ raise value.with_traceback(tb)
+ raise value
+ finally:
+ value = None
+ tb = None
+
else:
+
def exec_(_code_, _globs_=None, _locs_=None):
"""Execute code in a namespace."""
if _globs_ is None:
@@ -698,28 +752,45 @@ else:
_locs_ = _globs_
exec("""exec _code_ in _globs_, _locs_""")
- exec_("""def reraise(tp, value, tb=None):
- raise tp, value, tb
-""")
+ exec_(
+ """def reraise(tp, value, tb=None):
+ try:
+ raise tp, value, tb
+ finally:
+ tb = None
+"""
+ )
if sys.version_info[:2] == (3, 2):
- exec_("""def raise_from(value, from_value):
- if from_value is None:
- raise value
- raise value from from_value
-""")
+ exec_(
+ """def raise_from(value, from_value):
+ try:
+ if from_value is None:
+ raise value
+ raise value from from_value
+ finally:
+ value = None
+"""
+ )
elif sys.version_info[:2] > (3, 2):
- exec_("""def raise_from(value, from_value):
- raise value from from_value
-""")
+ exec_(
+ """def raise_from(value, from_value):
+ try:
+ raise value from from_value
+ finally:
+ value = None
+"""
+ )
else:
+
def raise_from(value, from_value):
raise value
print_ = getattr(moves.builtins, "print", None)
if print_ is None:
+
def print_(*args, **kwargs):
"""The new-style print function for Python 2.4 and 2.5."""
fp = kwargs.pop("file", sys.stdout)
@@ -730,14 +801,17 @@ if print_ is None:
if not isinstance(data, basestring):
data = str(data)
# If the file has an encoding, encode unicode with it.
- if (isinstance(fp, file) and
- isinstance(data, unicode) and
- fp.encoding is not None):
+ if (
+ isinstance(fp, file)
+ and isinstance(data, unicode)
+ and fp.encoding is not None
+ ):
errors = getattr(fp, "errors", None)
if errors is None:
errors = "strict"
data = data.encode(fp.encoding, errors)
fp.write(data)
+
want_unicode = False
sep = kwargs.pop("sep", None)
if sep is not None:
@@ -773,6 +847,8 @@ if print_ is None:
write(sep)
write(arg)
write(end)
+
+
if sys.version_info[:2] < (3, 3):
_print = print_
@@ -783,16 +859,24 @@ if sys.version_info[:2] < (3, 3):
if flush and fp is not None:
fp.flush()
+
_add_doc(reraise, """Reraise an exception.""")
if sys.version_info[0:2] < (3, 4):
- def wraps(wrapped, assigned=functools.WRAPPER_ASSIGNMENTS,
- updated=functools.WRAPPER_UPDATES):
+
+ def wraps(
+ wrapped,
+ assigned=functools.WRAPPER_ASSIGNMENTS,
+ updated=functools.WRAPPER_UPDATES,
+ ):
def wrapper(f):
f = functools.wraps(wrapped, assigned, updated)(f)
f.__wrapped__ = wrapped
return f
+
return wrapper
+
+
else:
wraps = functools.wraps
@@ -802,29 +886,95 @@ def with_metaclass(meta, *bases):
# This requires a bit of explanation: the basic idea is to make a dummy
# metaclass for one level of class instantiation that replaces itself with
# the actual metaclass.
- class metaclass(meta):
-
+ class metaclass(type):
def __new__(cls, name, this_bases, d):
return meta(name, bases, d)
- return type.__new__(metaclass, 'temporary_class', (), {})
+
+ @classmethod
+ def __prepare__(cls, name, this_bases):
+ return meta.__prepare__(name, bases)
+
+ return type.__new__(metaclass, "temporary_class", (), {})
def add_metaclass(metaclass):
"""Class decorator for creating a class with a metaclass."""
+
def wrapper(cls):
orig_vars = cls.__dict__.copy()
- slots = orig_vars.get('__slots__')
+ slots = orig_vars.get("__slots__")
if slots is not None:
if isinstance(slots, str):
slots = [slots]
for slots_var in slots:
orig_vars.pop(slots_var)
- orig_vars.pop('__dict__', None)
- orig_vars.pop('__weakref__', None)
+ orig_vars.pop("__dict__", None)
+ orig_vars.pop("__weakref__", None)
+ if hasattr(cls, "__qualname__"):
+ orig_vars["__qualname__"] = cls.__qualname__
return metaclass(cls.__name__, cls.__bases__, orig_vars)
+
return wrapper
+def ensure_binary(s, encoding="utf-8", errors="strict"):
+ """Coerce **s** to six.binary_type.
+
+ For Python 2:
+ - `unicode` -> encoded to `str`
+ - `str` -> `str`
+
+ For Python 3:
+ - `str` -> encoded to `bytes`
+ - `bytes` -> `bytes`
+ """
+ if isinstance(s, text_type):
+ return s.encode(encoding, errors)
+ elif isinstance(s, binary_type):
+ return s
+ else:
+ raise TypeError("not expecting type '%s'" % type(s))
+
+
+def ensure_str(s, encoding="utf-8", errors="strict"):
+ """Coerce *s* to `str`.
+
+ For Python 2:
+ - `unicode` -> encoded to `str`
+ - `str` -> `str`
+
+ For Python 3:
+ - `str` -> `str`
+ - `bytes` -> decoded to `str`
+ """
+ if not isinstance(s, (text_type, binary_type)):
+ raise TypeError("not expecting type '%s'" % type(s))
+ if PY2 and isinstance(s, text_type):
+ s = s.encode(encoding, errors)
+ elif PY3 and isinstance(s, binary_type):
+ s = s.decode(encoding, errors)
+ return s
+
+
+def ensure_text(s, encoding="utf-8", errors="strict"):
+ """Coerce *s* to six.text_type.
+
+ For Python 2:
+ - `unicode` -> `unicode`
+ - `str` -> `unicode`
+
+ For Python 3:
+ - `str` -> `str`
+ - `bytes` -> decoded to `str`
+ """
+ if isinstance(s, binary_type):
+ return s.decode(encoding, errors)
+ elif isinstance(s, text_type):
+ return s
+ else:
+ raise TypeError("not expecting type '%s'" % type(s))
+
+
def python_2_unicode_compatible(klass):
"""
A decorator that defines __unicode__ and __str__ methods under Python 2.
@@ -834,12 +984,13 @@ def python_2_unicode_compatible(klass):
returning text and apply this decorator to the class.
"""
if PY2:
- if '__str__' not in klass.__dict__:
- raise ValueError("@python_2_unicode_compatible cannot be applied "
- "to %s because it doesn't define __str__()." %
- klass.__name__)
+ if "__str__" not in klass.__dict__:
+ raise ValueError(
+ "@python_2_unicode_compatible cannot be applied "
+ "to %s because it doesn't define __str__()." % klass.__name__
+ )
klass.__unicode__ = klass.__str__
- klass.__str__ = lambda self: self.__unicode__().encode('utf-8')
+ klass.__str__ = lambda self: self.__unicode__().encode("utf-8")
return klass
@@ -859,8 +1010,10 @@ if sys.meta_path:
# be floating around. Therefore, we can't use isinstance() to check for
# the six meta path importer, since the other six instance will have
# inserted an importer with different class.
- if (type(importer).__name__ == "_SixMetaPathImporter" and
- importer.name == __name__):
+ if (
+ type(importer).__name__ == "_SixMetaPathImporter"
+ and importer.name == __name__
+ ):
del sys.meta_path[i]
break
del i, importer
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py
index d6594eb..75b6bb1 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py
@@ -16,4 +16,4 @@ except ImportError:
from ._implementation import CertificateError, match_hostname
# Not needed, but documenting what we provide.
-__all__ = ('CertificateError', 'match_hostname')
+__all__ = ("CertificateError", "match_hostname")
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__pycache__/__init__.cpython-38.pyc
index 0c9fa6c..92f09ff 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__pycache__/_implementation.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__pycache__/_implementation.cpython-38.pyc
index f763571..f163674 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__pycache__/_implementation.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__pycache__/_implementation.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py
index 970cf65..5831c2e 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py
@@ -15,7 +15,7 @@ try:
except ImportError:
ipaddress = None
-__version__ = '3.5.0.1'
+__version__ = "3.5.0.1"
class CertificateError(ValueError):
@@ -33,18 +33,19 @@ def _dnsname_match(dn, hostname, max_wildcards=1):
# Ported from python3-syntax:
# leftmost, *remainder = dn.split(r'.')
- parts = dn.split(r'.')
+ parts = dn.split(r".")
leftmost = parts[0]
remainder = parts[1:]
- wildcards = leftmost.count('*')
+ wildcards = leftmost.count("*")
if wildcards > max_wildcards:
# Issue #17980: avoid denials of service by refusing more
# than one wildcard per fragment. A survey of established
# policy among SSL implementations showed it to be a
# reasonable choice.
raise CertificateError(
- "too many wildcards in certificate DNS name: " + repr(dn))
+ "too many wildcards in certificate DNS name: " + repr(dn)
+ )
# speed up common case w/o wildcards
if not wildcards:
@@ -53,11 +54,11 @@ def _dnsname_match(dn, hostname, max_wildcards=1):
# RFC 6125, section 6.4.3, subitem 1.
# The client SHOULD NOT attempt to match a presented identifier in which
# the wildcard character comprises a label other than the left-most label.
- if leftmost == '*':
+ if leftmost == "*":
# When '*' is a fragment by itself, it matches a non-empty dotless
# fragment.
- pats.append('[^.]+')
- elif leftmost.startswith('xn--') or hostname.startswith('xn--'):
+ pats.append("[^.]+")
+ elif leftmost.startswith("xn--") or hostname.startswith("xn--"):
# RFC 6125, section 6.4.3, subitem 3.
# The client SHOULD NOT attempt to match a presented identifier
# where the wildcard character is embedded within an A-label or
@@ -65,21 +66,22 @@ def _dnsname_match(dn, hostname, max_wildcards=1):
pats.append(re.escape(leftmost))
else:
# Otherwise, '*' matches any dotless string, e.g. www*
- pats.append(re.escape(leftmost).replace(r'\*', '[^.]*'))
+ pats.append(re.escape(leftmost).replace(r"\*", "[^.]*"))
# add the remaining fragments, ignore any wildcards
for frag in remainder:
pats.append(re.escape(frag))
- pat = re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE)
+ pat = re.compile(r"\A" + r"\.".join(pats) + r"\Z", re.IGNORECASE)
return pat.match(hostname)
def _to_unicode(obj):
if isinstance(obj, str) and sys.version_info < (3,):
- obj = unicode(obj, encoding='ascii', errors='strict')
+ obj = unicode(obj, encoding="ascii", errors="strict")
return obj
+
def _ipaddress_match(ipname, host_ip):
"""Exact matching of IP addresses.
@@ -101,9 +103,11 @@ def match_hostname(cert, hostname):
returns nothing.
"""
if not cert:
- raise ValueError("empty or no certificate, match_hostname needs a "
- "SSL socket or SSL context with either "
- "CERT_OPTIONAL or CERT_REQUIRED")
+ raise ValueError(
+ "empty or no certificate, match_hostname needs a "
+ "SSL socket or SSL context with either "
+ "CERT_OPTIONAL or CERT_REQUIRED"
+ )
try:
# Divergence from upstream: ipaddress can't handle byte str
host_ip = ipaddress.ip_address(_to_unicode(hostname))
@@ -122,35 +126,35 @@ def match_hostname(cert, hostname):
else:
raise
dnsnames = []
- san = cert.get('subjectAltName', ())
+ san = cert.get("subjectAltName", ())
for key, value in san:
- if key == 'DNS':
+ if key == "DNS":
if host_ip is None and _dnsname_match(value, hostname):
return
dnsnames.append(value)
- elif key == 'IP Address':
+ elif key == "IP Address":
if host_ip is not None and _ipaddress_match(value, host_ip):
return
dnsnames.append(value)
if not dnsnames:
# The subject is only checked when there is no dNSName entry
# in subjectAltName
- for sub in cert.get('subject', ()):
+ for sub in cert.get("subject", ()):
for key, value in sub:
# XXX according to RFC 2818, the most specific Common Name
# must be used.
- if key == 'commonName':
+ if key == "commonName":
if _dnsname_match(value, hostname):
return
dnsnames.append(value)
if len(dnsnames) > 1:
- raise CertificateError("hostname %r "
- "doesn't match either of %s"
- % (hostname, ', '.join(map(repr, dnsnames))))
+ raise CertificateError(
+ "hostname %r "
+ "doesn't match either of %s" % (hostname, ", ".join(map(repr, dnsnames)))
+ )
elif len(dnsnames) == 1:
- raise CertificateError("hostname %r "
- "doesn't match %r"
- % (hostname, dnsnames[0]))
+ raise CertificateError("hostname %r doesn't match %r" % (hostname, dnsnames[0]))
else:
- raise CertificateError("no appropriate commonName or "
- "subjectAltName fields were found")
+ raise CertificateError(
+ "no appropriate commonName or subjectAltName fields were found"
+ )
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/poolmanager.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/poolmanager.py
index a6ade6e..e2bd3bd 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/poolmanager.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/poolmanager.py
@@ -2,11 +2,17 @@ from __future__ import absolute_import
import collections
import functools
import logging
+import warnings
from ._collections import RecentlyUsedContainer
from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool
from .connectionpool import port_by_scheme
-from .exceptions import LocationValueError, MaxRetryError, ProxySchemeUnknown
+from .exceptions import (
+ LocationValueError,
+ MaxRetryError,
+ ProxySchemeUnknown,
+ InvalidProxyConfigurationWarning,
+)
from .packages import six
from .packages.six.moves.urllib.parse import urljoin
from .request import RequestMethods
@@ -14,48 +20,55 @@ from .util.url import parse_url
from .util.retry import Retry
-__all__ = ['PoolManager', 'ProxyManager', 'proxy_from_url']
+__all__ = ["PoolManager", "ProxyManager", "proxy_from_url"]
log = logging.getLogger(__name__)
-SSL_KEYWORDS = ('key_file', 'cert_file', 'cert_reqs', 'ca_certs',
- 'ssl_version', 'ca_cert_dir', 'ssl_context',
- 'key_password')
+SSL_KEYWORDS = (
+ "key_file",
+ "cert_file",
+ "cert_reqs",
+ "ca_certs",
+ "ssl_version",
+ "ca_cert_dir",
+ "ssl_context",
+ "key_password",
+)
# All known keyword arguments that could be provided to the pool manager, its
# pools, or the underlying connections. This is used to construct a pool key.
_key_fields = (
- 'key_scheme', # str
- 'key_host', # str
- 'key_port', # int
- 'key_timeout', # int or float or Timeout
- 'key_retries', # int or Retry
- 'key_strict', # bool
- 'key_block', # bool
- 'key_source_address', # str
- 'key_key_file', # str
- 'key_key_password', # str
- 'key_cert_file', # str
- 'key_cert_reqs', # str
- 'key_ca_certs', # str
- 'key_ssl_version', # str
- 'key_ca_cert_dir', # str
- 'key_ssl_context', # instance of ssl.SSLContext or urllib3.util.ssl_.SSLContext
- 'key_maxsize', # int
- 'key_headers', # dict
- 'key__proxy', # parsed proxy url
- 'key__proxy_headers', # dict
- 'key_socket_options', # list of (level (int), optname (int), value (int or str)) tuples
- 'key__socks_options', # dict
- 'key_assert_hostname', # bool or string
- 'key_assert_fingerprint', # str
- 'key_server_hostname', # str
+ "key_scheme", # str
+ "key_host", # str
+ "key_port", # int
+ "key_timeout", # int or float or Timeout
+ "key_retries", # int or Retry
+ "key_strict", # bool
+ "key_block", # bool
+ "key_source_address", # str
+ "key_key_file", # str
+ "key_key_password", # str
+ "key_cert_file", # str
+ "key_cert_reqs", # str
+ "key_ca_certs", # str
+ "key_ssl_version", # str
+ "key_ca_cert_dir", # str
+ "key_ssl_context", # instance of ssl.SSLContext or urllib3.util.ssl_.SSLContext
+ "key_maxsize", # int
+ "key_headers", # dict
+ "key__proxy", # parsed proxy url
+ "key__proxy_headers", # dict
+ "key_socket_options", # list of (level (int), optname (int), value (int or str)) tuples
+ "key__socks_options", # dict
+ "key_assert_hostname", # bool or string
+ "key_assert_fingerprint", # str
+ "key_server_hostname", # str
)
#: The namedtuple class used to construct keys for the connection pool.
#: All custom key schemes should include the fields in this key at a minimum.
-PoolKey = collections.namedtuple('PoolKey', _key_fields)
+PoolKey = collections.namedtuple("PoolKey", _key_fields)
def _default_key_normalizer(key_class, request_context):
@@ -80,24 +93,24 @@ def _default_key_normalizer(key_class, request_context):
"""
# Since we mutate the dictionary, make a copy first
context = request_context.copy()
- context['scheme'] = context['scheme'].lower()
- context['host'] = context['host'].lower()
+ context["scheme"] = context["scheme"].lower()
+ context["host"] = context["host"].lower()
# These are both dictionaries and need to be transformed into frozensets
- for key in ('headers', '_proxy_headers', '_socks_options'):
+ for key in ("headers", "_proxy_headers", "_socks_options"):
if key in context and context[key] is not None:
context[key] = frozenset(context[key].items())
# The socket_options key may be a list and needs to be transformed into a
# tuple.
- socket_opts = context.get('socket_options')
+ socket_opts = context.get("socket_options")
if socket_opts is not None:
- context['socket_options'] = tuple(socket_opts)
+ context["socket_options"] = tuple(socket_opts)
# Map the kwargs to the names in the namedtuple - this is necessary since
# namedtuples can't have fields starting with '_'.
for key in list(context.keys()):
- context['key_' + key] = context.pop(key)
+ context["key_" + key] = context.pop(key)
# Default to ``None`` for keys missing from the context
for field in key_class._fields:
@@ -112,14 +125,11 @@ def _default_key_normalizer(key_class, request_context):
#: Each PoolManager makes a copy of this dictionary so they can be configured
#: globally here, or individually on the instance.
key_fn_by_scheme = {
- 'http': functools.partial(_default_key_normalizer, PoolKey),
- 'https': functools.partial(_default_key_normalizer, PoolKey),
+ "http": functools.partial(_default_key_normalizer, PoolKey),
+ "https": functools.partial(_default_key_normalizer, PoolKey),
}
-pool_classes_by_scheme = {
- 'http': HTTPConnectionPool,
- 'https': HTTPSConnectionPool,
-}
+pool_classes_by_scheme = {"http": HTTPConnectionPool, "https": HTTPSConnectionPool}
class PoolManager(RequestMethods):
@@ -155,8 +165,7 @@ class PoolManager(RequestMethods):
def __init__(self, num_pools=10, headers=None, **connection_pool_kw):
RequestMethods.__init__(self, headers)
self.connection_pool_kw = connection_pool_kw
- self.pools = RecentlyUsedContainer(num_pools,
- dispose_func=lambda p: p.close())
+ self.pools = RecentlyUsedContainer(num_pools, dispose_func=lambda p: p.close())
# Locally set the pool classes and keys so other PoolManagers can
# override them.
@@ -189,10 +198,10 @@ class PoolManager(RequestMethods):
# this function has historically only used the scheme, host, and port
# in the positional args. When an API change is acceptable these can
# be removed.
- for key in ('scheme', 'host', 'port'):
+ for key in ("scheme", "host", "port"):
request_context.pop(key, None)
- if scheme == 'http':
+ if scheme == "http":
for kw in SSL_KEYWORDS:
request_context.pop(kw, None)
@@ -207,7 +216,7 @@ class PoolManager(RequestMethods):
"""
self.pools.clear()
- def connection_from_host(self, host, port=None, scheme='http', pool_kwargs=None):
+ def connection_from_host(self, host, port=None, scheme="http", pool_kwargs=None):
"""
Get a :class:`ConnectionPool` based on the host, port, and scheme.
@@ -222,11 +231,11 @@ class PoolManager(RequestMethods):
raise LocationValueError("No host specified.")
request_context = self._merge_pool_kwargs(pool_kwargs)
- request_context['scheme'] = scheme or 'http'
+ request_context["scheme"] = scheme or "http"
if not port:
- port = port_by_scheme.get(request_context['scheme'].lower(), 80)
- request_context['port'] = port
- request_context['host'] = host
+ port = port_by_scheme.get(request_context["scheme"].lower(), 80)
+ request_context["port"] = port
+ request_context["host"] = host
return self.connection_from_context(request_context)
@@ -237,7 +246,7 @@ class PoolManager(RequestMethods):
``request_context`` must at least contain the ``scheme`` key and its
value must be a key in ``key_fn_by_scheme`` instance variable.
"""
- scheme = request_context['scheme'].lower()
+ scheme = request_context["scheme"].lower()
pool_key_constructor = self.key_fn_by_scheme[scheme]
pool_key = pool_key_constructor(request_context)
@@ -259,9 +268,9 @@ class PoolManager(RequestMethods):
return pool
# Make a fresh ConnectionPool of the desired type
- scheme = request_context['scheme']
- host = request_context['host']
- port = request_context['port']
+ scheme = request_context["scheme"]
+ host = request_context["host"]
+ port = request_context["port"]
pool = self._new_pool(scheme, host, port, request_context=request_context)
self.pools[pool_key] = pool
@@ -279,8 +288,9 @@ class PoolManager(RequestMethods):
not used.
"""
u = parse_url(url)
- return self.connection_from_host(u.host, port=u.port, scheme=u.scheme,
- pool_kwargs=pool_kwargs)
+ return self.connection_from_host(
+ u.host, port=u.port, scheme=u.scheme, pool_kwargs=pool_kwargs
+ )
def _merge_pool_kwargs(self, override):
"""
@@ -314,11 +324,11 @@ class PoolManager(RequestMethods):
u = parse_url(url)
conn = self.connection_from_host(u.host, port=u.port, scheme=u.scheme)
- kw['assert_same_host'] = False
- kw['redirect'] = False
+ kw["assert_same_host"] = False
+ kw["redirect"] = False
- if 'headers' not in kw:
- kw['headers'] = self.headers.copy()
+ if "headers" not in kw:
+ kw["headers"] = self.headers.copy()
if self.proxy is not None and u.scheme == "http":
response = conn.urlopen(method, url, **kw)
@@ -334,33 +344,37 @@ class PoolManager(RequestMethods):
# RFC 7231, Section 6.4.4
if response.status == 303:
- method = 'GET'
+ method = "GET"
- retries = kw.get('retries')
+ retries = kw.get("retries")
if not isinstance(retries, Retry):
retries = Retry.from_int(retries, redirect=redirect)
# Strip headers marked as unsafe to forward to the redirected location.
# Check remove_headers_on_redirect to avoid a potential network call within
# conn.is_same_host() which may use socket.gethostbyname() in the future.
- if (retries.remove_headers_on_redirect
- and not conn.is_same_host(redirect_location)):
- headers = list(six.iterkeys(kw['headers']))
+ if retries.remove_headers_on_redirect and not conn.is_same_host(
+ redirect_location
+ ):
+ headers = list(six.iterkeys(kw["headers"]))
for header in headers:
if header.lower() in retries.remove_headers_on_redirect:
- kw['headers'].pop(header, None)
+ kw["headers"].pop(header, None)
try:
retries = retries.increment(method, url, response=response, _pool=conn)
except MaxRetryError:
if retries.raise_on_redirect:
+ response.drain_conn()
raise
return response
- kw['retries'] = retries
- kw['redirect'] = redirect
+ kw["retries"] = retries
+ kw["redirect"] = redirect
log.info("Redirecting %s -> %s", url, redirect_location)
+
+ response.drain_conn()
return self.urlopen(method, redirect_location, **kw)
@@ -391,12 +405,21 @@ class ProxyManager(PoolManager):
"""
- def __init__(self, proxy_url, num_pools=10, headers=None,
- proxy_headers=None, **connection_pool_kw):
+ def __init__(
+ self,
+ proxy_url,
+ num_pools=10,
+ headers=None,
+ proxy_headers=None,
+ **connection_pool_kw
+ ):
if isinstance(proxy_url, HTTPConnectionPool):
- proxy_url = '%s://%s:%i' % (proxy_url.scheme, proxy_url.host,
- proxy_url.port)
+ proxy_url = "%s://%s:%i" % (
+ proxy_url.scheme,
+ proxy_url.host,
+ proxy_url.port,
+ )
proxy = parse_url(proxy_url)
if not proxy.port:
port = port_by_scheme.get(proxy.scheme, 80)
@@ -408,45 +431,59 @@ class ProxyManager(PoolManager):
self.proxy = proxy
self.proxy_headers = proxy_headers or {}
- connection_pool_kw['_proxy'] = self.proxy
- connection_pool_kw['_proxy_headers'] = self.proxy_headers
+ connection_pool_kw["_proxy"] = self.proxy
+ connection_pool_kw["_proxy_headers"] = self.proxy_headers
- super(ProxyManager, self).__init__(
- num_pools, headers, **connection_pool_kw)
+ super(ProxyManager, self).__init__(num_pools, headers, **connection_pool_kw)
- def connection_from_host(self, host, port=None, scheme='http', pool_kwargs=None):
+ def connection_from_host(self, host, port=None, scheme="http", pool_kwargs=None):
if scheme == "https":
return super(ProxyManager, self).connection_from_host(
- host, port, scheme, pool_kwargs=pool_kwargs)
+ host, port, scheme, pool_kwargs=pool_kwargs
+ )
return super(ProxyManager, self).connection_from_host(
- self.proxy.host, self.proxy.port, self.proxy.scheme, pool_kwargs=pool_kwargs)
+ self.proxy.host, self.proxy.port, self.proxy.scheme, pool_kwargs=pool_kwargs
+ )
def _set_proxy_headers(self, url, headers=None):
"""
Sets headers needed by proxies: specifically, the Accept and Host
headers. Only sets headers not provided by the user.
"""
- headers_ = {'Accept': '*/*'}
+ headers_ = {"Accept": "*/*"}
netloc = parse_url(url).netloc
if netloc:
- headers_['Host'] = netloc
+ headers_["Host"] = netloc
if headers:
headers_.update(headers)
return headers_
+ def _validate_proxy_scheme_url_selection(self, url_scheme):
+ if url_scheme == "https" and self.proxy.scheme == "https":
+ warnings.warn(
+ "Your proxy configuration specified an HTTPS scheme for the proxy. "
+ "Are you sure you want to use HTTPS to contact the proxy? "
+ "This most likely indicates an error in your configuration. "
+ "Read this issue for more info: "
+ "https://github.com/urllib3/urllib3/issues/1850",
+ InvalidProxyConfigurationWarning,
+ stacklevel=3,
+ )
+
def urlopen(self, method, url, redirect=True, **kw):
"Same as HTTP(S)ConnectionPool.urlopen, ``url`` must be absolute."
u = parse_url(url)
+ self._validate_proxy_scheme_url_selection(u.scheme)
if u.scheme == "http":
# For proxied HTTPS requests, httplib sets the necessary headers
# on the CONNECT to the proxy. For HTTP, we'll definitely
# need to set 'Host' at the very least.
- headers = kw.get('headers', self.headers)
- kw['headers'] = self._set_proxy_headers(url, headers)
+ headers = kw.get("headers", self.headers)
+ kw["headers"] = self._set_proxy_headers(url, headers)
return super(ProxyManager, self).urlopen(method, url, redirect=redirect, **kw)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/request.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/request.py
index 8f2f44b..55f160b 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/request.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/request.py
@@ -4,7 +4,7 @@ from .filepost import encode_multipart_formdata
from .packages.six.moves.urllib.parse import urlencode
-__all__ = ['RequestMethods']
+__all__ = ["RequestMethods"]
class RequestMethods(object):
@@ -36,16 +36,25 @@ class RequestMethods(object):
explicitly.
"""
- _encode_url_methods = {'DELETE', 'GET', 'HEAD', 'OPTIONS'}
+ _encode_url_methods = {"DELETE", "GET", "HEAD", "OPTIONS"}
def __init__(self, headers=None):
self.headers = headers or {}
- def urlopen(self, method, url, body=None, headers=None,
- encode_multipart=True, multipart_boundary=None,
- **kw): # Abstract
- raise NotImplementedError("Classes extending RequestMethods must implement "
- "their own ``urlopen`` method.")
+ def urlopen(
+ self,
+ method,
+ url,
+ body=None,
+ headers=None,
+ encode_multipart=True,
+ multipart_boundary=None,
+ **kw
+ ): # Abstract
+ raise NotImplementedError(
+ "Classes extending RequestMethods must implement "
+ "their own ``urlopen`` method."
+ )
def request(self, method, url, fields=None, headers=None, **urlopen_kw):
"""
@@ -60,19 +69,18 @@ class RequestMethods(object):
"""
method = method.upper()
- urlopen_kw['request_url'] = url
+ urlopen_kw["request_url"] = url
if method in self._encode_url_methods:
- return self.request_encode_url(method, url, fields=fields,
- headers=headers,
- **urlopen_kw)
+ return self.request_encode_url(
+ method, url, fields=fields, headers=headers, **urlopen_kw
+ )
else:
- return self.request_encode_body(method, url, fields=fields,
- headers=headers,
- **urlopen_kw)
+ return self.request_encode_body(
+ method, url, fields=fields, headers=headers, **urlopen_kw
+ )
- def request_encode_url(self, method, url, fields=None, headers=None,
- **urlopen_kw):
+ def request_encode_url(self, method, url, fields=None, headers=None, **urlopen_kw):
"""
Make a request using :meth:`urlopen` with the ``fields`` encoded in
the url. This is useful for request methods like GET, HEAD, DELETE, etc.
@@ -80,17 +88,24 @@ class RequestMethods(object):
if headers is None:
headers = self.headers
- extra_kw = {'headers': headers}
+ extra_kw = {"headers": headers}
extra_kw.update(urlopen_kw)
if fields:
- url += '?' + urlencode(fields)
+ url += "?" + urlencode(fields)
return self.urlopen(method, url, **extra_kw)
- def request_encode_body(self, method, url, fields=None, headers=None,
- encode_multipart=True, multipart_boundary=None,
- **urlopen_kw):
+ def request_encode_body(
+ self,
+ method,
+ url,
+ fields=None,
+ headers=None,
+ encode_multipart=True,
+ multipart_boundary=None,
+ **urlopen_kw
+ ):
"""
Make a request using :meth:`urlopen` with the ``fields`` encoded in
the body. This is useful for request methods like POST, PUT, PATCH, etc.
@@ -129,22 +144,28 @@ class RequestMethods(object):
if headers is None:
headers = self.headers
- extra_kw = {'headers': {}}
+ extra_kw = {"headers": {}}
if fields:
- if 'body' in urlopen_kw:
+ if "body" in urlopen_kw:
raise TypeError(
- "request got values for both 'fields' and 'body', can only specify one.")
+ "request got values for both 'fields' and 'body', can only specify one."
+ )
if encode_multipart:
- body, content_type = encode_multipart_formdata(fields, boundary=multipart_boundary)
+ body, content_type = encode_multipart_formdata(
+ fields, boundary=multipart_boundary
+ )
else:
- body, content_type = urlencode(fields), 'application/x-www-form-urlencoded'
+ body, content_type = (
+ urlencode(fields),
+ "application/x-www-form-urlencoded",
+ )
- extra_kw['body'] = body
- extra_kw['headers'] = {'Content-Type': content_type}
+ extra_kw["body"] = body
+ extra_kw["headers"] = {"Content-Type": content_type}
- extra_kw['headers'].update(headers)
+ extra_kw["headers"].update(headers)
extra_kw.update(urlopen_kw)
return self.urlopen(method, url, **extra_kw)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/response.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/response.py
index 4f85793..7dc9b93 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/response.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/response.py
@@ -13,8 +13,14 @@ except ImportError:
from ._collections import HTTPHeaderDict
from .exceptions import (
- BodyNotHttplibCompatible, ProtocolError, DecodeError, ReadTimeoutError,
- ResponseNotChunked, IncompleteRead, InvalidHeader
+ BodyNotHttplibCompatible,
+ ProtocolError,
+ DecodeError,
+ ReadTimeoutError,
+ ResponseNotChunked,
+ IncompleteRead,
+ InvalidHeader,
+ HTTPError,
)
from .packages.six import string_types as basestring, PY3
from .packages.six.moves import http_client as httplib
@@ -25,10 +31,9 @@ log = logging.getLogger(__name__)
class DeflateDecoder(object):
-
def __init__(self):
self._first_try = True
- self._data = b''
+ self._data = b""
self._obj = zlib.decompressobj()
def __getattr__(self, name):
@@ -65,7 +70,6 @@ class GzipDecoderState(object):
class GzipDecoder(object):
-
def __init__(self):
self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
self._state = GzipDecoderState.FIRST_MEMBER
@@ -96,6 +100,7 @@ class GzipDecoder(object):
if brotli is not None:
+
class BrotliDecoder(object):
# Supports both 'brotlipy' and 'Brotli' packages
# since they share an import name. The top branches
@@ -104,14 +109,14 @@ if brotli is not None:
self._obj = brotli.Decompressor()
def decompress(self, data):
- if hasattr(self._obj, 'decompress'):
+ if hasattr(self._obj, "decompress"):
return self._obj.decompress(data)
return self._obj.process(data)
def flush(self):
- if hasattr(self._obj, 'flush'):
+ if hasattr(self._obj, "flush"):
return self._obj.flush()
- return b''
+ return b""
class MultiDecoder(object):
@@ -124,7 +129,7 @@ class MultiDecoder(object):
"""
def __init__(self, modes):
- self._decoders = [_get_decoder(m.strip()) for m in modes.split(',')]
+ self._decoders = [_get_decoder(m.strip()) for m in modes.split(",")]
def flush(self):
return self._decoders[0].flush()
@@ -136,13 +141,13 @@ class MultiDecoder(object):
def _get_decoder(mode):
- if ',' in mode:
+ if "," in mode:
return MultiDecoder(mode)
- if mode == 'gzip':
+ if mode == "gzip":
return GzipDecoder()
- if brotli is not None and mode == 'br':
+ if brotli is not None and mode == "br":
return BrotliDecoder()
return DeflateDecoder()
@@ -181,16 +186,31 @@ class HTTPResponse(io.IOBase):
value of Content-Length header, if present. Otherwise, raise error.
"""
- CONTENT_DECODERS = ['gzip', 'deflate']
+ CONTENT_DECODERS = ["gzip", "deflate"]
if brotli is not None:
- CONTENT_DECODERS += ['br']
+ CONTENT_DECODERS += ["br"]
REDIRECT_STATUSES = [301, 302, 303, 307, 308]
- def __init__(self, body='', headers=None, status=0, version=0, reason=None,
- strict=0, preload_content=True, decode_content=True,
- original_response=None, pool=None, connection=None, msg=None,
- retries=None, enforce_content_length=False,
- request_method=None, request_url=None):
+ def __init__(
+ self,
+ body="",
+ headers=None,
+ status=0,
+ version=0,
+ reason=None,
+ strict=0,
+ preload_content=True,
+ decode_content=True,
+ original_response=None,
+ pool=None,
+ connection=None,
+ msg=None,
+ retries=None,
+ enforce_content_length=False,
+ request_method=None,
+ request_url=None,
+ auto_close=True,
+ ):
if isinstance(headers, HTTPHeaderDict):
self.headers = headers
@@ -203,6 +223,7 @@ class HTTPResponse(io.IOBase):
self.decode_content = decode_content
self.retries = retries
self.enforce_content_length = enforce_content_length
+ self.auto_close = auto_close
self._decoder = None
self._body = None
@@ -218,13 +239,13 @@ class HTTPResponse(io.IOBase):
self._pool = pool
self._connection = connection
- if hasattr(body, 'read'):
+ if hasattr(body, "read"):
self._fp = body
# Are we using the chunked-style of transfer encoding?
self.chunked = False
self.chunk_left = None
- tr_enc = self.headers.get('transfer-encoding', '').lower()
+ tr_enc = self.headers.get("transfer-encoding", "").lower()
# Don't incur the penalty of creating a list and then discarding it
encodings = (enc.strip() for enc in tr_enc.split(","))
if "chunked" in encodings:
@@ -246,7 +267,7 @@ class HTTPResponse(io.IOBase):
location. ``False`` if not a redirect status code.
"""
if self.status in self.REDIRECT_STATUSES:
- return self.headers.get('location')
+ return self.headers.get("location")
return False
@@ -257,6 +278,17 @@ class HTTPResponse(io.IOBase):
self._pool._put_conn(self._connection)
self._connection = None
+ def drain_conn(self):
+ """
+ Read and discard any remaining HTTP response data in the response connection.
+
+ Unread data in the HTTPResponse connection blocks the connection from being released back to the pool.
+ """
+ try:
+ self.read()
+ except (HTTPError, SocketError, BaseSSLError, HTTPException):
+ pass
+
@property
def data(self):
# For backwords-compat with earlier urllib3 0.4 and earlier.
@@ -285,18 +317,20 @@ class HTTPResponse(io.IOBase):
"""
Set initial length value for Response content if available.
"""
- length = self.headers.get('content-length')
+ length = self.headers.get("content-length")
if length is not None:
if self.chunked:
# This Response will fail with an IncompleteRead if it can't be
# received as chunked. This method falls back to attempt reading
# the response before raising an exception.
- log.warning("Received response with both Content-Length and "
- "Transfer-Encoding set. This is expressly forbidden "
- "by RFC 7230 sec 3.3.2. Ignoring Content-Length and "
- "attempting to process response as Transfer-Encoding: "
- "chunked.")
+ log.warning(
+ "Received response with both Content-Length and "
+ "Transfer-Encoding set. This is expressly forbidden "
+ "by RFC 7230 sec 3.3.2. Ignoring Content-Length and "
+ "attempting to process response as Transfer-Encoding: "
+ "chunked."
+ )
return None
try:
@@ -305,10 +339,12 @@ class HTTPResponse(io.IOBase):
# (e.g. Content-Length: 42, 42). This line ensures the values
# are all valid ints and that as long as the `set` length is 1,
# all values are the same. Otherwise, the header is invalid.
- lengths = set([int(val) for val in length.split(',')])
+ lengths = set([int(val) for val in length.split(",")])
if len(lengths) > 1:
- raise InvalidHeader("Content-Length contained multiple "
- "unmatching values (%s)" % length)
+ raise InvalidHeader(
+ "Content-Length contained multiple "
+ "unmatching values (%s)" % length
+ )
length = lengths.pop()
except ValueError:
length = None
@@ -324,7 +360,7 @@ class HTTPResponse(io.IOBase):
status = 0
# Check for responses that shouldn't include a body
- if status in (204, 304) or 100 <= status < 200 or request_method == 'HEAD':
+ if status in (204, 304) or 100 <= status < 200 or request_method == "HEAD":
length = 0
return length
@@ -335,14 +371,16 @@ class HTTPResponse(io.IOBase):
"""
# Note: content-encoding value should be case-insensitive, per RFC 7230
# Section 3.2
- content_encoding = self.headers.get('content-encoding', '').lower()
+ content_encoding = self.headers.get("content-encoding", "").lower()
if self._decoder is None:
if content_encoding in self.CONTENT_DECODERS:
self._decoder = _get_decoder(content_encoding)
- elif ',' in content_encoding:
+ elif "," in content_encoding:
encodings = [
- e.strip() for e in content_encoding.split(',')
- if e.strip() in self.CONTENT_DECODERS]
+ e.strip()
+ for e in content_encoding.split(",")
+ if e.strip() in self.CONTENT_DECODERS
+ ]
if len(encodings):
self._decoder = _get_decoder(content_encoding)
@@ -361,10 +399,12 @@ class HTTPResponse(io.IOBase):
if self._decoder:
data = self._decoder.decompress(data)
except self.DECODER_ERROR_CLASSES as e:
- content_encoding = self.headers.get('content-encoding', '').lower()
+ content_encoding = self.headers.get("content-encoding", "").lower()
raise DecodeError(
"Received response with content-encoding: %s, but "
- "failed to decode it." % content_encoding, e)
+ "failed to decode it." % content_encoding,
+ e,
+ )
if flush_decoder:
data += self._flush_decoder()
@@ -376,10 +416,10 @@ class HTTPResponse(io.IOBase):
being used.
"""
if self._decoder:
- buf = self._decoder.decompress(b'')
+ buf = self._decoder.decompress(b"")
return buf + self._decoder.flush()
- return b''
+ return b""
@contextmanager
def _error_catcher(self):
@@ -399,20 +439,20 @@ class HTTPResponse(io.IOBase):
except SocketTimeout:
# FIXME: Ideally we'd like to include the url in the ReadTimeoutError but
# there is yet no clean way to get at it from this context.
- raise ReadTimeoutError(self._pool, None, 'Read timed out.')
+ raise ReadTimeoutError(self._pool, None, "Read timed out.")
except BaseSSLError as e:
# FIXME: Is there a better way to differentiate between SSLErrors?
- if 'read operation timed out' not in str(e): # Defensive:
+ if "read operation timed out" not in str(e): # Defensive:
# This shouldn't happen but just in case we're missing an edge
# case, let's avoid swallowing SSL errors.
raise
- raise ReadTimeoutError(self._pool, None, 'Read timed out.')
+ raise ReadTimeoutError(self._pool, None, "Read timed out.")
except (HTTPException, SocketError) as e:
# This includes IncompleteRead.
- raise ProtocolError('Connection broken: %r' % e, e)
+ raise ProtocolError("Connection broken: %r" % e, e)
# If no exception is thrown, we should avoid cleaning up
# unnecessarily.
@@ -467,17 +507,19 @@ class HTTPResponse(io.IOBase):
return
flush_decoder = False
- data = None
+ fp_closed = getattr(self._fp, "closed", False)
with self._error_catcher():
if amt is None:
# cStringIO doesn't like amt=None
- data = self._fp.read()
+ data = self._fp.read() if not fp_closed else b""
flush_decoder = True
else:
cache_content = False
- data = self._fp.read(amt)
- if amt != 0 and not data: # Platform-specific: Buggy versions of Python.
+ data = self._fp.read(amt) if not fp_closed else b""
+ if (
+ amt != 0 and not data
+ ): # Platform-specific: Buggy versions of Python.
# Close the connection when no data is returned
#
# This is redundant to what httplib/http.client _should_
@@ -487,7 +529,10 @@ class HTTPResponse(io.IOBase):
# no harm in redundantly calling close.
self._fp.close()
flush_decoder = True
- if self.enforce_content_length and self.length_remaining not in (0, None):
+ if self.enforce_content_length and self.length_remaining not in (
+ 0,
+ None,
+ ):
# This is an edge case that httplib failed to cover due
# to concerns of backward compatibility. We're
# addressing it here to make sure IncompleteRead is
@@ -507,7 +552,7 @@ class HTTPResponse(io.IOBase):
return data
- def stream(self, amt=2**16, decode_content=None):
+ def stream(self, amt=2 ** 16, decode_content=None):
"""
A generator wrapper for the read() method. A call will block until
``amt`` bytes have been read from the connection or until the
@@ -552,15 +597,17 @@ class HTTPResponse(io.IOBase):
headers = HTTPHeaderDict.from_httplib(headers)
# HTTPResponse objects in Python 3 don't have a .strict attribute
- strict = getattr(r, 'strict', 0)
- resp = ResponseCls(body=r,
- headers=headers,
- status=r.status,
- version=r.version,
- reason=r.reason,
- strict=strict,
- original_response=r,
- **response_kw)
+ strict = getattr(r, "strict", 0)
+ resp = ResponseCls(
+ body=r,
+ headers=headers,
+ status=r.status,
+ version=r.version,
+ reason=r.reason,
+ strict=strict,
+ original_response=r,
+ **response_kw
+ )
return resp
# Backwards-compatibility methods for httplib.HTTPResponse
@@ -582,13 +629,18 @@ class HTTPResponse(io.IOBase):
if self._connection:
self._connection.close()
+ if not self.auto_close:
+ io.IOBase.close(self)
+
@property
def closed(self):
- if self._fp is None:
+ if not self.auto_close:
+ return io.IOBase.closed.__get__(self)
+ elif self._fp is None:
return True
- elif hasattr(self._fp, 'isclosed'):
+ elif hasattr(self._fp, "isclosed"):
return self._fp.isclosed()
- elif hasattr(self._fp, 'closed'):
+ elif hasattr(self._fp, "closed"):
return self._fp.closed
else:
return True
@@ -599,11 +651,17 @@ class HTTPResponse(io.IOBase):
elif hasattr(self._fp, "fileno"):
return self._fp.fileno()
else:
- raise IOError("The file-like object this HTTPResponse is wrapped "
- "around has no file descriptor")
+ raise IOError(
+ "The file-like object this HTTPResponse is wrapped "
+ "around has no file descriptor"
+ )
def flush(self):
- if self._fp is not None and hasattr(self._fp, 'flush'):
+ if (
+ self._fp is not None
+ and hasattr(self._fp, "flush")
+ and not getattr(self._fp, "closed", False)
+ ):
return self._fp.flush()
def readable(self):
@@ -616,7 +674,7 @@ class HTTPResponse(io.IOBase):
if len(temp) == 0:
return 0
else:
- b[:len(temp)] = temp
+ b[: len(temp)] = temp
return len(temp)
def supports_chunked_reads(self):
@@ -626,7 +684,7 @@ class HTTPResponse(io.IOBase):
attribute. If it is present we assume it returns raw chunks as
processed by read_chunked().
"""
- return hasattr(self._fp, 'fp')
+ return hasattr(self._fp, "fp")
def _update_chunk_length(self):
# First, we'll figure out length of a chunk and then
@@ -634,7 +692,7 @@ class HTTPResponse(io.IOBase):
if self.chunk_left is not None:
return
line = self._fp.fp.readline()
- line = line.split(b';', 1)[0]
+ line = line.split(b";", 1)[0]
try:
self.chunk_left = int(line, 16)
except ValueError:
@@ -683,11 +741,13 @@ class HTTPResponse(io.IOBase):
if not self.chunked:
raise ResponseNotChunked(
"Response is not chunked. "
- "Header 'transfer-encoding: chunked' is missing.")
+ "Header 'transfer-encoding: chunked' is missing."
+ )
if not self.supports_chunked_reads():
raise BodyNotHttplibCompatible(
"Body should be httplib.HTTPResponse like. "
- "It should have have an fp attribute which returns raw chunks.")
+ "It should have have an fp attribute which returns raw chunks."
+ )
with self._error_catcher():
# Don't bother reading the body of a HEAD request.
@@ -705,8 +765,9 @@ class HTTPResponse(io.IOBase):
if self.chunk_left == 0:
break
chunk = self._handle_chunk(amt)
- decoded = self._decode(chunk, decode_content=decode_content,
- flush_decoder=False)
+ decoded = self._decode(
+ chunk, decode_content=decode_content, flush_decoder=False
+ )
if decoded:
yield decoded
@@ -724,7 +785,7 @@ class HTTPResponse(io.IOBase):
if not line:
# Some sites may not end with '\r\n'.
break
- if line == b'\r\n':
+ if line == b"\r\n":
break
# We read everything; close the "file".
@@ -743,7 +804,7 @@ class HTTPResponse(io.IOBase):
return self._request_url
def __iter__(self):
- buffer = [b""]
+ buffer = []
for chunk in self.stream(decode_content=True):
if b"\n" in chunk:
chunk = chunk.split(b"\n")
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__init__.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__init__.py
index 2914bb4..a96c73a 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__init__.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__init__.py
@@ -1,4 +1,5 @@
from __future__ import absolute_import
+
# For backwards compatibility, provide imports that used to be here.
from .connection import is_connection_dropped
from .request import make_headers
@@ -14,43 +15,32 @@ from .ssl_ import (
ssl_wrap_socket,
PROTOCOL_TLS,
)
-from .timeout import (
- current_time,
- Timeout,
-)
+from .timeout import current_time, Timeout
from .retry import Retry
-from .url import (
- get_host,
- parse_url,
- split_first,
- Url,
-)
-from .wait import (
- wait_for_read,
- wait_for_write
-)
+from .url import get_host, parse_url, split_first, Url
+from .wait import wait_for_read, wait_for_write
__all__ = (
- 'HAS_SNI',
- 'IS_PYOPENSSL',
- 'IS_SECURETRANSPORT',
- 'SSLContext',
- 'PROTOCOL_TLS',
- 'Retry',
- 'Timeout',
- 'Url',
- 'assert_fingerprint',
- 'current_time',
- 'is_connection_dropped',
- 'is_fp_closed',
- 'get_host',
- 'parse_url',
- 'make_headers',
- 'resolve_cert_reqs',
- 'resolve_ssl_version',
- 'split_first',
- 'ssl_wrap_socket',
- 'wait_for_read',
- 'wait_for_write'
+ "HAS_SNI",
+ "IS_PYOPENSSL",
+ "IS_SECURETRANSPORT",
+ "SSLContext",
+ "PROTOCOL_TLS",
+ "Retry",
+ "Timeout",
+ "Url",
+ "assert_fingerprint",
+ "current_time",
+ "is_connection_dropped",
+ "is_fp_closed",
+ "get_host",
+ "parse_url",
+ "make_headers",
+ "resolve_cert_reqs",
+ "resolve_ssl_version",
+ "split_first",
+ "ssl_wrap_socket",
+ "wait_for_read",
+ "wait_for_write",
)
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-38.pyc
index 57f8d56..480089d 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-38.pyc
index cb61675..36800f6 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-38.pyc
index 07b9ee9..2ea0815 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-38.pyc
index 2d101c6..6603d3c 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-38.pyc
index f393f96..89f52ff 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-38.pyc
index a827462..ec8be23 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-38.pyc
index 31c6827..7187a18 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-38.pyc
index 9c92592..ee2ddd1 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-38.pyc
index 4a6d247..771a183 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-38.pyc
index b05c7d1..88c31de 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/connection.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/connection.py
index 5ad70b2..86f0a3b 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/connection.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/connection.py
@@ -14,7 +14,7 @@ def is_connection_dropped(conn): # Platform-specific
Note: For platforms like AppEngine, this will always return ``False`` to
let the platform handle connection recycling transparently for us.
"""
- sock = getattr(conn, 'sock', False)
+ sock = getattr(conn, "sock", False)
if sock is False: # Platform-specific: AppEngine
return False
if sock is None: # Connection already closed (such as by httplib).
@@ -30,8 +30,12 @@ def is_connection_dropped(conn): # Platform-specific
# library test suite. Added to its signature is only `socket_options`.
# One additional modification is that we avoid binding to IPv6 servers
# discovered in DNS if the system doesn't have IPv6 functionality.
-def create_connection(address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
- source_address=None, socket_options=None):
+def create_connection(
+ address,
+ timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
+ source_address=None,
+ socket_options=None,
+):
"""Connect to *address* and return the socket object.
Convenience function. Connect to *address* (a 2-tuple ``(host,
@@ -45,8 +49,8 @@ def create_connection(address, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
"""
host, port = address
- if host.startswith('['):
- host = host.strip('[]')
+ if host.startswith("["):
+ host = host.strip("[]")
err = None
# Using the value from allowed_gai_family() in the context of getaddrinfo lets
@@ -117,7 +121,7 @@ def _has_ipv6(host):
# has_ipv6 returns true if cPython was compiled with IPv6 support.
# It does not tell us if the system has IPv6 support enabled. To
# determine that we must bind to an IPv6 address.
- # https://github.com/shazow/urllib3/pull/611
+ # https://github.com/urllib3/urllib3/pull/611
# https://bugs.python.org/issue658327
try:
sock = socket.socket(socket.AF_INET6)
@@ -131,4 +135,4 @@ def _has_ipv6(host):
return has_ipv6
-HAS_IPV6 = _has_ipv6('::1')
+HAS_IPV6 = _has_ipv6("::1")
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/request.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/request.py
index 280b853..3b7bb54 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/request.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/request.py
@@ -4,19 +4,25 @@ from base64 import b64encode
from ..packages.six import b, integer_types
from ..exceptions import UnrewindableBodyError
-ACCEPT_ENCODING = 'gzip,deflate'
+ACCEPT_ENCODING = "gzip,deflate"
try:
import brotli as _unused_module_brotli # noqa: F401
except ImportError:
pass
else:
- ACCEPT_ENCODING += ',br'
+ ACCEPT_ENCODING += ",br"
_FAILEDTELL = object()
-def make_headers(keep_alive=None, accept_encoding=None, user_agent=None,
- basic_auth=None, proxy_basic_auth=None, disable_cache=None):
+def make_headers(
+ keep_alive=None,
+ accept_encoding=None,
+ user_agent=None,
+ basic_auth=None,
+ proxy_basic_auth=None,
+ disable_cache=None,
+):
"""
Shortcuts for generating request headers.
@@ -56,27 +62,27 @@ def make_headers(keep_alive=None, accept_encoding=None, user_agent=None,
if isinstance(accept_encoding, str):
pass
elif isinstance(accept_encoding, list):
- accept_encoding = ','.join(accept_encoding)
+ accept_encoding = ",".join(accept_encoding)
else:
accept_encoding = ACCEPT_ENCODING
- headers['accept-encoding'] = accept_encoding
+ headers["accept-encoding"] = accept_encoding
if user_agent:
- headers['user-agent'] = user_agent
+ headers["user-agent"] = user_agent
if keep_alive:
- headers['connection'] = 'keep-alive'
+ headers["connection"] = "keep-alive"
if basic_auth:
- headers['authorization'] = 'Basic ' + \
- b64encode(b(basic_auth)).decode('utf-8')
+ headers["authorization"] = "Basic " + b64encode(b(basic_auth)).decode("utf-8")
if proxy_basic_auth:
- headers['proxy-authorization'] = 'Basic ' + \
- b64encode(b(proxy_basic_auth)).decode('utf-8')
+ headers["proxy-authorization"] = "Basic " + b64encode(
+ b(proxy_basic_auth)
+ ).decode("utf-8")
if disable_cache:
- headers['cache-control'] = 'no-cache'
+ headers["cache-control"] = "no-cache"
return headers
@@ -88,7 +94,7 @@ def set_file_position(body, pos):
"""
if pos is not None:
rewind_body(body, pos)
- elif getattr(body, 'tell', None) is not None:
+ elif getattr(body, "tell", None) is not None:
try:
pos = body.tell()
except (IOError, OSError):
@@ -110,16 +116,20 @@ def rewind_body(body, body_pos):
:param int pos:
Position to seek to in file.
"""
- body_seek = getattr(body, 'seek', None)
+ body_seek = getattr(body, "seek", None)
if body_seek is not None and isinstance(body_pos, integer_types):
try:
body_seek(body_pos)
except (IOError, OSError):
- raise UnrewindableBodyError("An error occurred when rewinding request "
- "body for redirect/retry.")
+ raise UnrewindableBodyError(
+ "An error occurred when rewinding request body for redirect/retry."
+ )
elif body_pos is _FAILEDTELL:
- raise UnrewindableBodyError("Unable to record file position for rewinding "
- "request body during a redirect/retry.")
+ raise UnrewindableBodyError(
+ "Unable to record file position for rewinding "
+ "request body during a redirect/retry."
+ )
else:
- raise ValueError("body_pos must be of type integer, "
- "instead it was %s." % type(body_pos))
+ raise ValueError(
+ "body_pos must be of type integer, instead it was %s." % type(body_pos)
+ )
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/response.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/response.py
index 3d54864..715868d 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/response.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/response.py
@@ -52,11 +52,10 @@ def assert_header_parsing(headers):
# This will fail silently if we pass in the wrong kind of parameter.
# To make debugging easier add an explicit check.
if not isinstance(headers, httplib.HTTPMessage):
- raise TypeError('expected httplib.Message, got {0}.'.format(
- type(headers)))
+ raise TypeError("expected httplib.Message, got {0}.".format(type(headers)))
- defects = getattr(headers, 'defects', None)
- get_payload = getattr(headers, 'get_payload', None)
+ defects = getattr(headers, "defects", None)
+ get_payload = getattr(headers, "get_payload", None)
unparsed_data = None
if get_payload:
@@ -84,4 +83,4 @@ def is_response_to_head(response):
method = response._method
if isinstance(method, int): # Platform-specific: Appengine
return method == 3
- return method.upper() == 'HEAD'
+ return method.upper() == "HEAD"
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/retry.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/retry.py
index 02429ee..ee30c91 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/retry.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/retry.py
@@ -13,6 +13,7 @@ from ..exceptions import (
ReadTimeoutError,
ResponseError,
InvalidHeader,
+ ProxyError,
)
from ..packages import six
@@ -21,8 +22,9 @@ log = logging.getLogger(__name__)
# Data structure for representing the metadata of requests that result in a retry.
-RequestHistory = namedtuple('RequestHistory', ["method", "url", "error",
- "status", "redirect_location"])
+RequestHistory = namedtuple(
+ "RequestHistory", ["method", "url", "error", "status", "redirect_location"]
+)
class Retry(object):
@@ -146,21 +148,33 @@ class Retry(object):
request.
"""
- DEFAULT_METHOD_WHITELIST = frozenset([
- 'HEAD', 'GET', 'PUT', 'DELETE', 'OPTIONS', 'TRACE'])
+ DEFAULT_METHOD_WHITELIST = frozenset(
+ ["HEAD", "GET", "PUT", "DELETE", "OPTIONS", "TRACE"]
+ )
RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503])
- DEFAULT_REDIRECT_HEADERS_BLACKLIST = frozenset(['Authorization'])
+ DEFAULT_REDIRECT_HEADERS_BLACKLIST = frozenset(["Authorization"])
#: Maximum backoff time.
BACKOFF_MAX = 120
- def __init__(self, total=10, connect=None, read=None, redirect=None, status=None,
- method_whitelist=DEFAULT_METHOD_WHITELIST, status_forcelist=None,
- backoff_factor=0, raise_on_redirect=True, raise_on_status=True,
- history=None, respect_retry_after_header=True,
- remove_headers_on_redirect=DEFAULT_REDIRECT_HEADERS_BLACKLIST):
+ def __init__(
+ self,
+ total=10,
+ connect=None,
+ read=None,
+ redirect=None,
+ status=None,
+ method_whitelist=DEFAULT_METHOD_WHITELIST,
+ status_forcelist=None,
+ backoff_factor=0,
+ raise_on_redirect=True,
+ raise_on_status=True,
+ history=None,
+ respect_retry_after_header=True,
+ remove_headers_on_redirect=DEFAULT_REDIRECT_HEADERS_BLACKLIST,
+ ):
self.total = total
self.connect = connect
@@ -179,20 +193,25 @@ class Retry(object):
self.raise_on_status = raise_on_status
self.history = history or tuple()
self.respect_retry_after_header = respect_retry_after_header
- self.remove_headers_on_redirect = frozenset([
- h.lower() for h in remove_headers_on_redirect])
+ self.remove_headers_on_redirect = frozenset(
+ [h.lower() for h in remove_headers_on_redirect]
+ )
def new(self, **kw):
params = dict(
total=self.total,
- connect=self.connect, read=self.read, redirect=self.redirect, status=self.status,
+ connect=self.connect,
+ read=self.read,
+ redirect=self.redirect,
+ status=self.status,
method_whitelist=self.method_whitelist,
status_forcelist=self.status_forcelist,
backoff_factor=self.backoff_factor,
raise_on_redirect=self.raise_on_redirect,
raise_on_status=self.raise_on_status,
history=self.history,
- remove_headers_on_redirect=self.remove_headers_on_redirect
+ remove_headers_on_redirect=self.remove_headers_on_redirect,
+ respect_retry_after_header=self.respect_retry_after_header,
)
params.update(kw)
return type(self)(**params)
@@ -217,8 +236,11 @@ class Retry(object):
:rtype: float
"""
# We want to consider only the last consecutive errors sequence (Ignore redirects).
- consecutive_errors_len = len(list(takewhile(lambda x: x.redirect_location is None,
- reversed(self.history))))
+ consecutive_errors_len = len(
+ list(
+ takewhile(lambda x: x.redirect_location is None, reversed(self.history))
+ )
+ )
if consecutive_errors_len <= 1:
return 0
@@ -274,7 +296,7 @@ class Retry(object):
this method will return immediately.
"""
- if response:
+ if self.respect_retry_after_header and response:
slept = self.sleep_for_retry(response)
if slept:
return
@@ -285,6 +307,8 @@ class Retry(object):
""" Errors when we're fairly sure that the server did not receive the
request, so it should be safe to retry.
"""
+ if isinstance(err, ProxyError):
+ err = err.original_error
return isinstance(err, ConnectTimeoutError)
def _is_read_error(self, err):
@@ -315,8 +339,12 @@ class Retry(object):
if self.status_forcelist and status_code in self.status_forcelist:
return True
- return (self.total and self.respect_retry_after_header and
- has_retry_after and (status_code in self.RETRY_AFTER_STATUS_CODES))
+ return (
+ self.total
+ and self.respect_retry_after_header
+ and has_retry_after
+ and (status_code in self.RETRY_AFTER_STATUS_CODES)
+ )
def is_exhausted(self):
""" Are we out of retries? """
@@ -327,8 +355,15 @@ class Retry(object):
return min(retry_counts) < 0
- def increment(self, method=None, url=None, response=None, error=None,
- _pool=None, _stacktrace=None):
+ def increment(
+ self,
+ method=None,
+ url=None,
+ response=None,
+ error=None,
+ _pool=None,
+ _stacktrace=None,
+ ):
""" Return a new Retry object with incremented retry counters.
:param response: A response object, or None, if the server did not
@@ -351,7 +386,7 @@ class Retry(object):
read = self.read
redirect = self.redirect
status_count = self.status
- cause = 'unknown'
+ cause = "unknown"
status = None
redirect_location = None
@@ -373,7 +408,7 @@ class Retry(object):
# Redirect retry?
if redirect is not None:
redirect -= 1
- cause = 'too many redirects'
+ cause = "too many redirects"
redirect_location = response.get_redirect_location()
status = response.status
@@ -384,16 +419,21 @@ class Retry(object):
if response and response.status:
if status_count is not None:
status_count -= 1
- cause = ResponseError.SPECIFIC_ERROR.format(
- status_code=response.status)
+ cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status)
status = response.status
- history = self.history + (RequestHistory(method, url, error, status, redirect_location),)
+ history = self.history + (
+ RequestHistory(method, url, error, status, redirect_location),
+ )
new_retry = self.new(
total=total,
- connect=connect, read=read, redirect=redirect, status=status_count,
- history=history)
+ connect=connect,
+ read=read,
+ redirect=redirect,
+ status=status_count,
+ history=history,
+ )
if new_retry.is_exhausted():
raise MaxRetryError(_pool, url, error or ResponseError(cause))
@@ -403,9 +443,10 @@ class Retry(object):
return new_retry
def __repr__(self):
- return ('{cls.__name__}(total={self.total}, connect={self.connect}, '
- 'read={self.read}, redirect={self.redirect}, status={self.status})').format(
- cls=type(self), self=self)
+ return (
+ "{cls.__name__}(total={self.total}, connect={self.connect}, "
+ "read={self.read}, redirect={self.redirect}, status={self.status})"
+ ).format(cls=type(self), self=self)
# For backwards compatibility (equivalent to pre-v1.9):
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/ssl_.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/ssl_.py
index fbdef65..d3b463d 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/ssl_.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/ssl_.py
@@ -2,14 +2,14 @@ from __future__ import absolute_import
import errno
import warnings
import hmac
-import re
+import sys
from binascii import hexlify, unhexlify
from hashlib import md5, sha1, sha256
+from .url import IPV4_RE, BRACELESS_IPV6_ADDRZ_RE
from ..exceptions import SSLError, InsecurePlatformWarning, SNIMissingWarning
from ..packages import six
-from ..packages.rfc3986 import abnf_regexp
SSLContext = None
@@ -18,11 +18,7 @@ IS_PYOPENSSL = False
IS_SECURETRANSPORT = False
# Maps the length of a digest to a possible hash function producing this digest
-HASHFUNC_MAP = {
- 32: md5,
- 40: sha1,
- 64: sha256,
-}
+HASHFUNC_MAP = {32: md5, 40: sha1, 64: sha256}
def _const_compare_digest_backport(a, b):
@@ -38,18 +34,7 @@ def _const_compare_digest_backport(a, b):
return result == 0
-_const_compare_digest = getattr(hmac, 'compare_digest',
- _const_compare_digest_backport)
-
-# Borrow rfc3986's regular expressions for IPv4
-# and IPv6 addresses for use in is_ipaddress()
-_IP_ADDRESS_REGEX = re.compile(
- r'^(?:%s|%s|%s)$' % (
- abnf_regexp.IPv4_RE,
- abnf_regexp.IPv6_RE,
- abnf_regexp.IPv6_ADDRZ_RFC4007_RE
- )
-)
+_const_compare_digest = getattr(hmac, "compare_digest", _const_compare_digest_backport)
try: # Test for SSL features
import ssl
@@ -60,10 +45,12 @@ except ImportError:
try: # Platform-specific: Python 3.6
from ssl import PROTOCOL_TLS
+
PROTOCOL_SSLv23 = PROTOCOL_TLS
except ImportError:
try:
from ssl import PROTOCOL_SSLv23 as PROTOCOL_TLS
+
PROTOCOL_SSLv23 = PROTOCOL_TLS
except ImportError:
PROTOCOL_SSLv23 = PROTOCOL_TLS = 2
@@ -93,26 +80,29 @@ except ImportError:
# insecure ciphers for security reasons.
# - NOTE: TLS 1.3 cipher suites are managed through a different interface
# not exposed by CPython (yet!) and are enabled by default if they're available.
-DEFAULT_CIPHERS = ':'.join([
- 'ECDHE+AESGCM',
- 'ECDHE+CHACHA20',
- 'DHE+AESGCM',
- 'DHE+CHACHA20',
- 'ECDH+AESGCM',
- 'DH+AESGCM',
- 'ECDH+AES',
- 'DH+AES',
- 'RSA+AESGCM',
- 'RSA+AES',
- '!aNULL',
- '!eNULL',
- '!MD5',
- '!DSS',
-])
+DEFAULT_CIPHERS = ":".join(
+ [
+ "ECDHE+AESGCM",
+ "ECDHE+CHACHA20",
+ "DHE+AESGCM",
+ "DHE+CHACHA20",
+ "ECDH+AESGCM",
+ "DH+AESGCM",
+ "ECDH+AES",
+ "DH+AES",
+ "RSA+AESGCM",
+ "RSA+AES",
+ "!aNULL",
+ "!eNULL",
+ "!MD5",
+ "!DSS",
+ ]
+)
try:
from ssl import SSLContext # Modern SSL?
except ImportError:
+
class SSLContext(object): # Platform-specific: Python 2
def __init__(self, protocol_version):
self.protocol = protocol_version
@@ -129,32 +119,35 @@ except ImportError:
self.certfile = certfile
self.keyfile = keyfile
- def load_verify_locations(self, cafile=None, capath=None):
+ def load_verify_locations(self, cafile=None, capath=None, cadata=None):
self.ca_certs = cafile
if capath is not None:
raise SSLError("CA directories not supported in older Pythons")
+ if cadata is not None:
+ raise SSLError("CA data not supported in older Pythons")
+
def set_ciphers(self, cipher_suite):
self.ciphers = cipher_suite
def wrap_socket(self, socket, server_hostname=None, server_side=False):
warnings.warn(
- 'A true SSLContext object is not available. This prevents '
- 'urllib3 from configuring SSL appropriately and may cause '
- 'certain SSL connections to fail. You can upgrade to a newer '
- 'version of Python to solve this. For more information, see '
- 'https://urllib3.readthedocs.io/en/latest/advanced-usage.html'
- '#ssl-warnings',
- InsecurePlatformWarning
+ "A true SSLContext object is not available. This prevents "
+ "urllib3 from configuring SSL appropriately and may cause "
+ "certain SSL connections to fail. You can upgrade to a newer "
+ "version of Python to solve this. For more information, see "
+ "https://urllib3.readthedocs.io/en/latest/advanced-usage.html"
+ "#ssl-warnings",
+ InsecurePlatformWarning,
)
kwargs = {
- 'keyfile': self.keyfile,
- 'certfile': self.certfile,
- 'ca_certs': self.ca_certs,
- 'cert_reqs': self.verify_mode,
- 'ssl_version': self.protocol,
- 'server_side': server_side,
+ "keyfile": self.keyfile,
+ "certfile": self.certfile,
+ "ca_certs": self.ca_certs,
+ "cert_reqs": self.verify_mode,
+ "ssl_version": self.protocol,
+ "server_side": server_side,
}
return wrap_socket(socket, ciphers=self.ciphers, **kwargs)
@@ -169,12 +162,11 @@ def assert_fingerprint(cert, fingerprint):
Fingerprint as string of hexdigits, can be interspersed by colons.
"""
- fingerprint = fingerprint.replace(':', '').lower()
+ fingerprint = fingerprint.replace(":", "").lower()
digest_length = len(fingerprint)
hashfunc = HASHFUNC_MAP.get(digest_length)
if not hashfunc:
- raise SSLError(
- 'Fingerprint of invalid length: {0}'.format(fingerprint))
+ raise SSLError("Fingerprint of invalid length: {0}".format(fingerprint))
# We need encode() here for py32; works on py2 and p33.
fingerprint_bytes = unhexlify(fingerprint.encode())
@@ -182,15 +174,18 @@ def assert_fingerprint(cert, fingerprint):
cert_digest = hashfunc(cert).digest()
if not _const_compare_digest(cert_digest, fingerprint_bytes):
- raise SSLError('Fingerprints did not match. Expected "{0}", got "{1}".'
- .format(fingerprint, hexlify(cert_digest)))
+ raise SSLError(
+ 'Fingerprints did not match. Expected "{0}", got "{1}".'.format(
+ fingerprint, hexlify(cert_digest)
+ )
+ )
def resolve_cert_reqs(candidate):
"""
Resolves the argument to a numeric constant, which can be passed to
the wrap_socket function/method from the ssl module.
- Defaults to :data:`ssl.CERT_NONE`.
+ Defaults to :data:`ssl.CERT_REQUIRED`.
If given a string it is assumed to be the name of the constant in the
:mod:`ssl` module or its abbreviation.
(So you can specify `REQUIRED` instead of `CERT_REQUIRED`.
@@ -203,7 +198,7 @@ def resolve_cert_reqs(candidate):
if isinstance(candidate, str):
res = getattr(ssl, candidate, None)
if res is None:
- res = getattr(ssl, 'CERT_' + candidate)
+ res = getattr(ssl, "CERT_" + candidate)
return res
return candidate
@@ -219,14 +214,15 @@ def resolve_ssl_version(candidate):
if isinstance(candidate, str):
res = getattr(ssl, candidate, None)
if res is None:
- res = getattr(ssl, 'PROTOCOL_' + candidate)
+ res = getattr(ssl, "PROTOCOL_" + candidate)
return res
return candidate
-def create_urllib3_context(ssl_version=None, cert_reqs=None,
- options=None, ciphers=None):
+def create_urllib3_context(
+ ssl_version=None, cert_reqs=None, options=None, ciphers=None
+):
"""All arguments have the same meaning as ``ssl_wrap_socket``.
By default, this function does a lot of the same work that
@@ -279,18 +275,41 @@ def create_urllib3_context(ssl_version=None, cert_reqs=None,
context.options |= options
+ # Enable post-handshake authentication for TLS 1.3, see GH #1634. PHA is
+ # necessary for conditional client cert authentication with TLS 1.3.
+ # The attribute is None for OpenSSL <= 1.1.0 or does not exist in older
+ # versions of Python. We only enable on Python 3.7.4+ or if certificate
+ # verification is enabled to work around Python issue #37428
+ # See: https://bugs.python.org/issue37428
+ if (cert_reqs == ssl.CERT_REQUIRED or sys.version_info >= (3, 7, 4)) and getattr(
+ context, "post_handshake_auth", None
+ ) is not None:
+ context.post_handshake_auth = True
+
context.verify_mode = cert_reqs
- if getattr(context, 'check_hostname', None) is not None: # Platform-specific: Python 3.2
+ if (
+ getattr(context, "check_hostname", None) is not None
+ ): # Platform-specific: Python 3.2
# We do our own verification, including fingerprints and alternative
# hostnames. So disable it here
context.check_hostname = False
return context
-def ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None,
- ca_certs=None, server_hostname=None,
- ssl_version=None, ciphers=None, ssl_context=None,
- ca_cert_dir=None, key_password=None):
+def ssl_wrap_socket(
+ sock,
+ keyfile=None,
+ certfile=None,
+ cert_reqs=None,
+ ca_certs=None,
+ server_hostname=None,
+ ssl_version=None,
+ ciphers=None,
+ ssl_context=None,
+ ca_cert_dir=None,
+ key_password=None,
+ ca_cert_data=None,
+):
"""
All arguments except for server_hostname, ssl_context, and ca_cert_dir have
the same meaning as they do when using :func:`ssl.wrap_socket`.
@@ -308,18 +327,20 @@ def ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None,
SSLContext.load_verify_locations().
:param key_password:
Optional password if the keyfile is encrypted.
+ :param ca_cert_data:
+ Optional string containing CA certificates in PEM format suitable for
+ passing as the cadata parameter to SSLContext.load_verify_locations()
"""
context = ssl_context
if context is None:
# Note: This branch of code and all the variables in it are no longer
# used by urllib3 itself. We should consider deprecating and removing
# this code.
- context = create_urllib3_context(ssl_version, cert_reqs,
- ciphers=ciphers)
+ context = create_urllib3_context(ssl_version, cert_reqs, ciphers=ciphers)
- if ca_certs or ca_cert_dir:
+ if ca_certs or ca_cert_dir or ca_cert_data:
try:
- context.load_verify_locations(ca_certs, ca_cert_dir)
+ context.load_verify_locations(ca_certs, ca_cert_dir, ca_cert_data)
except IOError as e: # Platform-specific: Python 2.7
raise SSLError(e)
# Py33 raises FileNotFoundError which subclasses OSError
@@ -329,7 +350,7 @@ def ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None,
raise SSLError(e)
raise
- elif ssl_context is None and hasattr(context, 'load_default_certs'):
+ elif ssl_context is None and hasattr(context, "load_default_certs"):
# try to load OS default certs; works well on Windows (require Python3.4+)
context.load_default_certs()
@@ -349,20 +370,21 @@ def ssl_wrap_socket(sock, keyfile=None, certfile=None, cert_reqs=None,
# extension should not be used according to RFC3546 Section 3.1
# We shouldn't warn the user if SNI isn't available but we would
# not be using SNI anyways due to IP address for server_hostname.
- if ((server_hostname is not None and not is_ipaddress(server_hostname))
- or IS_SECURETRANSPORT):
+ if (
+ server_hostname is not None and not is_ipaddress(server_hostname)
+ ) or IS_SECURETRANSPORT:
if HAS_SNI and server_hostname is not None:
return context.wrap_socket(sock, server_hostname=server_hostname)
warnings.warn(
- 'An HTTPS request has been made, but the SNI (Server Name '
- 'Indication) extension to TLS is not available on this platform. '
- 'This may cause the server to present an incorrect TLS '
- 'certificate, which can cause validation failures. You can upgrade to '
- 'a newer version of Python to solve this. For more information, see '
- 'https://urllib3.readthedocs.io/en/latest/advanced-usage.html'
- '#ssl-warnings',
- SNIMissingWarning
+ "An HTTPS request has been made, but the SNI (Server Name "
+ "Indication) extension to TLS is not available on this platform. "
+ "This may cause the server to present an incorrect TLS "
+ "certificate, which can cause validation failures. You can upgrade to "
+ "a newer version of Python to solve this. For more information, see "
+ "https://urllib3.readthedocs.io/en/latest/advanced-usage.html"
+ "#ssl-warnings",
+ SNIMissingWarning,
)
return context.wrap_socket(sock)
@@ -375,18 +397,18 @@ def is_ipaddress(hostname):
:param str hostname: Hostname to examine.
:return: True if the hostname is an IP address, False otherwise.
"""
- if six.PY3 and isinstance(hostname, bytes):
+ if not six.PY2 and isinstance(hostname, bytes):
# IDN A-label bytes are ASCII compatible.
- hostname = hostname.decode('ascii')
- return _IP_ADDRESS_REGEX.match(hostname) is not None
+ hostname = hostname.decode("ascii")
+ return bool(IPV4_RE.match(hostname) or BRACELESS_IPV6_ADDRZ_RE.match(hostname))
def _is_key_file_encrypted(key_file):
"""Detects if a key file is encrypted or not."""
- with open(key_file, 'r') as f:
+ with open(key_file, "r") as f:
for line in f:
# Look for Proc-Type: 4,ENCRYPTED
- if 'ENCRYPTED' in line:
+ if "ENCRYPTED" in line:
return True
return False
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/timeout.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/timeout.py
index a4d004a..b61fea7 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/timeout.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/timeout.py
@@ -1,4 +1,5 @@
from __future__ import absolute_import
+
# The default socket timeout, used by httplib to indicate that no timeout was
# specified by the user
from socket import _GLOBAL_DEFAULT_TIMEOUT
@@ -45,19 +46,20 @@ class Timeout(object):
:type total: integer, float, or None
:param connect:
- The maximum amount of time to wait for a connection attempt to a server
- to succeed. Omitting the parameter will default the connect timeout to
- the system default, probably `the global default timeout in socket.py
+ The maximum amount of time (in seconds) to wait for a connection
+ attempt to a server to succeed. Omitting the parameter will default the
+ connect timeout to the system default, probably `the global default
+ timeout in socket.py
`_.
None will set an infinite timeout for connection attempts.
:type connect: integer, float, or None
:param read:
- The maximum amount of time to wait between consecutive
- read operations for a response from the server. Omitting
- the parameter will default the read timeout to the system
- default, probably `the global default timeout in socket.py
+ The maximum amount of time (in seconds) to wait between consecutive
+ read operations for a response from the server. Omitting the parameter
+ will default the read timeout to the system default, probably `the
+ global default timeout in socket.py
`_.
None will set an infinite timeout.
@@ -91,14 +93,21 @@ class Timeout(object):
DEFAULT_TIMEOUT = _GLOBAL_DEFAULT_TIMEOUT
def __init__(self, total=None, connect=_Default, read=_Default):
- self._connect = self._validate_timeout(connect, 'connect')
- self._read = self._validate_timeout(read, 'read')
- self.total = self._validate_timeout(total, 'total')
+ self._connect = self._validate_timeout(connect, "connect")
+ self._read = self._validate_timeout(read, "read")
+ self.total = self._validate_timeout(total, "total")
self._start_connect = None
- def __str__(self):
- return '%s(connect=%r, read=%r, total=%r)' % (
- type(self).__name__, self._connect, self._read, self.total)
+ def __repr__(self):
+ return "%s(connect=%r, read=%r, total=%r)" % (
+ type(self).__name__,
+ self._connect,
+ self._read,
+ self.total,
+ )
+
+ # __str__ provided for backwards compatibility
+ __str__ = __repr__
@classmethod
def _validate_timeout(cls, value, name):
@@ -118,23 +127,31 @@ class Timeout(object):
return value
if isinstance(value, bool):
- raise ValueError("Timeout cannot be a boolean value. It must "
- "be an int, float or None.")
+ raise ValueError(
+ "Timeout cannot be a boolean value. It must "
+ "be an int, float or None."
+ )
try:
float(value)
except (TypeError, ValueError):
- raise ValueError("Timeout value %s was %s, but it must be an "
- "int, float or None." % (name, value))
+ raise ValueError(
+ "Timeout value %s was %s, but it must be an "
+ "int, float or None." % (name, value)
+ )
try:
if value <= 0:
- raise ValueError("Attempted to set %s timeout to %s, but the "
- "timeout cannot be set to a value less "
- "than or equal to 0." % (name, value))
+ raise ValueError(
+ "Attempted to set %s timeout to %s, but the "
+ "timeout cannot be set to a value less "
+ "than or equal to 0." % (name, value)
+ )
except TypeError:
# Python 3
- raise ValueError("Timeout value %s was %s, but it must be an "
- "int, float or None." % (name, value))
+ raise ValueError(
+ "Timeout value %s was %s, but it must be an "
+ "int, float or None." % (name, value)
+ )
return value
@@ -166,8 +183,7 @@ class Timeout(object):
# We can't use copy.deepcopy because that will also create a new object
# for _GLOBAL_DEFAULT_TIMEOUT, which socket.py uses as a sentinel to
# detect the user default.
- return Timeout(connect=self._connect, read=self._read,
- total=self.total)
+ return Timeout(connect=self._connect, read=self._read, total=self.total)
def start_connect(self):
""" Start the timeout clock, used during a connect() attempt
@@ -183,14 +199,15 @@ class Timeout(object):
def get_connect_duration(self):
""" Gets the time elapsed since the call to :meth:`start_connect`.
- :return: Elapsed time.
+ :return: Elapsed time in seconds.
:rtype: float
:raises urllib3.exceptions.TimeoutStateError: if you attempt
to get duration for a timer that hasn't been started.
"""
if self._start_connect is None:
- raise TimeoutStateError("Can't get connect duration for timer "
- "that has not started.")
+ raise TimeoutStateError(
+ "Can't get connect duration for timer that has not started."
+ )
return current_time() - self._start_connect
@property
@@ -228,15 +245,16 @@ class Timeout(object):
:raises urllib3.exceptions.TimeoutStateError: If :meth:`start_connect`
has not yet been called on this object.
"""
- if (self.total is not None and
- self.total is not self.DEFAULT_TIMEOUT and
- self._read is not None and
- self._read is not self.DEFAULT_TIMEOUT):
+ if (
+ self.total is not None
+ and self.total is not self.DEFAULT_TIMEOUT
+ and self._read is not None
+ and self._read is not self.DEFAULT_TIMEOUT
+ ):
# In case the connect timeout has not yet been established.
if self._start_connect is None:
return self._read
- return max(0, min(self.total - self.get_connect_duration(),
- self._read))
+ return max(0, min(self.total - self.get_connect_duration(), self._read))
elif self.total is not None and self.total is not self.DEFAULT_TIMEOUT:
return max(0, self.total - self.get_connect_duration())
else:
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/url.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/url.py
index aefa119..0eb0b6a 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/url.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/url.py
@@ -3,41 +3,108 @@ import re
from collections import namedtuple
from ..exceptions import LocationParseError
-from ..packages import six, rfc3986
-from ..packages.rfc3986.exceptions import RFC3986Exception, ValidationError
-from ..packages.rfc3986.validators import Validator
-from ..packages.rfc3986 import abnf_regexp, normalizers, compat, misc
+from ..packages import six
-url_attrs = ['scheme', 'auth', 'host', 'port', 'path', 'query', 'fragment']
+url_attrs = ["scheme", "auth", "host", "port", "path", "query", "fragment"]
# We only want to normalize urls with an HTTP(S) scheme.
# urllib3 infers URLs without a scheme (None) to be http.
-NORMALIZABLE_SCHEMES = ('http', 'https', None)
+NORMALIZABLE_SCHEMES = ("http", "https", None)
-# Regex for detecting URLs with schemes. RFC 3986 Section 3.1
-SCHEME_REGEX = re.compile(r"^(?:[a-zA-Z][a-zA-Z0-9+\-]*:|/)")
+# Almost all of these patterns were derived from the
+# 'rfc3986' module: https://github.com/python-hyper/rfc3986
+PERCENT_RE = re.compile(r"%[a-fA-F0-9]{2}")
+SCHEME_RE = re.compile(r"^(?:[a-zA-Z][a-zA-Z0-9+-]*:|/)")
+URI_RE = re.compile(
+ r"^(?:([a-zA-Z][a-zA-Z0-9+.-]*):)?"
+ r"(?://([^\\/?#]*))?"
+ r"([^?#]*)"
+ r"(?:\?([^#]*))?"
+ r"(?:#(.*))?$",
+ re.UNICODE | re.DOTALL,
+)
-PATH_CHARS = abnf_regexp.UNRESERVED_CHARS_SET | abnf_regexp.SUB_DELIMITERS_SET | {':', '@', '/'}
-QUERY_CHARS = FRAGMENT_CHARS = PATH_CHARS | {'?'}
+IPV4_PAT = r"(?:[0-9]{1,3}\.){3}[0-9]{1,3}"
+HEX_PAT = "[0-9A-Fa-f]{1,4}"
+LS32_PAT = "(?:{hex}:{hex}|{ipv4})".format(hex=HEX_PAT, ipv4=IPV4_PAT)
+_subs = {"hex": HEX_PAT, "ls32": LS32_PAT}
+_variations = [
+ # 6( h16 ":" ) ls32
+ "(?:%(hex)s:){6}%(ls32)s",
+ # "::" 5( h16 ":" ) ls32
+ "::(?:%(hex)s:){5}%(ls32)s",
+ # [ h16 ] "::" 4( h16 ":" ) ls32
+ "(?:%(hex)s)?::(?:%(hex)s:){4}%(ls32)s",
+ # [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
+ "(?:(?:%(hex)s:)?%(hex)s)?::(?:%(hex)s:){3}%(ls32)s",
+ # [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
+ "(?:(?:%(hex)s:){0,2}%(hex)s)?::(?:%(hex)s:){2}%(ls32)s",
+ # [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
+ "(?:(?:%(hex)s:){0,3}%(hex)s)?::%(hex)s:%(ls32)s",
+ # [ *4( h16 ":" ) h16 ] "::" ls32
+ "(?:(?:%(hex)s:){0,4}%(hex)s)?::%(ls32)s",
+ # [ *5( h16 ":" ) h16 ] "::" h16
+ "(?:(?:%(hex)s:){0,5}%(hex)s)?::%(hex)s",
+ # [ *6( h16 ":" ) h16 ] "::"
+ "(?:(?:%(hex)s:){0,6}%(hex)s)?::",
+]
+
+UNRESERVED_PAT = r"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._!\-~"
+IPV6_PAT = "(?:" + "|".join([x % _subs for x in _variations]) + ")"
+ZONE_ID_PAT = "(?:%25|%)(?:[" + UNRESERVED_PAT + "]|%[a-fA-F0-9]{2})+"
+IPV6_ADDRZ_PAT = r"\[" + IPV6_PAT + r"(?:" + ZONE_ID_PAT + r")?\]"
+REG_NAME_PAT = r"(?:[^\[\]%:/?#]|%[a-fA-F0-9]{2})*"
+TARGET_RE = re.compile(r"^(/[^?#]*)(?:\?([^#]*))?(?:#.*)?$")
+
+IPV4_RE = re.compile("^" + IPV4_PAT + "$")
+IPV6_RE = re.compile("^" + IPV6_PAT + "$")
+IPV6_ADDRZ_RE = re.compile("^" + IPV6_ADDRZ_PAT + "$")
+BRACELESS_IPV6_ADDRZ_RE = re.compile("^" + IPV6_ADDRZ_PAT[2:-2] + "$")
+ZONE_ID_RE = re.compile("(" + ZONE_ID_PAT + r")\]$")
+
+SUBAUTHORITY_PAT = (u"^(?:(.*)@)?(%s|%s|%s)(?::([0-9]{0,5}))?$") % (
+ REG_NAME_PAT,
+ IPV4_PAT,
+ IPV6_ADDRZ_PAT,
+)
+SUBAUTHORITY_RE = re.compile(SUBAUTHORITY_PAT, re.UNICODE | re.DOTALL)
+
+UNRESERVED_CHARS = set(
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-~"
+)
+SUB_DELIM_CHARS = set("!$&'()*+,;=")
+USERINFO_CHARS = UNRESERVED_CHARS | SUB_DELIM_CHARS | {":"}
+PATH_CHARS = USERINFO_CHARS | {"@", "/"}
+QUERY_CHARS = FRAGMENT_CHARS = PATH_CHARS | {"?"}
-class Url(namedtuple('Url', url_attrs)):
+class Url(namedtuple("Url", url_attrs)):
"""
Data structure for representing an HTTP URL. Used as a return value for
:func:`parse_url`. Both the scheme and host are normalized as they are
both case-insensitive according to RFC 3986.
"""
+
__slots__ = ()
- def __new__(cls, scheme=None, auth=None, host=None, port=None, path=None,
- query=None, fragment=None):
- if path and not path.startswith('/'):
- path = '/' + path
+ def __new__(
+ cls,
+ scheme=None,
+ auth=None,
+ host=None,
+ port=None,
+ path=None,
+ query=None,
+ fragment=None,
+ ):
+ if path and not path.startswith("/"):
+ path = "/" + path
if scheme is not None:
scheme = scheme.lower()
- return super(Url, cls).__new__(cls, scheme, auth, host, port, path,
- query, fragment)
+ return super(Url, cls).__new__(
+ cls, scheme, auth, host, port, path, query, fragment
+ )
@property
def hostname(self):
@@ -47,10 +114,10 @@ class Url(namedtuple('Url', url_attrs)):
@property
def request_uri(self):
"""Absolute path including the query string."""
- uri = self.path or '/'
+ uri = self.path or "/"
if self.query is not None:
- uri += '?' + self.query
+ uri += "?" + self.query
return uri
@@ -58,7 +125,7 @@ class Url(namedtuple('Url', url_attrs)):
def netloc(self):
"""Network location including host and port"""
if self.port:
- return '%s:%d' % (self.host, self.port)
+ return "%s:%d" % (self.host, self.port)
return self.host
@property
@@ -81,23 +148,23 @@ class Url(namedtuple('Url', url_attrs)):
'http://username:password@host.com:80/path?query#fragment'
"""
scheme, auth, host, port, path, query, fragment = self
- url = u''
+ url = u""
# We use "is not None" we want things to happen with empty strings (or 0 port)
if scheme is not None:
- url += scheme + u'://'
+ url += scheme + u"://"
if auth is not None:
- url += auth + u'@'
+ url += auth + u"@"
if host is not None:
url += host
if port is not None:
- url += u':' + str(port)
+ url += u":" + str(port)
if path is not None:
url += path
if query is not None:
- url += u'?' + query
+ url += u"?" + query
if fragment is not None:
- url += u'#' + fragment
+ url += u"#" + fragment
return url
@@ -135,48 +202,140 @@ def split_first(s, delims):
min_delim = d
if min_idx is None or min_idx < 0:
- return s, '', None
+ return s, "", None
- return s[:min_idx], s[min_idx + 1:], min_delim
+ return s[:min_idx], s[min_idx + 1 :], min_delim
-def _encode_invalid_chars(component, allowed_chars, encoding='utf-8'):
+def _encode_invalid_chars(component, allowed_chars, encoding="utf-8"):
"""Percent-encodes a URI component without reapplying
- onto an already percent-encoded component. Based on
- rfc3986.normalizers.encode_component()
+ onto an already percent-encoded component.
"""
if component is None:
return component
+ component = six.ensure_text(component)
+
+ # Normalize existing percent-encoded bytes.
# Try to see if the component we're encoding is already percent-encoded
# so we can skip all '%' characters but still encode all others.
- percent_encodings = len(normalizers.PERCENT_MATCHER.findall(
- compat.to_str(component, encoding)))
-
- uri_bytes = component.encode('utf-8', 'surrogatepass')
- is_percent_encoded = percent_encodings == uri_bytes.count(b'%')
+ component, percent_encodings = PERCENT_RE.subn(
+ lambda match: match.group(0).upper(), component
+ )
+ uri_bytes = component.encode("utf-8", "surrogatepass")
+ is_percent_encoded = percent_encodings == uri_bytes.count(b"%")
encoded_component = bytearray()
for i in range(0, len(uri_bytes)):
# Will return a single character bytestring on both Python 2 & 3
- byte = uri_bytes[i:i+1]
+ byte = uri_bytes[i : i + 1]
byte_ord = ord(byte)
- if ((is_percent_encoded and byte == b'%')
- or (byte_ord < 128 and byte.decode() in allowed_chars)):
- encoded_component.extend(byte)
+ if (is_percent_encoded and byte == b"%") or (
+ byte_ord < 128 and byte.decode() in allowed_chars
+ ):
+ encoded_component += byte
continue
- encoded_component.extend('%{0:02x}'.format(byte_ord).encode().upper())
+ encoded_component.extend(b"%" + (hex(byte_ord)[2:].encode().zfill(2).upper()))
return encoded_component.decode(encoding)
+def _remove_path_dot_segments(path):
+ # See http://tools.ietf.org/html/rfc3986#section-5.2.4 for pseudo-code
+ segments = path.split("/") # Turn the path into a list of segments
+ output = [] # Initialize the variable to use to store output
+
+ for segment in segments:
+ # '.' is the current directory, so ignore it, it is superfluous
+ if segment == ".":
+ continue
+ # Anything other than '..', should be appended to the output
+ elif segment != "..":
+ output.append(segment)
+ # In this case segment == '..', if we can, we should pop the last
+ # element
+ elif output:
+ output.pop()
+
+ # If the path starts with '/' and the output is empty or the first string
+ # is non-empty
+ if path.startswith("/") and (not output or output[0]):
+ output.insert(0, "")
+
+ # If the path starts with '/.' or '/..' ensure we add one more empty
+ # string to add a trailing '/'
+ if path.endswith(("/.", "/..")):
+ output.append("")
+
+ return "/".join(output)
+
+
+def _normalize_host(host, scheme):
+ if host:
+ if isinstance(host, six.binary_type):
+ host = six.ensure_str(host)
+
+ if scheme in NORMALIZABLE_SCHEMES:
+ is_ipv6 = IPV6_ADDRZ_RE.match(host)
+ if is_ipv6:
+ match = ZONE_ID_RE.search(host)
+ if match:
+ start, end = match.span(1)
+ zone_id = host[start:end]
+
+ if zone_id.startswith("%25") and zone_id != "%25":
+ zone_id = zone_id[3:]
+ else:
+ zone_id = zone_id[1:]
+ zone_id = "%" + _encode_invalid_chars(zone_id, UNRESERVED_CHARS)
+ return host[:start].lower() + zone_id + host[end:]
+ else:
+ return host.lower()
+ elif not IPV4_RE.match(host):
+ return six.ensure_str(
+ b".".join([_idna_encode(label) for label in host.split(".")])
+ )
+ return host
+
+
+def _idna_encode(name):
+ if name and any([ord(x) > 128 for x in name]):
+ try:
+ from pip._vendor import idna
+ except ImportError:
+ six.raise_from(
+ LocationParseError("Unable to parse URL without the 'idna' module"),
+ None,
+ )
+ try:
+ return idna.encode(name.lower(), strict=True, std3_rules=True)
+ except idna.IDNAError:
+ six.raise_from(
+ LocationParseError(u"Name '%s' is not a valid IDNA label" % name), None
+ )
+ return name.lower().encode("ascii")
+
+
+def _encode_target(target):
+ """Percent-encodes a request target so that there are no invalid characters"""
+ path, query = TARGET_RE.match(target).groups()
+ target = _encode_invalid_chars(path, PATH_CHARS)
+ query = _encode_invalid_chars(query, QUERY_CHARS)
+ if query is not None:
+ target += "?" + query
+ return target
+
+
def parse_url(url):
"""
Given a url, return a parsed :class:`.Url` namedtuple. Best-effort is
performed to parse incomplete urls. Fields not provided will be None.
This parser is RFC 3986 compliant.
+ The parser logic and helper functions are based heavily on
+ work done in the ``rfc3986`` module.
+
:param str url: URL to parse into a :class:`.Url` namedtuple.
Partly backwards-compatible with :mod:`urlparse`.
@@ -194,90 +353,72 @@ def parse_url(url):
# Empty
return Url()
- is_string = not isinstance(url, six.binary_type)
-
- # RFC 3986 doesn't like URLs that have a host but don't start
- # with a scheme and we support URLs like that so we need to
- # detect that problem and add an empty scheme indication.
- # We don't get hurt on path-only URLs here as it's stripped
- # off and given an empty scheme anyways.
- if not SCHEME_REGEX.search(url):
+ source_url = url
+ if not SCHEME_RE.search(url):
url = "//" + url
- def idna_encode(name):
- if name and any([ord(x) > 128 for x in name]):
- try:
- from pip._vendor import idna
- except ImportError:
- raise LocationParseError("Unable to parse URL without the 'idna' module")
- try:
- return idna.encode(name.lower(), strict=True, std3_rules=True)
- except idna.IDNAError:
- raise LocationParseError(u"Name '%s' is not a valid IDNA label" % name)
- return name
-
try:
- split_iri = misc.IRI_MATCHER.match(compat.to_str(url)).groupdict()
- iri_ref = rfc3986.IRIReference(
- split_iri['scheme'], split_iri['authority'],
- _encode_invalid_chars(split_iri['path'], PATH_CHARS),
- _encode_invalid_chars(split_iri['query'], QUERY_CHARS),
- _encode_invalid_chars(split_iri['fragment'], FRAGMENT_CHARS)
- )
- has_authority = iri_ref.authority is not None
- uri_ref = iri_ref.encode(idna_encoder=idna_encode)
- except (ValueError, RFC3986Exception):
- return six.raise_from(LocationParseError(url), None)
+ scheme, authority, path, query, fragment = URI_RE.match(url).groups()
+ normalize_uri = scheme is None or scheme.lower() in NORMALIZABLE_SCHEMES
- # rfc3986 strips the authority if it's invalid
- if has_authority and uri_ref.authority is None:
- raise LocationParseError(url)
+ if scheme:
+ scheme = scheme.lower()
- # Only normalize schemes we understand to not break http+unix
- # or other schemes that don't follow RFC 3986.
- if uri_ref.scheme is None or uri_ref.scheme.lower() in NORMALIZABLE_SCHEMES:
- uri_ref = uri_ref.normalize()
+ if authority:
+ auth, host, port = SUBAUTHORITY_RE.match(authority).groups()
+ if auth and normalize_uri:
+ auth = _encode_invalid_chars(auth, USERINFO_CHARS)
+ if port == "":
+ port = None
+ else:
+ auth, host, port = None, None, None
- # Validate all URIReference components and ensure that all
- # components that were set before are still set after
- # normalization has completed.
- validator = Validator()
- try:
- validator.check_validity_of(
- *validator.COMPONENT_NAMES
- ).validate(uri_ref)
- except ValidationError:
- return six.raise_from(LocationParseError(url), None)
+ if port is not None:
+ port = int(port)
+ if not (0 <= port <= 65535):
+ raise LocationParseError(url)
+
+ host = _normalize_host(host, scheme)
+
+ if normalize_uri and path:
+ path = _remove_path_dot_segments(path)
+ path = _encode_invalid_chars(path, PATH_CHARS)
+ if normalize_uri and query:
+ query = _encode_invalid_chars(query, QUERY_CHARS)
+ if normalize_uri and fragment:
+ fragment = _encode_invalid_chars(fragment, FRAGMENT_CHARS)
+
+ except (ValueError, AttributeError):
+ return six.raise_from(LocationParseError(source_url), None)
# For the sake of backwards compatibility we put empty
# string values for path if there are any defined values
# beyond the path in the URL.
# TODO: Remove this when we break backwards compatibility.
- path = uri_ref.path
if not path:
- if (uri_ref.query is not None
- or uri_ref.fragment is not None):
+ if query is not None or fragment is not None:
path = ""
else:
path = None
# Ensure that each part of the URL is a `str` for
# backwards compatibility.
- def to_input_type(x):
- if x is None:
- return None
- elif not is_string and not isinstance(x, six.binary_type):
- return x.encode('utf-8')
- return x
+ if isinstance(url, six.text_type):
+ ensure_func = six.ensure_text
+ else:
+ ensure_func = six.ensure_str
+
+ def ensure_type(x):
+ return x if x is None else ensure_func(x)
return Url(
- scheme=to_input_type(uri_ref.scheme),
- auth=to_input_type(uri_ref.userinfo),
- host=to_input_type(uri_ref.host),
- port=int(uri_ref.port) if uri_ref.port is not None else None,
- path=to_input_type(path),
- query=to_input_type(uri_ref.query),
- fragment=to_input_type(uri_ref.fragment)
+ scheme=ensure_type(scheme),
+ auth=ensure_type(auth),
+ host=ensure_type(host),
+ port=port,
+ path=ensure_type(path),
+ query=ensure_type(query),
+ fragment=ensure_type(fragment),
)
@@ -286,4 +427,4 @@ def get_host(url):
Deprecated. Use :func:`parse_url` instead.
"""
p = parse_url(url)
- return p.scheme or 'http', p.hostname, p.port
+ return p.scheme or "http", p.hostname, p.port
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/wait.py b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/wait.py
index 4db71ba..d71d2fd 100644
--- a/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/wait.py
+++ b/venv/lib/python3.8/site-packages/pip/_vendor/urllib3/util/wait.py
@@ -2,6 +2,7 @@ import errno
from functools import partial
import select
import sys
+
try:
from time import monotonic
except ImportError:
@@ -40,6 +41,8 @@ if sys.version_info >= (3, 5):
# Modern Python, that retries syscalls by default
def _retry_on_intr(fn, timeout):
return fn(timeout)
+
+
else:
# Old and broken Pythons.
def _retry_on_intr(fn, timeout):
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/__init__.cpython-38.pyc
index b6c222f..467cd33 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/labels.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/labels.cpython-38.pyc
index e5503b4..df44f41 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/labels.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/labels.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/mklabels.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/mklabels.cpython-38.pyc
index 5443143..41d966e 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/mklabels.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/mklabels.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/tests.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/tests.cpython-38.pyc
index 4bca903..803eab8 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/tests.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/tests.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/x_user_defined.cpython-38.pyc b/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/x_user_defined.cpython-38.pyc
index 79c9d6a..6b91d3d 100644
Binary files a/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/x_user_defined.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pip/_vendor/webencodings/__pycache__/x_user_defined.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/__init__.py b/venv/lib/python3.8/site-packages/pkg_resources/__init__.py
index 1f170cf..5927ef0 100644
--- a/venv/lib/python3.8/site-packages/pkg_resources/__init__.py
+++ b/venv/lib/python3.8/site-packages/pkg_resources/__init__.py
@@ -55,7 +55,7 @@ except NameError:
FileExistsError = OSError
from pkg_resources.extern import six
-from pkg_resources.extern.six.moves import urllib, map, filter
+from pkg_resources.extern.six.moves import map, filter
# capture these to bypass sandboxing
from os import utime
@@ -76,7 +76,6 @@ try:
except ImportError:
importlib_machinery = None
-from . import py31compat
from pkg_resources.extern import appdirs
from pkg_resources.extern import packaging
__import__('pkg_resources.extern.packaging.version')
@@ -88,8 +87,8 @@ __import__('pkg_resources.extern.packaging.markers')
__metaclass__ = type
-if (3, 0) < sys.version_info < (3, 4):
- raise RuntimeError("Python 3.4 or later is required")
+if (3, 0) < sys.version_info < (3, 5):
+ raise RuntimeError("Python 3.5 or later is required")
if six.PY2:
# Those builtin exceptions are only defined in Python 3
@@ -178,10 +177,10 @@ def get_supported_platform():
"""Return this platform's maximum compatible version.
distutils.util.get_platform() normally reports the minimum version
- of Mac OS X that would be required to *use* extensions produced by
+ of macOS that would be required to *use* extensions produced by
distutils. But what we want when checking compatibility is to know the
- version of Mac OS X that we are *running*. To allow usage of packages that
- explicitly require a newer version of Mac OS X, we must also know the
+ version of macOS that we are *running*. To allow usage of packages that
+ explicitly require a newer version of macOS, we must also know the
current version of the OS.
If this condition occurs for any other platform with a version in its
@@ -191,9 +190,9 @@ def get_supported_platform():
m = macosVersionString.match(plat)
if m is not None and sys.platform == "darwin":
try:
- plat = 'macosx-%s-%s' % ('.'.join(_macosx_vers()[:2]), m.group(3))
+ plat = 'macosx-%s-%s' % ('.'.join(_macos_vers()[:2]), m.group(3))
except ValueError:
- # not Mac OS X
+ # not macOS
pass
return plat
@@ -333,7 +332,7 @@ class UnknownExtra(ResolutionError):
_provider_factories = {}
-PY_MAJOR = sys.version[:3]
+PY_MAJOR = '{}.{}'.format(*sys.version_info)
EGG_DIST = 3
BINARY_DIST = 2
SOURCE_DIST = 1
@@ -364,7 +363,7 @@ def get_provider(moduleOrReq):
return _find_adapter(_provider_factories, loader)(module)
-def _macosx_vers(_cache=[]):
+def _macos_vers(_cache=[]):
if not _cache:
version = platform.mac_ver()[0]
# fallback for MacPorts
@@ -380,7 +379,7 @@ def _macosx_vers(_cache=[]):
return _cache[0]
-def _macosx_arch(machine):
+def _macos_arch(machine):
return {'PowerPC': 'ppc', 'Power_Macintosh': 'ppc'}.get(machine, machine)
@@ -388,18 +387,18 @@ def get_build_platform():
"""Return this platform's string for platform-specific distributions
XXX Currently this is the same as ``distutils.util.get_platform()``, but it
- needs some hacks for Linux and Mac OS X.
+ needs some hacks for Linux and macOS.
"""
from sysconfig import get_platform
plat = get_platform()
if sys.platform == "darwin" and not plat.startswith('macosx-'):
try:
- version = _macosx_vers()
+ version = _macos_vers()
machine = os.uname()[4].replace(" ", "_")
return "macosx-%d.%d-%s" % (
int(version[0]), int(version[1]),
- _macosx_arch(machine),
+ _macos_arch(machine),
)
except ValueError:
# if someone is running a non-Mac darwin system, this will fall
@@ -425,7 +424,7 @@ def compatible_platforms(provided, required):
# easy case
return True
- # Mac OS X special cases
+ # macOS special cases
reqMac = macosVersionString.match(required)
if reqMac:
provMac = macosVersionString.match(provided)
@@ -434,7 +433,7 @@ def compatible_platforms(provided, required):
if not provMac:
# this is backwards compatibility for packages built before
# setuptools 0.6. All packages built after this point will
- # use the new macosx designation.
+ # use the new macOS designation.
provDarwin = darwinVersionString.match(provided)
if provDarwin:
dversion = int(provDarwin.group(1))
@@ -442,7 +441,7 @@ def compatible_platforms(provided, required):
if dversion == 7 and macosversion >= "10.3" or \
dversion == 8 and macosversion >= "10.4":
return True
- # egg isn't macosx or legacy darwin
+ # egg isn't macOS or legacy darwin
return False
# are they the same major version and machine type?
@@ -1234,12 +1233,13 @@ class ResourceManager:
mode = os.stat(path).st_mode
if mode & stat.S_IWOTH or mode & stat.S_IWGRP:
msg = (
- "%s is writable by group/others and vulnerable to attack "
- "when "
- "used with get_resource_filename. Consider a more secure "
+ "Extraction path is writable by group/others "
+ "and vulnerable to attack when "
+ "used with get_resource_filename ({path}). "
+ "Consider a more secure "
"location (set with .set_extraction_path or the "
- "PYTHON_EGG_CACHE environment variable)." % path
- )
+ "PYTHON_EGG_CACHE environment variable)."
+ ).format(**locals())
warnings.warn(msg, UserWarning)
def postprocess(self, tempname, filename):
@@ -1377,7 +1377,7 @@ def evaluate_marker(text, extra=None):
marker = packaging.markers.Marker(text)
return marker.evaluate()
except packaging.markers.InvalidMarker as e:
- raise SyntaxError(e)
+ raise SyntaxError(e) from e
class NullProvider:
@@ -1457,7 +1457,8 @@ class NullProvider:
script_filename = self._fn(self.egg_info, script)
namespace['__file__'] = script_filename
if os.path.exists(script_filename):
- source = open(script_filename).read()
+ with open(script_filename) as fid:
+ source = fid.read()
code = compile(source, script_filename, 'exec')
exec(code, namespace, namespace)
else:
@@ -1575,6 +1576,17 @@ is not allowed.
register_loader_type(object, NullProvider)
+def _parents(path):
+ """
+ yield all parents of path including path
+ """
+ last = None
+ while path != last:
+ yield path
+ last = path
+ path, _ = os.path.split(path)
+
+
class EggProvider(NullProvider):
"""Provider based on a virtual filesystem"""
@@ -1583,18 +1595,16 @@ class EggProvider(NullProvider):
self._setup_prefix()
def _setup_prefix(self):
- # we assume here that our metadata may be nested inside a "basket"
- # of multiple eggs; that's why we use module_path instead of .archive
- path = self.module_path
- old = None
- while path != old:
- if _is_egg_path(path):
- self.egg_name = os.path.basename(path)
- self.egg_info = os.path.join(path, 'EGG-INFO')
- self.egg_root = path
- break
- old = path
- path, base = os.path.split(path)
+ # Assume that metadata may be nested inside a "basket"
+ # of multiple eggs and use module_path instead of .archive.
+ eggs = filter(_is_egg_path, _parents(self.module_path))
+ egg = next(eggs, None)
+ egg and self._set_egg(egg)
+
+ def _set_egg(self, path):
+ self.egg_name = os.path.basename(path)
+ self.egg_info = os.path.join(path, 'EGG-INFO')
+ self.egg_root = path
class DefaultProvider(EggProvider):
@@ -2067,11 +2077,14 @@ def find_on_path(importer, path_item, only=False):
def dist_factory(path_item, entry, only):
- """
- Return a dist_factory for a path_item and entry
- """
+ """Return a dist_factory for the given entry."""
lower = entry.lower()
- is_meta = any(map(lower.endswith, ('.egg-info', '.dist-info')))
+ is_egg_info = lower.endswith('.egg-info')
+ is_dist_info = (
+ lower.endswith('.dist-info') and
+ os.path.isdir(os.path.join(path_item, entry))
+ )
+ is_meta = is_egg_info or is_dist_info
return (
distributions_from_metadata
if is_meta else
@@ -2195,10 +2208,14 @@ def _handle_ns(packageName, path_item):
if importer is None:
return None
- # capture warnings due to #1111
- with warnings.catch_warnings():
- warnings.simplefilter("ignore")
- loader = importer.find_module(packageName)
+ # use find_spec (PEP 451) and fall-back to find_module (PEP 302)
+ try:
+ loader = importer.find_spec(packageName).loader
+ except AttributeError:
+ # capture warnings due to #1111
+ with warnings.catch_warnings():
+ warnings.simplefilter("ignore")
+ loader = importer.find_module(packageName)
if loader is None:
return None
@@ -2270,8 +2287,8 @@ def declare_namespace(packageName):
__import__(parent)
try:
path = sys.modules[parent].__path__
- except AttributeError:
- raise TypeError("Not a package:", parent)
+ except AttributeError as e:
+ raise TypeError("Not a package:", parent) from e
# Track what packages are namespaces, so when new path items are added,
# they can be updated
@@ -2328,7 +2345,8 @@ register_namespace_handler(object, null_ns_handler)
def normalize_path(filename):
"""Normalize a file/dir name for comparison purposes"""
- return os.path.normcase(os.path.realpath(os.path.normpath(_cygwin_patch(filename))))
+ return os.path.normcase(os.path.realpath(os.path.normpath(
+ _cygwin_patch(filename))))
def _cygwin_patch(filename): # pragma: nocover
@@ -2450,7 +2468,7 @@ class EntryPoint:
try:
return functools.reduce(getattr, self.attrs, module)
except AttributeError as exc:
- raise ImportError(str(exc))
+ raise ImportError(str(exc)) from exc
def require(self, env=None, installer=None):
if self.extras and not self.dist:
@@ -2536,15 +2554,6 @@ class EntryPoint:
return maps
-def _remove_md5_fragment(location):
- if not location:
- return ''
- parsed = urllib.parse.urlparse(location)
- if parsed[-1].startswith('md5='):
- return urllib.parse.urlunparse(parsed[:-1] + ('',))
- return location
-
-
def _version_from_file(lines):
"""
Given an iterable of lines from a Metadata file, return
@@ -2601,7 +2610,7 @@ class Distribution:
self.parsed_version,
self.precedence,
self.key,
- _remove_md5_fragment(self.location),
+ self.location,
self.py_version or '',
self.platform or '',
)
@@ -2679,14 +2688,14 @@ class Distribution:
def version(self):
try:
return self._version
- except AttributeError:
+ except AttributeError as e:
version = self._get_version()
if version is None:
path = self._get_metadata_path_for_display(self.PKG_INFO)
msg = (
"Missing 'Version:' header and/or {} file at path: {}"
).format(self.PKG_INFO, path)
- raise ValueError(msg, self)
+ raise ValueError(msg, self) from e
return version
@@ -2739,10 +2748,10 @@ class Distribution:
for ext in extras:
try:
deps.extend(dm[safe_extra(ext)])
- except KeyError:
+ except KeyError as e:
raise UnknownExtra(
"%s has no such extra feature %r" % (self, ext)
- )
+ ) from e
return deps
def _get_metadata_path_for_display(self, name):
@@ -3067,11 +3076,6 @@ def issue_warning(*args, **kw):
warnings.warn(stacklevel=level + 1, *args, **kw)
-class RequirementParseError(ValueError):
- def __str__(self):
- return ' '.join(self.args)
-
-
def parse_requirements(strs):
"""Yield ``Requirement`` objects for each specification in `strs`
@@ -3094,13 +3098,14 @@ def parse_requirements(strs):
yield Requirement(line)
+class RequirementParseError(packaging.requirements.InvalidRequirement):
+ "Compatibility wrapper for InvalidRequirement"
+
+
class Requirement(packaging.requirements.Requirement):
def __init__(self, requirement_string):
"""DO NOT CALL THIS UNDOCUMENTED METHOD; use Requirement.parse()!"""
- try:
- super(Requirement, self).__init__(requirement_string)
- except packaging.requirements.InvalidRequirement as e:
- raise RequirementParseError(str(e))
+ super(Requirement, self).__init__(requirement_string)
self.unsafe_name = self.name
project_name = safe_name(self.name)
self.project_name, self.key = project_name, project_name.lower()
@@ -3109,6 +3114,7 @@ class Requirement(packaging.requirements.Requirement):
self.extras = tuple(map(safe_extra, self.extras))
self.hashCmp = (
self.key,
+ self.url,
self.specifier,
frozenset(self.extras),
str(self.marker) if self.marker else None,
@@ -3169,7 +3175,7 @@ def _find_adapter(registry, ob):
def ensure_directory(path):
"""Ensure that the parent directory of `path` exists"""
dirname = os.path.dirname(path)
- py31compat.makedirs(dirname, exist_ok=True)
+ os.makedirs(dirname, exist_ok=True)
def _bypass_ensure_directory(path):
@@ -3286,6 +3292,7 @@ def _initialize_master_working_set():
list(map(working_set.add_entry, sys.path))
globals().update(locals())
+
class PkgResourcesDeprecationWarning(Warning):
"""
Base class for warning about deprecations in ``pkg_resources``
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pkg_resources/__pycache__/__init__.cpython-38.pyc
index bdf865f..7603f71 100644
Binary files a/venv/lib/python3.8/site-packages/pkg_resources/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pkg_resources/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/__pycache__/py31compat.cpython-38.pyc b/venv/lib/python3.8/site-packages/pkg_resources/__pycache__/py31compat.cpython-38.pyc
deleted file mode 100644
index ceca597..0000000
Binary files a/venv/lib/python3.8/site-packages/pkg_resources/__pycache__/py31compat.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__pycache__/__init__.cpython-38.pyc
index ea089a9..07394f3 100644
Binary files a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__pycache__/appdirs.cpython-38.pyc b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__pycache__/appdirs.cpython-38.pyc
index 8335065..c7866cc 100644
Binary files a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__pycache__/appdirs.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__pycache__/appdirs.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__pycache__/pyparsing.cpython-38.pyc b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__pycache__/pyparsing.cpython-38.pyc
index 4ddd85b..0d94690 100644
Binary files a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__pycache__/pyparsing.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__pycache__/pyparsing.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__pycache__/six.cpython-38.pyc b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__pycache__/six.cpython-38.pyc
index d97140a..124abcd 100644
Binary files a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__pycache__/six.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/__pycache__/six.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__about__.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__about__.py
index 95d330e..dc95138 100644
--- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__about__.py
+++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__about__.py
@@ -4,18 +4,24 @@
from __future__ import absolute_import, division, print_function
__all__ = [
- "__title__", "__summary__", "__uri__", "__version__", "__author__",
- "__email__", "__license__", "__copyright__",
+ "__title__",
+ "__summary__",
+ "__uri__",
+ "__version__",
+ "__author__",
+ "__email__",
+ "__license__",
+ "__copyright__",
]
__title__ = "packaging"
__summary__ = "Core utilities for Python packages"
__uri__ = "https://github.com/pypa/packaging"
-__version__ = "16.8"
+__version__ = "19.2"
__author__ = "Donald Stufft and individual contributors"
__email__ = "donald@stufft.io"
__license__ = "BSD or Apache License, Version 2.0"
-__copyright__ = "Copyright 2014-2016 %s" % __author__
+__copyright__ = "Copyright 2014-2019 %s" % __author__
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__init__.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__init__.py
index 5ee6220..a0cf67d 100644
--- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__init__.py
+++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__init__.py
@@ -4,11 +4,23 @@
from __future__ import absolute_import, division, print_function
from .__about__ import (
- __author__, __copyright__, __email__, __license__, __summary__, __title__,
- __uri__, __version__
+ __author__,
+ __copyright__,
+ __email__,
+ __license__,
+ __summary__,
+ __title__,
+ __uri__,
+ __version__,
)
__all__ = [
- "__title__", "__summary__", "__uri__", "__version__", "__author__",
- "__email__", "__license__", "__copyright__",
+ "__title__",
+ "__summary__",
+ "__uri__",
+ "__version__",
+ "__author__",
+ "__email__",
+ "__license__",
+ "__copyright__",
]
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/__about__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/__about__.cpython-38.pyc
index 750d1f5..d04239a 100644
Binary files a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/__about__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/__about__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/__init__.cpython-38.pyc
index 4642ae2..599eed8 100644
Binary files a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/_compat.cpython-38.pyc b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/_compat.cpython-38.pyc
index 334678e..56f8305 100644
Binary files a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/_compat.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/_compat.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/_structures.cpython-38.pyc b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/_structures.cpython-38.pyc
index 0a42069..844f7b2 100644
Binary files a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/_structures.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/_structures.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/markers.cpython-38.pyc b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/markers.cpython-38.pyc
index 08bb3e4..11a2d71 100644
Binary files a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/markers.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/markers.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/requirements.cpython-38.pyc b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/requirements.cpython-38.pyc
index 42af351..2b5d683 100644
Binary files a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/requirements.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/requirements.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc
index 70e92ab..309f3bd 100644
Binary files a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/utils.cpython-38.pyc b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/utils.cpython-38.pyc
index e643152..e72a749 100644
Binary files a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/utils.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/utils.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/version.cpython-38.pyc b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/version.cpython-38.pyc
index 4f27ed8..125fbfc 100644
Binary files a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/version.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/__pycache__/version.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_compat.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_compat.py
index 210bb80..25da473 100644
--- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_compat.py
+++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_compat.py
@@ -12,9 +12,9 @@ PY3 = sys.version_info[0] == 3
# flake8: noqa
if PY3:
- string_types = str,
+ string_types = (str,)
else:
- string_types = basestring,
+ string_types = (basestring,)
def with_metaclass(meta, *bases):
@@ -27,4 +27,5 @@ def with_metaclass(meta, *bases):
class metaclass(meta):
def __new__(cls, name, this_bases, d):
return meta(name, bases, d)
- return type.__new__(metaclass, 'temporary_class', (), {})
+
+ return type.__new__(metaclass, "temporary_class", (), {})
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_structures.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_structures.py
index ccc2786..68dcca6 100644
--- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_structures.py
+++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/_structures.py
@@ -5,7 +5,6 @@ from __future__ import absolute_import, division, print_function
class Infinity(object):
-
def __repr__(self):
return "Infinity"
@@ -33,11 +32,11 @@ class Infinity(object):
def __neg__(self):
return NegativeInfinity
+
Infinity = Infinity()
class NegativeInfinity(object):
-
def __repr__(self):
return "-Infinity"
@@ -65,4 +64,5 @@ class NegativeInfinity(object):
def __neg__(self):
return Infinity
+
NegativeInfinity = NegativeInfinity()
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/markers.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/markers.py
index 892e578..733123f 100644
--- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/markers.py
+++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/markers.py
@@ -17,8 +17,11 @@ from .specifiers import Specifier, InvalidSpecifier
__all__ = [
- "InvalidMarker", "UndefinedComparison", "UndefinedEnvironmentName",
- "Marker", "default_environment",
+ "InvalidMarker",
+ "UndefinedComparison",
+ "UndefinedEnvironmentName",
+ "Marker",
+ "default_environment",
]
@@ -42,7 +45,6 @@ class UndefinedEnvironmentName(ValueError):
class Node(object):
-
def __init__(self, value):
self.value = value
@@ -57,62 +59,52 @@ class Node(object):
class Variable(Node):
-
def serialize(self):
return str(self)
class Value(Node):
-
def serialize(self):
return '"{0}"'.format(self)
class Op(Node):
-
def serialize(self):
return str(self)
VARIABLE = (
- L("implementation_version") |
- L("platform_python_implementation") |
- L("implementation_name") |
- L("python_full_version") |
- L("platform_release") |
- L("platform_version") |
- L("platform_machine") |
- L("platform_system") |
- L("python_version") |
- L("sys_platform") |
- L("os_name") |
- L("os.name") | # PEP-345
- L("sys.platform") | # PEP-345
- L("platform.version") | # PEP-345
- L("platform.machine") | # PEP-345
- L("platform.python_implementation") | # PEP-345
- L("python_implementation") | # undocumented setuptools legacy
- L("extra")
+ L("implementation_version")
+ | L("platform_python_implementation")
+ | L("implementation_name")
+ | L("python_full_version")
+ | L("platform_release")
+ | L("platform_version")
+ | L("platform_machine")
+ | L("platform_system")
+ | L("python_version")
+ | L("sys_platform")
+ | L("os_name")
+ | L("os.name")
+ | L("sys.platform") # PEP-345
+ | L("platform.version") # PEP-345
+ | L("platform.machine") # PEP-345
+ | L("platform.python_implementation") # PEP-345
+ | L("python_implementation") # PEP-345
+ | L("extra") # undocumented setuptools legacy
)
ALIASES = {
- 'os.name': 'os_name',
- 'sys.platform': 'sys_platform',
- 'platform.version': 'platform_version',
- 'platform.machine': 'platform_machine',
- 'platform.python_implementation': 'platform_python_implementation',
- 'python_implementation': 'platform_python_implementation'
+ "os.name": "os_name",
+ "sys.platform": "sys_platform",
+ "platform.version": "platform_version",
+ "platform.machine": "platform_machine",
+ "platform.python_implementation": "platform_python_implementation",
+ "python_implementation": "platform_python_implementation",
}
VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0])))
VERSION_CMP = (
- L("===") |
- L("==") |
- L(">=") |
- L("<=") |
- L("!=") |
- L("~=") |
- L(">") |
- L("<")
+ L("===") | L("==") | L(">=") | L("<=") | L("!=") | L("~=") | L(">") | L("<")
)
MARKER_OP = VERSION_CMP | L("not in") | L("in")
@@ -152,8 +144,11 @@ def _format_marker(marker, first=True):
# where the single item is itself it's own list. In that case we want skip
# the rest of this function so that we don't get extraneous () on the
# outside.
- if (isinstance(marker, list) and len(marker) == 1 and
- isinstance(marker[0], (list, tuple))):
+ if (
+ isinstance(marker, list)
+ and len(marker) == 1
+ and isinstance(marker[0], (list, tuple))
+ ):
return _format_marker(marker[0])
if isinstance(marker, list):
@@ -239,20 +234,20 @@ def _evaluate_markers(markers, environment):
def format_full_version(info):
- version = '{0.major}.{0.minor}.{0.micro}'.format(info)
+ version = "{0.major}.{0.minor}.{0.micro}".format(info)
kind = info.releaselevel
- if kind != 'final':
+ if kind != "final":
version += kind[0] + str(info.serial)
return version
def default_environment():
- if hasattr(sys, 'implementation'):
+ if hasattr(sys, "implementation"):
iver = format_full_version(sys.implementation.version)
implementation_name = sys.implementation.name
else:
- iver = '0'
- implementation_name = ''
+ iver = "0"
+ implementation_name = ""
return {
"implementation_name": implementation_name,
@@ -264,19 +259,19 @@ def default_environment():
"platform_version": platform.version(),
"python_full_version": platform.python_version(),
"platform_python_implementation": platform.python_implementation(),
- "python_version": platform.python_version()[:3],
+ "python_version": ".".join(platform.python_version_tuple()[:2]),
"sys_platform": sys.platform,
}
class Marker(object):
-
def __init__(self, marker):
try:
self._markers = _coerce_parse_result(MARKER.parseString(marker))
except ParseException as e:
err_str = "Invalid marker: {0!r}, parse error at {1!r}".format(
- marker, marker[e.loc:e.loc + 8])
+ marker, marker[e.loc : e.loc + 8]
+ )
raise InvalidMarker(err_str)
def __str__(self):
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/requirements.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/requirements.py
index 0c8c4a3..c3424dc 100644
--- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/requirements.py
+++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/requirements.py
@@ -38,8 +38,8 @@ IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END))
NAME = IDENTIFIER("name")
EXTRA = IDENTIFIER
-URI = Regex(r'[^ ]+')("url")
-URL = (AT + URI)
+URI = Regex(r"[^ ]+")("url")
+URL = AT + URI
EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA)
EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras")
@@ -48,28 +48,31 @@ VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE)
VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE)
VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY
-VERSION_MANY = Combine(VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE),
- joinString=",", adjacent=False)("_raw_spec")
+VERSION_MANY = Combine(
+ VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), joinString=",", adjacent=False
+)("_raw_spec")
_VERSION_SPEC = Optional(((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY))
-_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or '')
+_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or "")
VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier")
VERSION_SPEC.setParseAction(lambda s, l, t: t[1])
MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker")
MARKER_EXPR.setParseAction(
- lambda s, l, t: Marker(s[t._original_start:t._original_end])
+ lambda s, l, t: Marker(s[t._original_start : t._original_end])
)
-MARKER_SEPERATOR = SEMICOLON
-MARKER = MARKER_SEPERATOR + MARKER_EXPR
+MARKER_SEPARATOR = SEMICOLON
+MARKER = MARKER_SEPARATOR + MARKER_EXPR
VERSION_AND_MARKER = VERSION_SPEC + Optional(MARKER)
URL_AND_MARKER = URL + Optional(MARKER)
-NAMED_REQUIREMENT = \
- NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER)
+NAMED_REQUIREMENT = NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER)
REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd
+# pkg_resources.extern.pyparsing isn't thread safe during initialization, so we do it eagerly, see
+# issue #104
+REQUIREMENT.parseString("x[]")
class Requirement(object):
@@ -90,15 +93,21 @@ class Requirement(object):
req = REQUIREMENT.parseString(requirement_string)
except ParseException as e:
raise InvalidRequirement(
- "Invalid requirement, parse error at \"{0!r}\"".format(
- requirement_string[e.loc:e.loc + 8]))
+ 'Parse error at "{0!r}": {1}'.format(
+ requirement_string[e.loc : e.loc + 8], e.msg
+ )
+ )
self.name = req.name
if req.url:
parsed_url = urlparse.urlparse(req.url)
- if not (parsed_url.scheme and parsed_url.netloc) or (
- not parsed_url.scheme and not parsed_url.netloc):
- raise InvalidRequirement("Invalid URL given")
+ if parsed_url.scheme == "file":
+ if urlparse.urlunparse(parsed_url) != req.url:
+ raise InvalidRequirement("Invalid URL given")
+ elif not (parsed_url.scheme and parsed_url.netloc) or (
+ not parsed_url.scheme and not parsed_url.netloc
+ ):
+ raise InvalidRequirement("Invalid URL: {0}".format(req.url))
self.url = req.url
else:
self.url = None
@@ -117,6 +126,8 @@ class Requirement(object):
if self.url:
parts.append("@ {0}".format(self.url))
+ if self.marker:
+ parts.append(" ")
if self.marker:
parts.append("; {0}".format(self.marker))
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/specifiers.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/specifiers.py
index 7f5a76c..743576a 100644
--- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/specifiers.py
+++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/specifiers.py
@@ -19,7 +19,6 @@ class InvalidSpecifier(ValueError):
class BaseSpecifier(with_metaclass(abc.ABCMeta, object)):
-
@abc.abstractmethod
def __str__(self):
"""
@@ -84,10 +83,7 @@ class _IndividualSpecifier(BaseSpecifier):
if not match:
raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec))
- self._spec = (
- match.group("operator").strip(),
- match.group("version").strip(),
- )
+ self._spec = (match.group("operator").strip(), match.group("version").strip())
# Store whether or not this Specifier should accept prereleases
self._prereleases = prereleases
@@ -99,11 +95,7 @@ class _IndividualSpecifier(BaseSpecifier):
else ""
)
- return "<{0}({1!r}{2})>".format(
- self.__class__.__name__,
- str(self),
- pre,
- )
+ return "<{0}({1!r}{2})>".format(self.__class__.__name__, str(self), pre)
def __str__(self):
return "{0}{1}".format(*self._spec)
@@ -194,11 +186,12 @@ class _IndividualSpecifier(BaseSpecifier):
# If our version is a prerelease, and we were not set to allow
# prereleases, then we'll store it for later incase nothing
# else matches this specifier.
- if (parsed_version.is_prerelease and not
- (prereleases or self.prereleases)):
+ if parsed_version.is_prerelease and not (
+ prereleases or self.prereleases
+ ):
found_prereleases.append(version)
# Either this is not a prerelease, or we should have been
- # accepting prereleases from the begining.
+ # accepting prereleases from the beginning.
else:
yielded = True
yield version
@@ -213,8 +206,7 @@ class _IndividualSpecifier(BaseSpecifier):
class LegacySpecifier(_IndividualSpecifier):
- _regex_str = (
- r"""
+ _regex_str = r"""
(?P(==|!=|<=|>=|<|>))
\s*
(?P
@@ -225,10 +217,8 @@ class LegacySpecifier(_IndividualSpecifier):
# them, and a comma since it's a version separator.
)
"""
- )
- _regex = re.compile(
- r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
+ _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
_operators = {
"==": "equal",
@@ -269,13 +259,13 @@ def _require_version_compare(fn):
if not isinstance(prospective, Version):
return False
return fn(self, prospective, spec)
+
return wrapped
class Specifier(_IndividualSpecifier):
- _regex_str = (
- r"""
+ _regex_str = r"""
(?P(~=|==|!=|<=|>=|<|>|===))
(?P
(?:
@@ -367,10 +357,8 @@ class Specifier(_IndividualSpecifier):
)
)
"""
- )
- _regex = re.compile(
- r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
+ _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
_operators = {
"~=": "compatible",
@@ -397,8 +385,7 @@ class Specifier(_IndividualSpecifier):
prefix = ".".join(
list(
itertools.takewhile(
- lambda x: (not x.startswith("post") and not
- x.startswith("dev")),
+ lambda x: (not x.startswith("post") and not x.startswith("dev")),
_version_split(spec),
)
)[:-1]
@@ -407,8 +394,9 @@ class Specifier(_IndividualSpecifier):
# Add the prefix notation to the end of our string
prefix += ".*"
- return (self._get_operator(">=")(prospective, spec) and
- self._get_operator("==")(prospective, prefix))
+ return self._get_operator(">=")(prospective, spec) and self._get_operator("==")(
+ prospective, prefix
+ )
@_require_version_compare
def _compare_equal(self, prospective, spec):
@@ -428,7 +416,7 @@ class Specifier(_IndividualSpecifier):
# Shorten the prospective version to be the same length as the spec
# so that we can determine if the specifier is a prefix of the
# prospective version or not.
- prospective = prospective[:len(spec)]
+ prospective = prospective[: len(spec)]
# Pad out our two sides with zeros so that they both equal the same
# length.
@@ -503,7 +491,7 @@ class Specifier(_IndividualSpecifier):
return False
# Ensure that we do not allow a local version of the version mentioned
- # in the specifier, which is techincally greater than, to match.
+ # in the specifier, which is technically greater than, to match.
if prospective.local is not None:
if Version(prospective.base_version) == Version(spec.base_version):
return False
@@ -567,27 +555,17 @@ def _pad_version(left, right):
right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right)))
# Get the rest of our versions
- left_split.append(left[len(left_split[0]):])
- right_split.append(right[len(right_split[0]):])
+ left_split.append(left[len(left_split[0]) :])
+ right_split.append(right[len(right_split[0]) :])
# Insert our padding
- left_split.insert(
- 1,
- ["0"] * max(0, len(right_split[0]) - len(left_split[0])),
- )
- right_split.insert(
- 1,
- ["0"] * max(0, len(left_split[0]) - len(right_split[0])),
- )
+ left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0])))
+ right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0])))
- return (
- list(itertools.chain(*left_split)),
- list(itertools.chain(*right_split)),
- )
+ return (list(itertools.chain(*left_split)), list(itertools.chain(*right_split)))
class SpecifierSet(BaseSpecifier):
-
def __init__(self, specifiers="", prereleases=None):
# Split on , to break each indidivual specifier into it's own item, and
# strip each item to remove leading/trailing whitespace.
@@ -721,10 +699,7 @@ class SpecifierSet(BaseSpecifier):
# given version is contained within all of them.
# Note: This use of all() here means that an empty set of specifiers
# will always return True, this is an explicit design decision.
- return all(
- s.contains(item, prereleases=prereleases)
- for s in self._specs
- )
+ return all(s.contains(item, prereleases=prereleases) for s in self._specs)
def filter(self, iterable, prereleases=None):
# Determine if we're forcing a prerelease or not, if we're not forcing
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/utils.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/utils.py
index 942387c..8841878 100644
--- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/utils.py
+++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/utils.py
@@ -5,6 +5,8 @@ from __future__ import absolute_import, division, print_function
import re
+from .version import InvalidVersion, Version
+
_canonicalize_regex = re.compile(r"[-_.]+")
@@ -12,3 +14,44 @@ _canonicalize_regex = re.compile(r"[-_.]+")
def canonicalize_name(name):
# This is taken from PEP 503.
return _canonicalize_regex.sub("-", name).lower()
+
+
+def canonicalize_version(version):
+ """
+ This is very similar to Version.__str__, but has one subtle differences
+ with the way it handles the release segment.
+ """
+
+ try:
+ version = Version(version)
+ except InvalidVersion:
+ # Legacy versions cannot be normalized
+ return version
+
+ parts = []
+
+ # Epoch
+ if version.epoch != 0:
+ parts.append("{0}!".format(version.epoch))
+
+ # Release segment
+ # NB: This strips trailing '.0's to normalize
+ parts.append(re.sub(r"(\.0)+$", "", ".".join(str(x) for x in version.release)))
+
+ # Pre-release
+ if version.pre is not None:
+ parts.append("".join(str(x) for x in version.pre))
+
+ # Post-release
+ if version.post is not None:
+ parts.append(".post{0}".format(version.post))
+
+ # Development release
+ if version.dev is not None:
+ parts.append(".dev{0}".format(version.dev))
+
+ # Local version segment
+ if version.local is not None:
+ parts.append("+{0}".format(version.local))
+
+ return "".join(parts)
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/version.py b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/version.py
index 83b5ee8..95157a1 100644
--- a/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/version.py
+++ b/venv/lib/python3.8/site-packages/pkg_resources/_vendor/packaging/version.py
@@ -10,14 +10,11 @@ import re
from ._structures import Infinity
-__all__ = [
- "parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"
-]
+__all__ = ["parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"]
_Version = collections.namedtuple(
- "_Version",
- ["epoch", "release", "dev", "pre", "post", "local"],
+ "_Version", ["epoch", "release", "dev", "pre", "post", "local"]
)
@@ -40,7 +37,6 @@ class InvalidVersion(ValueError):
class _BaseVersion(object):
-
def __hash__(self):
return hash(self._key)
@@ -70,7 +66,6 @@ class _BaseVersion(object):
class LegacyVersion(_BaseVersion):
-
def __init__(self, version):
self._version = str(version)
self._key = _legacy_cmpkey(self._version)
@@ -89,6 +84,26 @@ class LegacyVersion(_BaseVersion):
def base_version(self):
return self._version
+ @property
+ def epoch(self):
+ return -1
+
+ @property
+ def release(self):
+ return None
+
+ @property
+ def pre(self):
+ return None
+
+ @property
+ def post(self):
+ return None
+
+ @property
+ def dev(self):
+ return None
+
@property
def local(self):
return None
@@ -101,13 +116,19 @@ class LegacyVersion(_BaseVersion):
def is_postrelease(self):
return False
+ @property
+ def is_devrelease(self):
+ return False
-_legacy_version_component_re = re.compile(
- r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE,
-)
+
+_legacy_version_component_re = re.compile(r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE)
_legacy_version_replacement_map = {
- "pre": "c", "preview": "c", "-": "final-", "rc": "c", "dev": "@",
+ "pre": "c",
+ "preview": "c",
+ "-": "final-",
+ "rc": "c",
+ "dev": "@",
}
@@ -154,6 +175,7 @@ def _legacy_cmpkey(version):
return epoch, parts
+
# Deliberately not anchored to the start and end of the string, to make it
# easier for 3rd party code to reuse
VERSION_PATTERN = r"""
@@ -190,10 +212,7 @@ VERSION_PATTERN = r"""
class Version(_BaseVersion):
- _regex = re.compile(
- r"^\s*" + VERSION_PATTERN + r"\s*$",
- re.VERBOSE | re.IGNORECASE,
- )
+ _regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE)
def __init__(self, version):
# Validate the version and parse it into pieces
@@ -205,18 +224,11 @@ class Version(_BaseVersion):
self._version = _Version(
epoch=int(match.group("epoch")) if match.group("epoch") else 0,
release=tuple(int(i) for i in match.group("release").split(".")),
- pre=_parse_letter_version(
- match.group("pre_l"),
- match.group("pre_n"),
- ),
+ pre=_parse_letter_version(match.group("pre_l"), match.group("pre_n")),
post=_parse_letter_version(
- match.group("post_l"),
- match.group("post_n1") or match.group("post_n2"),
- ),
- dev=_parse_letter_version(
- match.group("dev_l"),
- match.group("dev_n"),
+ match.group("post_l"), match.group("post_n1") or match.group("post_n2")
),
+ dev=_parse_letter_version(match.group("dev_l"), match.group("dev_n")),
local=_parse_local_version(match.group("local")),
)
@@ -237,32 +249,57 @@ class Version(_BaseVersion):
parts = []
# Epoch
- if self._version.epoch != 0:
- parts.append("{0}!".format(self._version.epoch))
+ if self.epoch != 0:
+ parts.append("{0}!".format(self.epoch))
# Release segment
- parts.append(".".join(str(x) for x in self._version.release))
+ parts.append(".".join(str(x) for x in self.release))
# Pre-release
- if self._version.pre is not None:
- parts.append("".join(str(x) for x in self._version.pre))
+ if self.pre is not None:
+ parts.append("".join(str(x) for x in self.pre))
# Post-release
- if self._version.post is not None:
- parts.append(".post{0}".format(self._version.post[1]))
+ if self.post is not None:
+ parts.append(".post{0}".format(self.post))
# Development release
- if self._version.dev is not None:
- parts.append(".dev{0}".format(self._version.dev[1]))
+ if self.dev is not None:
+ parts.append(".dev{0}".format(self.dev))
# Local version segment
- if self._version.local is not None:
- parts.append(
- "+{0}".format(".".join(str(x) for x in self._version.local))
- )
+ if self.local is not None:
+ parts.append("+{0}".format(self.local))
return "".join(parts)
+ @property
+ def epoch(self):
+ return self._version.epoch
+
+ @property
+ def release(self):
+ return self._version.release
+
+ @property
+ def pre(self):
+ return self._version.pre
+
+ @property
+ def post(self):
+ return self._version.post[1] if self._version.post else None
+
+ @property
+ def dev(self):
+ return self._version.dev[1] if self._version.dev else None
+
+ @property
+ def local(self):
+ if self._version.local:
+ return ".".join(str(x) for x in self._version.local)
+ else:
+ return None
+
@property
def public(self):
return str(self).split("+", 1)[0]
@@ -272,27 +309,25 @@ class Version(_BaseVersion):
parts = []
# Epoch
- if self._version.epoch != 0:
- parts.append("{0}!".format(self._version.epoch))
+ if self.epoch != 0:
+ parts.append("{0}!".format(self.epoch))
# Release segment
- parts.append(".".join(str(x) for x in self._version.release))
+ parts.append(".".join(str(x) for x in self.release))
return "".join(parts)
- @property
- def local(self):
- version_string = str(self)
- if "+" in version_string:
- return version_string.split("+", 1)[1]
-
@property
def is_prerelease(self):
- return bool(self._version.dev or self._version.pre)
+ return self.dev is not None or self.pre is not None
@property
def is_postrelease(self):
- return bool(self._version.post)
+ return self.post is not None
+
+ @property
+ def is_devrelease(self):
+ return self.dev is not None
def _parse_letter_version(letter, number):
@@ -326,7 +361,7 @@ def _parse_letter_version(letter, number):
return letter, int(number)
-_local_version_seperators = re.compile(r"[\._-]")
+_local_version_separators = re.compile(r"[\._-]")
def _parse_local_version(local):
@@ -336,7 +371,7 @@ def _parse_local_version(local):
if local is not None:
return tuple(
part.lower() if not part.isdigit() else int(part)
- for part in _local_version_seperators.split(local)
+ for part in _local_version_separators.split(local)
)
@@ -347,12 +382,7 @@ def _cmpkey(epoch, release, pre, post, dev, local):
# re-reverse it back into the correct order and make it a tuple and use
# that for our sorting key.
release = tuple(
- reversed(list(
- itertools.dropwhile(
- lambda x: x == 0,
- reversed(release),
- )
- ))
+ reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release))))
)
# We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
@@ -385,9 +415,6 @@ def _cmpkey(epoch, release, pre, post, dev, local):
# - Numeric segments sort numerically
# - Shorter versions sort before longer versions when the prefixes
# match exactly
- local = tuple(
- (i, "") if isinstance(i, int) else (-Infinity, i)
- for i in local
- )
+ local = tuple((i, "") if isinstance(i, int) else (-Infinity, i) for i in local)
return epoch, release, pre, post, dev, local
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/extern/__init__.py b/venv/lib/python3.8/site-packages/pkg_resources/extern/__init__.py
index c1eb9e9..bf98d8f 100644
--- a/venv/lib/python3.8/site-packages/pkg_resources/extern/__init__.py
+++ b/venv/lib/python3.8/site-packages/pkg_resources/extern/__init__.py
@@ -43,13 +43,6 @@ class VendorImporter:
__import__(extant)
mod = sys.modules[extant]
sys.modules[fullname] = mod
- # mysterious hack:
- # Remove the reference to the extant package/module
- # on later Python versions to cause relative imports
- # in the vendor package to resolve the same modules
- # as those going through this importer.
- if prefix and sys.version_info > (3, 3):
- del sys.modules[extant]
return mod
except ImportError:
pass
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/extern/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/pkg_resources/extern/__pycache__/__init__.cpython-38.pyc
index 2df720b..9cef2ea 100644
Binary files a/venv/lib/python3.8/site-packages/pkg_resources/extern/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/pkg_resources/extern/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/pkg_resources/py31compat.py b/venv/lib/python3.8/site-packages/pkg_resources/py31compat.py
deleted file mode 100644
index a381c42..0000000
--- a/venv/lib/python3.8/site-packages/pkg_resources/py31compat.py
+++ /dev/null
@@ -1,23 +0,0 @@
-import os
-import errno
-import sys
-
-from .extern import six
-
-
-def _makedirs_31(path, exist_ok=False):
- try:
- os.makedirs(path)
- except OSError as exc:
- if not exist_ok or exc.errno != errno.EEXIST:
- raise
-
-
-# rely on compatibility behavior until mode considerations
-# and exists_ok considerations are disentangled.
-# See https://github.com/pypa/setuptools/pull/1083#issuecomment-315168663
-needs_makedirs = (
- six.PY2 or
- (3, 4) <= sys.version_info < (3, 4, 1)
-)
-makedirs = _makedirs_31 if needs_makedirs else os.makedirs
diff --git a/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/INSTALLER b/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/LICENSE b/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/LICENSE
deleted file mode 100644
index 6e0693b..0000000
--- a/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/LICENSE
+++ /dev/null
@@ -1,19 +0,0 @@
-Copyright (C) 2016 Jason R Coombs
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal in
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --git a/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/METADATA b/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/METADATA
deleted file mode 100644
index 96f2587..0000000
--- a/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/METADATA
+++ /dev/null
@@ -1,77 +0,0 @@
-Metadata-Version: 2.1
-Name: setuptools
-Version: 41.2.0
-Summary: Easily download, build, install, upgrade, and uninstall Python packages
-Home-page: https://github.com/pypa/setuptools
-Author: Python Packaging Authority
-Author-email: distutils-sig@python.org
-License: UNKNOWN
-Project-URL: Documentation, https://setuptools.readthedocs.io/
-Keywords: CPAN PyPI distutils eggs package management
-Platform: UNKNOWN
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: MIT License
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python :: 2
-Classifier: Programming Language :: Python :: 2.7
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.4
-Classifier: Programming Language :: Python :: 3.5
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Classifier: Topic :: System :: Archiving :: Packaging
-Classifier: Topic :: System :: Systems Administration
-Classifier: Topic :: Utilities
-Requires-Python: >=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*
-Description-Content-Type: text/x-rst; charset=UTF-8
-Provides-Extra: certs
-Requires-Dist: certifi (==2016.9.26) ; extra == 'certs'
-Provides-Extra: ssl
-Requires-Dist: wincertstore (==0.2) ; (sys_platform == "win32") and extra == 'ssl'
-
-.. image:: https://img.shields.io/pypi/v/setuptools.svg
- :target: https://pypi.org/project/setuptools
-
-.. image:: https://img.shields.io/readthedocs/setuptools/latest.svg
- :target: https://setuptools.readthedocs.io
-
-.. image:: https://img.shields.io/travis/pypa/setuptools/master.svg?label=Linux%20CI&logo=travis&logoColor=white
- :target: https://travis-ci.org/pypa/setuptools
-
-.. image:: https://img.shields.io/appveyor/ci/pypa/setuptools/master.svg?label=Windows%20CI&logo=appveyor&logoColor=white
- :target: https://ci.appveyor.com/project/pypa/setuptools/branch/master
-
-.. image:: https://img.shields.io/codecov/c/github/pypa/setuptools/master.svg?logo=codecov&logoColor=white
- :target: https://codecov.io/gh/pypa/setuptools
-
-.. image:: https://tidelift.com/badges/github/pypa/setuptools?style=flat
- :target: https://tidelift.com/subscription/pkg/pypi-setuptools?utm_source=pypi-setuptools&utm_medium=readme
-
-.. image:: https://img.shields.io/pypi/pyversions/setuptools.svg
-
-See the `Installation Instructions
- `_ in the Python Packaging
-User's Guide for instructions on installing, upgrading, and uninstalling
-Setuptools.
-
-Questions and comments should be directed to the `distutils-sig
-mailing list `_.
-Bug reports and especially tested patches may be
-submitted directly to the `bug tracker
-`_.
-
-To report a security vulnerability, please use the
-`Tidelift security contact `_.
-Tidelift will coordinate the fix and disclosure.
-
-
-Code of Conduct
----------------
-
-Everyone interacting in the setuptools project's codebases, issue trackers,
-chat rooms, and mailing lists is expected to follow the
-`PyPA Code of Conduct `_.
-
-
diff --git a/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/RECORD b/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/RECORD
deleted file mode 100644
index d999f14..0000000
--- a/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/RECORD
+++ /dev/null
@@ -1,186 +0,0 @@
-../../../bin/easy_install,sha256=7L8MxSdJ8B5NVwhC8PdWc-NeaUmZjD7v3N2LndiAiik,259
-../../../bin/easy_install-3.8,sha256=7L8MxSdJ8B5NVwhC8PdWc-NeaUmZjD7v3N2LndiAiik,259
-__pycache__/easy_install.cpython-38.pyc,,
-easy_install.py,sha256=MDC9vt5AxDsXX5qcKlBz2TnW6Tpuv_AobnfhCJ9X3PM,126
-pkg_resources/__init__.py,sha256=6Kq6B-JSGEFSg_2FAnl6Lmoa5by2RyjDxPBiWuAh-dw,108309
-pkg_resources/__pycache__/__init__.cpython-38.pyc,,
-pkg_resources/__pycache__/py31compat.cpython-38.pyc,,
-pkg_resources/_vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-pkg_resources/_vendor/__pycache__/__init__.cpython-38.pyc,,
-pkg_resources/_vendor/__pycache__/appdirs.cpython-38.pyc,,
-pkg_resources/_vendor/__pycache__/pyparsing.cpython-38.pyc,,
-pkg_resources/_vendor/__pycache__/six.cpython-38.pyc,,
-pkg_resources/_vendor/appdirs.py,sha256=MievUEuv3l_mQISH5SF0shDk_BNhHHzYiAPrT3ITN4I,24701
-pkg_resources/_vendor/packaging/__about__.py,sha256=zkcCPTN_6TcLW0Nrlg0176-R1QQ_WVPTm8sz1R4-HjM,720
-pkg_resources/_vendor/packaging/__init__.py,sha256=_vNac5TrzwsrzbOFIbF-5cHqc_Y2aPT2D7zrIR06BOo,513
-pkg_resources/_vendor/packaging/__pycache__/__about__.cpython-38.pyc,,
-pkg_resources/_vendor/packaging/__pycache__/__init__.cpython-38.pyc,,
-pkg_resources/_vendor/packaging/__pycache__/_compat.cpython-38.pyc,,
-pkg_resources/_vendor/packaging/__pycache__/_structures.cpython-38.pyc,,
-pkg_resources/_vendor/packaging/__pycache__/markers.cpython-38.pyc,,
-pkg_resources/_vendor/packaging/__pycache__/requirements.cpython-38.pyc,,
-pkg_resources/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc,,
-pkg_resources/_vendor/packaging/__pycache__/utils.cpython-38.pyc,,
-pkg_resources/_vendor/packaging/__pycache__/version.cpython-38.pyc,,
-pkg_resources/_vendor/packaging/_compat.py,sha256=Vi_A0rAQeHbU-a9X0tt1yQm9RqkgQbDSxzRw8WlU9kA,860
-pkg_resources/_vendor/packaging/_structures.py,sha256=RImECJ4c_wTlaTYYwZYLHEiebDMaAJmK1oPARhw1T5o,1416
-pkg_resources/_vendor/packaging/markers.py,sha256=uEcBBtGvzqltgnArqb9c4RrcInXezDLos14zbBHhWJo,8248
-pkg_resources/_vendor/packaging/requirements.py,sha256=SikL2UynbsT0qtY9ltqngndha_sfo0w6XGFhAhoSoaQ,4355
-pkg_resources/_vendor/packaging/specifiers.py,sha256=SAMRerzO3fK2IkFZCaZkuwZaL_EGqHNOz4pni4vhnN0,28025
-pkg_resources/_vendor/packaging/utils.py,sha256=3m6WvPm6NNxE8rkTGmn0r75B_GZSGg7ikafxHsBN1WA,421
-pkg_resources/_vendor/packaging/version.py,sha256=OwGnxYfr2ghNzYx59qWIBkrK3SnB6n-Zfd1XaLpnnM0,11556
-pkg_resources/_vendor/pyparsing.py,sha256=tmrp-lu-qO1i75ZzIN5A12nKRRD1Cm4Vpk-5LR9rims,232055
-pkg_resources/_vendor/six.py,sha256=A6hdJZVjI3t_geebZ9BzUvwRrIXo0lfwzQlM2LcKyas,30098
-pkg_resources/extern/__init__.py,sha256=cHiEfHuLmm6rs5Ve_ztBfMI7Lr31vss-D4wkqF5xzlI,2498
-pkg_resources/extern/__pycache__/__init__.cpython-38.pyc,,
-pkg_resources/py31compat.py,sha256=-WQ0e4c3RG_acdhwC3gLiXhP_lg4G5q7XYkZkQg0gxU,558
-setuptools-41.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-setuptools-41.2.0.dist-info/LICENSE,sha256=wyo6w5WvYyHv0ovnPQagDw22q4h9HCHU_sRhKNIFbVo,1078
-setuptools-41.2.0.dist-info/METADATA,sha256=_t0DvK_bLLT2yjvvNOCXiSIoNJvjX6dTWT8fLNVrUQk,3305
-setuptools-41.2.0.dist-info/RECORD,,
-setuptools-41.2.0.dist-info/WHEEL,sha256=8zNYZbwQSXoB9IfXOjPfeNwvAsALAjffgk27FqvCWbo,110
-setuptools-41.2.0.dist-info/dependency_links.txt,sha256=HlkCFkoK5TbZ5EMLbLKYhLcY_E31kBWD8TqW2EgmatQ,239
-setuptools-41.2.0.dist-info/entry_points.txt,sha256=jBqCYDlVjl__sjYFGXo1JQGIMAYFJE-prYWUtnMZEew,2990
-setuptools-41.2.0.dist-info/top_level.txt,sha256=2HUXVVwA4Pff1xgTFr3GsTXXKaPaO6vlG6oNJ_4u4Tg,38
-setuptools-41.2.0.dist-info/zip-safe,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
-setuptools/__init__.py,sha256=WBpCcn2lvdckotabeae1TTYonPOcgCIF3raD2zRWzBc,7283
-setuptools/__pycache__/__init__.cpython-38.pyc,,
-setuptools/__pycache__/_deprecation_warning.cpython-38.pyc,,
-setuptools/__pycache__/archive_util.cpython-38.pyc,,
-setuptools/__pycache__/build_meta.cpython-38.pyc,,
-setuptools/__pycache__/config.cpython-38.pyc,,
-setuptools/__pycache__/dep_util.cpython-38.pyc,,
-setuptools/__pycache__/depends.cpython-38.pyc,,
-setuptools/__pycache__/dist.cpython-38.pyc,,
-setuptools/__pycache__/extension.cpython-38.pyc,,
-setuptools/__pycache__/glibc.cpython-38.pyc,,
-setuptools/__pycache__/glob.cpython-38.pyc,,
-setuptools/__pycache__/launch.cpython-38.pyc,,
-setuptools/__pycache__/lib2to3_ex.cpython-38.pyc,,
-setuptools/__pycache__/monkey.cpython-38.pyc,,
-setuptools/__pycache__/msvc.cpython-38.pyc,,
-setuptools/__pycache__/namespaces.cpython-38.pyc,,
-setuptools/__pycache__/package_index.cpython-38.pyc,,
-setuptools/__pycache__/pep425tags.cpython-38.pyc,,
-setuptools/__pycache__/py27compat.cpython-38.pyc,,
-setuptools/__pycache__/py31compat.cpython-38.pyc,,
-setuptools/__pycache__/py33compat.cpython-38.pyc,,
-setuptools/__pycache__/sandbox.cpython-38.pyc,,
-setuptools/__pycache__/site-patch.cpython-38.pyc,,
-setuptools/__pycache__/ssl_support.cpython-38.pyc,,
-setuptools/__pycache__/unicode_utils.cpython-38.pyc,,
-setuptools/__pycache__/version.cpython-38.pyc,,
-setuptools/__pycache__/wheel.cpython-38.pyc,,
-setuptools/__pycache__/windows_support.cpython-38.pyc,,
-setuptools/_deprecation_warning.py,sha256=jU9-dtfv6cKmtQJOXN8nP1mm7gONw5kKEtiPtbwnZyI,218
-setuptools/_vendor/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-setuptools/_vendor/__pycache__/__init__.cpython-38.pyc,,
-setuptools/_vendor/__pycache__/pyparsing.cpython-38.pyc,,
-setuptools/_vendor/__pycache__/six.cpython-38.pyc,,
-setuptools/_vendor/packaging/__about__.py,sha256=zkcCPTN_6TcLW0Nrlg0176-R1QQ_WVPTm8sz1R4-HjM,720
-setuptools/_vendor/packaging/__init__.py,sha256=_vNac5TrzwsrzbOFIbF-5cHqc_Y2aPT2D7zrIR06BOo,513
-setuptools/_vendor/packaging/__pycache__/__about__.cpython-38.pyc,,
-setuptools/_vendor/packaging/__pycache__/__init__.cpython-38.pyc,,
-setuptools/_vendor/packaging/__pycache__/_compat.cpython-38.pyc,,
-setuptools/_vendor/packaging/__pycache__/_structures.cpython-38.pyc,,
-setuptools/_vendor/packaging/__pycache__/markers.cpython-38.pyc,,
-setuptools/_vendor/packaging/__pycache__/requirements.cpython-38.pyc,,
-setuptools/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc,,
-setuptools/_vendor/packaging/__pycache__/utils.cpython-38.pyc,,
-setuptools/_vendor/packaging/__pycache__/version.cpython-38.pyc,,
-setuptools/_vendor/packaging/_compat.py,sha256=Vi_A0rAQeHbU-a9X0tt1yQm9RqkgQbDSxzRw8WlU9kA,860
-setuptools/_vendor/packaging/_structures.py,sha256=RImECJ4c_wTlaTYYwZYLHEiebDMaAJmK1oPARhw1T5o,1416
-setuptools/_vendor/packaging/markers.py,sha256=Gvpk9EY20yKaMTiKgQZ8yFEEpodqVgVYtfekoic1Yts,8239
-setuptools/_vendor/packaging/requirements.py,sha256=t44M2HVWtr8phIz2OhnILzuGT3rTATaovctV1dpnVIg,4343
-setuptools/_vendor/packaging/specifiers.py,sha256=SAMRerzO3fK2IkFZCaZkuwZaL_EGqHNOz4pni4vhnN0,28025
-setuptools/_vendor/packaging/utils.py,sha256=3m6WvPm6NNxE8rkTGmn0r75B_GZSGg7ikafxHsBN1WA,421
-setuptools/_vendor/packaging/version.py,sha256=OwGnxYfr2ghNzYx59qWIBkrK3SnB6n-Zfd1XaLpnnM0,11556
-setuptools/_vendor/pyparsing.py,sha256=tmrp-lu-qO1i75ZzIN5A12nKRRD1Cm4Vpk-5LR9rims,232055
-setuptools/_vendor/six.py,sha256=A6hdJZVjI3t_geebZ9BzUvwRrIXo0lfwzQlM2LcKyas,30098
-setuptools/archive_util.py,sha256=kw8Ib_lKjCcnPKNbS7h8HztRVK0d5RacU3r_KRdVnmM,6592
-setuptools/build_meta.py,sha256=-9Nmj9YdbW4zX3TssPJZhsENrTa4fw3k86Jm1cdKMik,9597
-setuptools/cli-32.exe,sha256=dfEuovMNnA2HLa3jRfMPVi5tk4R7alCbpTvuxtCyw0Y,65536
-setuptools/cli-64.exe,sha256=KLABu5pyrnokJCv6skjXZ6GsXeyYHGcqOUT3oHI3Xpo,74752
-setuptools/cli.exe,sha256=dfEuovMNnA2HLa3jRfMPVi5tk4R7alCbpTvuxtCyw0Y,65536
-setuptools/command/__init__.py,sha256=NWzJ0A1BEengZpVeqUyWLNm2bk4P3F4iL5QUErHy7kA,594
-setuptools/command/__pycache__/__init__.cpython-38.pyc,,
-setuptools/command/__pycache__/alias.cpython-38.pyc,,
-setuptools/command/__pycache__/bdist_egg.cpython-38.pyc,,
-setuptools/command/__pycache__/bdist_rpm.cpython-38.pyc,,
-setuptools/command/__pycache__/bdist_wininst.cpython-38.pyc,,
-setuptools/command/__pycache__/build_clib.cpython-38.pyc,,
-setuptools/command/__pycache__/build_ext.cpython-38.pyc,,
-setuptools/command/__pycache__/build_py.cpython-38.pyc,,
-setuptools/command/__pycache__/develop.cpython-38.pyc,,
-setuptools/command/__pycache__/dist_info.cpython-38.pyc,,
-setuptools/command/__pycache__/easy_install.cpython-38.pyc,,
-setuptools/command/__pycache__/egg_info.cpython-38.pyc,,
-setuptools/command/__pycache__/install.cpython-38.pyc,,
-setuptools/command/__pycache__/install_egg_info.cpython-38.pyc,,
-setuptools/command/__pycache__/install_lib.cpython-38.pyc,,
-setuptools/command/__pycache__/install_scripts.cpython-38.pyc,,
-setuptools/command/__pycache__/py36compat.cpython-38.pyc,,
-setuptools/command/__pycache__/register.cpython-38.pyc,,
-setuptools/command/__pycache__/rotate.cpython-38.pyc,,
-setuptools/command/__pycache__/saveopts.cpython-38.pyc,,
-setuptools/command/__pycache__/sdist.cpython-38.pyc,,
-setuptools/command/__pycache__/setopt.cpython-38.pyc,,
-setuptools/command/__pycache__/test.cpython-38.pyc,,
-setuptools/command/__pycache__/upload.cpython-38.pyc,,
-setuptools/command/__pycache__/upload_docs.cpython-38.pyc,,
-setuptools/command/alias.py,sha256=KjpE0sz_SDIHv3fpZcIQK-sCkJz-SrC6Gmug6b9Nkc8,2426
-setuptools/command/bdist_egg.py,sha256=be-IBpr1zhS9i6GjKANJgzkbH3ChImdWY7S-j0r2BK8,18167
-setuptools/command/bdist_rpm.py,sha256=B7l0TnzCGb-0nLlm6rS00jWLkojASwVmdhW2w5Qz_Ak,1508
-setuptools/command/bdist_wininst.py,sha256=_6dz3lpB1tY200LxKPLM7qgwTCceOMgaWFF-jW2-pm0,637
-setuptools/command/build_clib.py,sha256=bQ9aBr-5ZSO-9fGsGsDLz0mnnFteHUZnftVLkhvHDq0,4484
-setuptools/command/build_ext.py,sha256=Ib42YUGksBswm2mL5xmQPF6NeTA6HcqrvAtEgFCv32A,13019
-setuptools/command/build_py.py,sha256=yWyYaaS9F3o9JbIczn064A5g1C5_UiKRDxGaTqYbtLE,9596
-setuptools/command/develop.py,sha256=MQlnGS6uP19erK2JCNOyQYoYyquk3PADrqrrinqqLtA,8184
-setuptools/command/dist_info.py,sha256=5t6kOfrdgALT-P3ogss6PF9k-Leyesueycuk3dUyZnI,960
-setuptools/command/easy_install.py,sha256=telww7CuPsoTtvlpY-ktnZGT85cZ6xGCGZa0vHvFJ-Q,87273
-setuptools/command/egg_info.py,sha256=w73EdxYSOk2gsaAiHGL2dZrCldoPiuRr2eTfqcFvCds,25570
-setuptools/command/install.py,sha256=a0EZpL_A866KEdhicTGbuyD_TYl1sykfzdrri-zazT4,4683
-setuptools/command/install_egg_info.py,sha256=bMgeIeRiXzQ4DAGPV1328kcjwQjHjOWU4FngAWLV78Q,2203
-setuptools/command/install_lib.py,sha256=r5NuasaSxvmIrjgZNj38Iq-1UJG1o1ms7CuHq6MCTbQ,3862
-setuptools/command/install_scripts.py,sha256=UD0rEZ6861mTYhIdzcsqKnUl8PozocXWl9VBQ1VTWnc,2439
-setuptools/command/launcher manifest.xml,sha256=xlLbjWrB01tKC0-hlVkOKkiSPbzMml2eOPtJ_ucCnbE,628
-setuptools/command/py36compat.py,sha256=SzjZcOxF7zdFUT47Zv2n7AM3H8koDys_0OpS-n9gIfc,4986
-setuptools/command/register.py,sha256=LO3MvYKPE8dN1m-KkrBRHC68ZFoPvA_vI8Xgp7vv6zI,534
-setuptools/command/rotate.py,sha256=co5C1EkI7P0GGT6Tqz-T2SIj2LBJTZXYELpmao6d4KQ,2164
-setuptools/command/saveopts.py,sha256=za7QCBcQimKKriWcoCcbhxPjUz30gSB74zuTL47xpP4,658
-setuptools/command/sdist.py,sha256=gr5hFrDzUtGfp_0tu0sllzIyr3jMQegIkFmlDauQJxw,7388
-setuptools/command/setopt.py,sha256=NTWDyx-gjDF-txf4dO577s7LOzHVoKR0Mq33rFxaRr8,5085
-setuptools/command/test.py,sha256=oePJ49u17ENKtrM-rOrrLlRhtNnrzcSr0IW-gE9XVq0,9285
-setuptools/command/upload.py,sha256=GxtNkIl7SA0r8mACkbDcSCN1m2_WPppK9gZXJmQSiow,6811
-setuptools/command/upload_docs.py,sha256=oXiGplM_cUKLwE4CWWw98RzCufAu8tBhMC97GegFcms,7311
-setuptools/config.py,sha256=lz19l1AtoHctpp1_tbYZv176nrEj4Gpf7ykNIYTIkAQ,20425
-setuptools/dep_util.py,sha256=fgixvC1R7sH3r13ktyf7N0FALoqEXL1cBarmNpSEoWg,935
-setuptools/depends.py,sha256=hC8QIDcM3VDpRXvRVA6OfL9AaQfxvhxHcN_w6sAyNq8,5837
-setuptools/dist.py,sha256=MRrBrgBFEwzUvrJrIgW79IepDuAeRxetGuSPky-MawQ,50248
-setuptools/extension.py,sha256=uc6nHI-MxwmNCNPbUiBnybSyqhpJqjbhvOQ-emdvt_E,1729
-setuptools/extern/__init__.py,sha256=TxeNKFMSfBMzBpBDiHx8Dh3RzsdVmvWaXhtZ03DZMs0,2499
-setuptools/extern/__pycache__/__init__.cpython-38.pyc,,
-setuptools/glibc.py,sha256=X64VvGPL2AbURKwYRsWJOXXGAYOiF_v2qixeTkAULuU,3146
-setuptools/glob.py,sha256=o75cHrOxYsvn854thSxE0x9k8JrKDuhP_rRXlVB00Q4,5084
-setuptools/gui-32.exe,sha256=XBr0bHMA6Hpz2s9s9Bzjl-PwXfa9nH4ie0rFn4V2kWA,65536
-setuptools/gui-64.exe,sha256=aYKMhX1IJLn4ULHgWX0sE0yREUt6B3TEHf_jOw6yNyE,75264
-setuptools/gui.exe,sha256=XBr0bHMA6Hpz2s9s9Bzjl-PwXfa9nH4ie0rFn4V2kWA,65536
-setuptools/launch.py,sha256=sd7ejwhBocCDx_wG9rIs0OaZ8HtmmFU8ZC6IR_S0Lvg,787
-setuptools/lib2to3_ex.py,sha256=t5e12hbR2pi9V4ezWDTB4JM-AISUnGOkmcnYHek3xjg,2013
-setuptools/monkey.py,sha256=FGc9fffh7gAxMLFmJs2DW_OYWpBjkdbNS2n14UAK4NA,5264
-setuptools/msvc.py,sha256=uuRFaZzjJt5Fv3ZmyKUUuLtjx12_8G9RILigGec4irI,40838
-setuptools/namespaces.py,sha256=F0Nrbv8KCT2OrO7rwa03om4N4GZKAlnce-rr-cgDQa8,3199
-setuptools/package_index.py,sha256=F9LBC-hQ5fkjeEVflxif0mo_DzRMrepahdFTPenOtGM,40587
-setuptools/pep425tags.py,sha256=o_D_WVeWcXZiI2xjPSg7pouGOvaWRgGRxEDK9DzAXIA,10861
-setuptools/py27compat.py,sha256=3mwxRMDk5Q5O1rSXOERbQDXhFqwDJhhUitfMW_qpUCo,536
-setuptools/py31compat.py,sha256=h2rtZghOfwoGYd8sQ0-auaKiF3TcL3qX0bX3VessqcE,838
-setuptools/py33compat.py,sha256=SMF9Z8wnGicTOkU1uRNwZ_kz5Z_bj29PUBbqdqeeNsc,1330
-setuptools/sandbox.py,sha256=9UbwfEL5QY436oMI1LtFWohhoZ-UzwHvGyZjUH_qhkw,14276
-setuptools/script (dev).tmpl,sha256=RUzQzCQUaXtwdLtYHWYbIQmOaES5Brqq1FvUA_tu-5I,218
-setuptools/script.tmpl,sha256=WGTt5piezO27c-Dbx6l5Q4T3Ff20A5z7872hv3aAhYY,138
-setuptools/site-patch.py,sha256=OumkIHMuoSenRSW1382kKWI1VAwxNE86E5W8iDd34FY,2302
-setuptools/ssl_support.py,sha256=nLjPUBBw7RTTx6O4RJZ5eAMGgjJG8beiDbkFXDZpLuM,8493
-setuptools/unicode_utils.py,sha256=NOiZ_5hD72A6w-4wVj8awHFM3n51Kmw1Ic_vx15XFqw,996
-setuptools/version.py,sha256=og_cuZQb0QI6ukKZFfZWPlr1HgJBPPn2vO2m_bI9ZTE,144
-setuptools/wheel.py,sha256=94uqXsOaKt91d9hW5z6ZppZmNSs_nO66R4uiwhcr4V0,8094
-setuptools/windows_support.py,sha256=5GrfqSP2-dLGJoZTq2g6dCKkyQxxa2n5IQiXlJCoYEE,714
diff --git a/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/WHEEL b/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/WHEEL
deleted file mode 100644
index 8b701e9..0000000
--- a/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/WHEEL
+++ /dev/null
@@ -1,6 +0,0 @@
-Wheel-Version: 1.0
-Generator: bdist_wheel (0.33.6)
-Root-Is-Purelib: true
-Tag: py2-none-any
-Tag: py3-none-any
-
diff --git a/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/dependency_links.txt b/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/dependency_links.txt
deleted file mode 100644
index e87d021..0000000
--- a/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/dependency_links.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-https://files.pythonhosted.org/packages/source/c/certifi/certifi-2016.9.26.tar.gz#md5=baa81e951a29958563689d868ef1064d
-https://files.pythonhosted.org/packages/source/w/wincertstore/wincertstore-0.2.zip#md5=ae728f2f007185648d0c7a8679b361e2
diff --git a/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/entry_points.txt b/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/entry_points.txt
deleted file mode 100644
index 4159fd0..0000000
--- a/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/entry_points.txt
+++ /dev/null
@@ -1,65 +0,0 @@
-[console_scripts]
-easy_install = setuptools.command.easy_install:main
-easy_install-3.6 = setuptools.command.easy_install:main
-
-[distutils.commands]
-alias = setuptools.command.alias:alias
-bdist_egg = setuptools.command.bdist_egg:bdist_egg
-bdist_rpm = setuptools.command.bdist_rpm:bdist_rpm
-bdist_wininst = setuptools.command.bdist_wininst:bdist_wininst
-build_clib = setuptools.command.build_clib:build_clib
-build_ext = setuptools.command.build_ext:build_ext
-build_py = setuptools.command.build_py:build_py
-develop = setuptools.command.develop:develop
-dist_info = setuptools.command.dist_info:dist_info
-easy_install = setuptools.command.easy_install:easy_install
-egg_info = setuptools.command.egg_info:egg_info
-install = setuptools.command.install:install
-install_egg_info = setuptools.command.install_egg_info:install_egg_info
-install_lib = setuptools.command.install_lib:install_lib
-install_scripts = setuptools.command.install_scripts:install_scripts
-register = setuptools.command.register:register
-rotate = setuptools.command.rotate:rotate
-saveopts = setuptools.command.saveopts:saveopts
-sdist = setuptools.command.sdist:sdist
-setopt = setuptools.command.setopt:setopt
-test = setuptools.command.test:test
-upload = setuptools.command.upload:upload
-upload_docs = setuptools.command.upload_docs:upload_docs
-
-[distutils.setup_keywords]
-convert_2to3_doctests = setuptools.dist:assert_string_list
-dependency_links = setuptools.dist:assert_string_list
-eager_resources = setuptools.dist:assert_string_list
-entry_points = setuptools.dist:check_entry_points
-exclude_package_data = setuptools.dist:check_package_data
-extras_require = setuptools.dist:check_extras
-include_package_data = setuptools.dist:assert_bool
-install_requires = setuptools.dist:check_requirements
-namespace_packages = setuptools.dist:check_nsp
-package_data = setuptools.dist:check_package_data
-packages = setuptools.dist:check_packages
-python_requires = setuptools.dist:check_specifier
-setup_requires = setuptools.dist:check_requirements
-test_loader = setuptools.dist:check_importable
-test_runner = setuptools.dist:check_importable
-test_suite = setuptools.dist:check_test_suite
-tests_require = setuptools.dist:check_requirements
-use_2to3 = setuptools.dist:assert_bool
-use_2to3_exclude_fixers = setuptools.dist:assert_string_list
-use_2to3_fixers = setuptools.dist:assert_string_list
-zip_safe = setuptools.dist:assert_bool
-
-[egg_info.writers]
-PKG-INFO = setuptools.command.egg_info:write_pkg_info
-dependency_links.txt = setuptools.command.egg_info:overwrite_arg
-depends.txt = setuptools.command.egg_info:warn_depends_obsolete
-eager_resources.txt = setuptools.command.egg_info:overwrite_arg
-entry_points.txt = setuptools.command.egg_info:write_entries
-namespace_packages.txt = setuptools.command.egg_info:overwrite_arg
-requires.txt = setuptools.command.egg_info:write_requirements
-top_level.txt = setuptools.command.egg_info:write_toplevel_names
-
-[setuptools.installation]
-eggsecutable = setuptools.command.easy_install:bootstrap
-
diff --git a/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/top_level.txt b/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/top_level.txt
deleted file mode 100644
index 4577c6a..0000000
--- a/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/top_level.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-easy_install
-pkg_resources
-setuptools
diff --git a/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/zip-safe b/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/zip-safe
deleted file mode 100644
index 8b13789..0000000
--- a/venv/lib/python3.8/site-packages/setuptools-41.2.0.dist-info/zip-safe
+++ /dev/null
@@ -1 +0,0 @@
-
diff --git a/venv/lib/python3.8/site-packages/setuptools/__init__.py b/venv/lib/python3.8/site-packages/setuptools/__init__.py
index a71b2bb..8388251 100644
--- a/venv/lib/python3.8/site-packages/setuptools/__init__.py
+++ b/venv/lib/python3.8/site-packages/setuptools/__init__.py
@@ -1,8 +1,11 @@
"""Extensions to the 'distutils' for large or complex distributions"""
import os
-import sys
import functools
+
+# Disabled for now due to: #2228, #2230
+import setuptools.distutils_patch # noqa: F401
+
import distutils.core
import distutils.filelist
import re
@@ -17,7 +20,7 @@ from setuptools.extern.six.moves import filter, map
import setuptools.version
from setuptools.extension import Extension
-from setuptools.dist import Distribution, Feature
+from setuptools.dist import Distribution
from setuptools.depends import Require
from . import monkey
@@ -25,13 +28,13 @@ __metaclass__ = type
__all__ = [
- 'setup', 'Distribution', 'Feature', 'Command', 'Extension', 'Require',
+ 'setup', 'Distribution', 'Command', 'Extension', 'Require',
'SetuptoolsDeprecationWarning',
'find_packages'
]
if PY3:
- __all__.append('find_namespace_packages')
+ __all__.append('find_namespace_packages')
__version__ = setuptools.version.__version__
@@ -123,16 +126,33 @@ class PEP420PackageFinder(PackageFinder):
find_packages = PackageFinder.find
if PY3:
- find_namespace_packages = PEP420PackageFinder.find
+ find_namespace_packages = PEP420PackageFinder.find
def _install_setup_requires(attrs):
# Note: do not use `setuptools.Distribution` directly, as
# our PEP 517 backend patch `distutils.core.Distribution`.
- dist = distutils.core.Distribution(dict(
- (k, v) for k, v in attrs.items()
- if k in ('dependency_links', 'setup_requires')
- ))
+ class MinimalDistribution(distutils.core.Distribution):
+ """
+ A minimal version of a distribution for supporting the
+ fetch_build_eggs interface.
+ """
+ def __init__(self, attrs):
+ _incl = 'dependency_links', 'setup_requires'
+ filtered = {
+ k: attrs[k]
+ for k in set(_incl) & set(attrs)
+ }
+ distutils.core.Distribution.__init__(self, filtered)
+
+ def finalize_options(self):
+ """
+ Disable finalize_options to avoid building the working set.
+ Ref #2158.
+ """
+
+ dist = MinimalDistribution(attrs)
+
# Honor setup.cfg's options.
dist.parse_config_files(ignore_option_errors=True)
if dist.setup_requires:
@@ -144,6 +164,7 @@ def setup(**attrs):
_install_setup_requires(attrs)
return distutils.core.setup(**attrs)
+
setup.__doc__ = distutils.core.setup.__doc__
@@ -191,8 +212,8 @@ class Command(_Command):
ok = False
if not ok:
raise DistutilsOptionError(
- "'%s' must be a list of strings (got %r)"
- % (option, val))
+ "'%s' must be a list of strings (got %r)"
+ % (option, val))
def reinitialize_command(self, command, reinit_subcommands=0, **kw):
cmd = _Command.reinitialize_command(self, command, reinit_subcommands)
@@ -224,5 +245,9 @@ def findall(dir=os.curdir):
return list(files)
+class sic(str):
+ """Treat this string as-is (https://en.wikipedia.org/wiki/Sic)"""
+
+
# Apply monkey patches
monkey.patch_all()
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/__init__.cpython-38.pyc
index e85cfd3..1b21c90 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/_deprecation_warning.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/_deprecation_warning.cpython-38.pyc
index 68f1138..f8f22d8 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/_deprecation_warning.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/_deprecation_warning.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/archive_util.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/archive_util.cpython-38.pyc
index dd06cdb..07ebec9 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/archive_util.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/archive_util.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/build_meta.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/build_meta.cpython-38.pyc
index ff29053..2a97c5d 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/build_meta.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/build_meta.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/config.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/config.cpython-38.pyc
index 3c62572..96de966 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/config.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/config.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/dep_util.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/dep_util.cpython-38.pyc
index e4a929c..1ffeb2e 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/dep_util.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/dep_util.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/depends.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/depends.cpython-38.pyc
index 0e3806c..d6c2269 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/depends.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/depends.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/dist.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/dist.cpython-38.pyc
index 851c886..dbcb00d 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/dist.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/dist.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/extension.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/extension.cpython-38.pyc
index bba2971..adab1a8 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/extension.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/extension.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/glibc.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/glibc.cpython-38.pyc
deleted file mode 100644
index 2f90a44..0000000
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/glibc.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/glob.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/glob.cpython-38.pyc
index 44c5ea3..e325f30 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/glob.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/glob.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/launch.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/launch.cpython-38.pyc
index 2f69f37..a374dae 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/launch.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/launch.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/lib2to3_ex.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/lib2to3_ex.cpython-38.pyc
index 7f7ca19..73533e8 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/lib2to3_ex.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/lib2to3_ex.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/monkey.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/monkey.cpython-38.pyc
index 4278194..3ad1c9e 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/monkey.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/monkey.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/msvc.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/msvc.cpython-38.pyc
index 597e93e..4e563ec 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/msvc.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/msvc.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/namespaces.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/namespaces.cpython-38.pyc
index 4c7cbcb..2a5eb30 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/namespaces.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/namespaces.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/package_index.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/package_index.cpython-38.pyc
index c86d913..e9e4edb 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/package_index.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/package_index.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/pep425tags.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/pep425tags.cpython-38.pyc
deleted file mode 100644
index 0b96584..0000000
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/pep425tags.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/py27compat.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/py27compat.cpython-38.pyc
index 5dd1478..5ae3bdf 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/py27compat.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/py27compat.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/py31compat.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/py31compat.cpython-38.pyc
index 319d93c..85322db 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/py31compat.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/py31compat.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/py33compat.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/py33compat.cpython-38.pyc
index ae02e61..c42f722 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/py33compat.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/py33compat.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/sandbox.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/sandbox.cpython-38.pyc
index 11cb980..4121463 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/sandbox.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/sandbox.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/site-patch.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/site-patch.cpython-38.pyc
deleted file mode 100644
index ca75805..0000000
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/site-patch.cpython-38.pyc and /dev/null differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/ssl_support.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/ssl_support.cpython-38.pyc
index f41d1ce..e74eeee 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/ssl_support.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/ssl_support.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/unicode_utils.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/unicode_utils.cpython-38.pyc
index c54a296..4c4d2dd 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/unicode_utils.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/unicode_utils.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/version.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/version.cpython-38.pyc
index c08a1a1..2b8eb38 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/version.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/version.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/wheel.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/wheel.cpython-38.pyc
index 4d963e1..433be1c 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/wheel.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/wheel.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/__pycache__/windows_support.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/__pycache__/windows_support.cpython-38.pyc
index da477ec..78c3c93 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/__pycache__/windows_support.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/__pycache__/windows_support.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/_vendor/__pycache__/__init__.cpython-38.pyc
index 53f28fc..34ab5f7 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/_vendor/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/_vendor/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/__pycache__/pyparsing.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/_vendor/__pycache__/pyparsing.cpython-38.pyc
index 4c71bb6..ce8b493 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/_vendor/__pycache__/pyparsing.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/_vendor/__pycache__/pyparsing.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/__pycache__/six.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/_vendor/__pycache__/six.cpython-38.pyc
index d72d8b1..8763300 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/_vendor/__pycache__/six.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/_vendor/__pycache__/six.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__about__.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__about__.py
index 95d330e..dc95138 100644
--- a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__about__.py
+++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__about__.py
@@ -4,18 +4,24 @@
from __future__ import absolute_import, division, print_function
__all__ = [
- "__title__", "__summary__", "__uri__", "__version__", "__author__",
- "__email__", "__license__", "__copyright__",
+ "__title__",
+ "__summary__",
+ "__uri__",
+ "__version__",
+ "__author__",
+ "__email__",
+ "__license__",
+ "__copyright__",
]
__title__ = "packaging"
__summary__ = "Core utilities for Python packages"
__uri__ = "https://github.com/pypa/packaging"
-__version__ = "16.8"
+__version__ = "19.2"
__author__ = "Donald Stufft and individual contributors"
__email__ = "donald@stufft.io"
__license__ = "BSD or Apache License, Version 2.0"
-__copyright__ = "Copyright 2014-2016 %s" % __author__
+__copyright__ = "Copyright 2014-2019 %s" % __author__
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__init__.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__init__.py
index 5ee6220..a0cf67d 100644
--- a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__init__.py
+++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__init__.py
@@ -4,11 +4,23 @@
from __future__ import absolute_import, division, print_function
from .__about__ import (
- __author__, __copyright__, __email__, __license__, __summary__, __title__,
- __uri__, __version__
+ __author__,
+ __copyright__,
+ __email__,
+ __license__,
+ __summary__,
+ __title__,
+ __uri__,
+ __version__,
)
__all__ = [
- "__title__", "__summary__", "__uri__", "__version__", "__author__",
- "__email__", "__license__", "__copyright__",
+ "__title__",
+ "__summary__",
+ "__uri__",
+ "__version__",
+ "__author__",
+ "__email__",
+ "__license__",
+ "__copyright__",
]
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/__about__.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/__about__.cpython-38.pyc
index e53dba1..0939843 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/__about__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/__about__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/__init__.cpython-38.pyc
index 24d9583..79cd6df 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/_compat.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/_compat.cpython-38.pyc
index 4158f76..948a5ac 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/_compat.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/_compat.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/_structures.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/_structures.cpython-38.pyc
index 7da372c..1f90f67 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/_structures.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/_structures.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/markers.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/markers.cpython-38.pyc
index c584305..2140f86 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/markers.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/markers.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/requirements.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/requirements.cpython-38.pyc
index 2aef246..5de0a90 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/requirements.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/requirements.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc
index 1f0bac0..b252aad 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/specifiers.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/utils.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/utils.cpython-38.pyc
index 3013c2b..807db05 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/utils.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/utils.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/version.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/version.cpython-38.pyc
index 94b724b..b0c9700 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/version.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/__pycache__/version.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_compat.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_compat.py
index 210bb80..25da473 100644
--- a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_compat.py
+++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_compat.py
@@ -12,9 +12,9 @@ PY3 = sys.version_info[0] == 3
# flake8: noqa
if PY3:
- string_types = str,
+ string_types = (str,)
else:
- string_types = basestring,
+ string_types = (basestring,)
def with_metaclass(meta, *bases):
@@ -27,4 +27,5 @@ def with_metaclass(meta, *bases):
class metaclass(meta):
def __new__(cls, name, this_bases, d):
return meta(name, bases, d)
- return type.__new__(metaclass, 'temporary_class', (), {})
+
+ return type.__new__(metaclass, "temporary_class", (), {})
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_structures.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_structures.py
index ccc2786..68dcca6 100644
--- a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_structures.py
+++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/_structures.py
@@ -5,7 +5,6 @@ from __future__ import absolute_import, division, print_function
class Infinity(object):
-
def __repr__(self):
return "Infinity"
@@ -33,11 +32,11 @@ class Infinity(object):
def __neg__(self):
return NegativeInfinity
+
Infinity = Infinity()
class NegativeInfinity(object):
-
def __repr__(self):
return "-Infinity"
@@ -65,4 +64,5 @@ class NegativeInfinity(object):
def __neg__(self):
return Infinity
+
NegativeInfinity = NegativeInfinity()
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/markers.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/markers.py
index 031332a..4bdfdb2 100644
--- a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/markers.py
+++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/markers.py
@@ -17,8 +17,11 @@ from .specifiers import Specifier, InvalidSpecifier
__all__ = [
- "InvalidMarker", "UndefinedComparison", "UndefinedEnvironmentName",
- "Marker", "default_environment",
+ "InvalidMarker",
+ "UndefinedComparison",
+ "UndefinedEnvironmentName",
+ "Marker",
+ "default_environment",
]
@@ -42,7 +45,6 @@ class UndefinedEnvironmentName(ValueError):
class Node(object):
-
def __init__(self, value):
self.value = value
@@ -57,62 +59,52 @@ class Node(object):
class Variable(Node):
-
def serialize(self):
return str(self)
class Value(Node):
-
def serialize(self):
return '"{0}"'.format(self)
class Op(Node):
-
def serialize(self):
return str(self)
VARIABLE = (
- L("implementation_version") |
- L("platform_python_implementation") |
- L("implementation_name") |
- L("python_full_version") |
- L("platform_release") |
- L("platform_version") |
- L("platform_machine") |
- L("platform_system") |
- L("python_version") |
- L("sys_platform") |
- L("os_name") |
- L("os.name") | # PEP-345
- L("sys.platform") | # PEP-345
- L("platform.version") | # PEP-345
- L("platform.machine") | # PEP-345
- L("platform.python_implementation") | # PEP-345
- L("python_implementation") | # undocumented setuptools legacy
- L("extra")
+ L("implementation_version")
+ | L("platform_python_implementation")
+ | L("implementation_name")
+ | L("python_full_version")
+ | L("platform_release")
+ | L("platform_version")
+ | L("platform_machine")
+ | L("platform_system")
+ | L("python_version")
+ | L("sys_platform")
+ | L("os_name")
+ | L("os.name")
+ | L("sys.platform") # PEP-345
+ | L("platform.version") # PEP-345
+ | L("platform.machine") # PEP-345
+ | L("platform.python_implementation") # PEP-345
+ | L("python_implementation") # PEP-345
+ | L("extra") # undocumented setuptools legacy
)
ALIASES = {
- 'os.name': 'os_name',
- 'sys.platform': 'sys_platform',
- 'platform.version': 'platform_version',
- 'platform.machine': 'platform_machine',
- 'platform.python_implementation': 'platform_python_implementation',
- 'python_implementation': 'platform_python_implementation'
+ "os.name": "os_name",
+ "sys.platform": "sys_platform",
+ "platform.version": "platform_version",
+ "platform.machine": "platform_machine",
+ "platform.python_implementation": "platform_python_implementation",
+ "python_implementation": "platform_python_implementation",
}
VARIABLE.setParseAction(lambda s, l, t: Variable(ALIASES.get(t[0], t[0])))
VERSION_CMP = (
- L("===") |
- L("==") |
- L(">=") |
- L("<=") |
- L("!=") |
- L("~=") |
- L(">") |
- L("<")
+ L("===") | L("==") | L(">=") | L("<=") | L("!=") | L("~=") | L(">") | L("<")
)
MARKER_OP = VERSION_CMP | L("not in") | L("in")
@@ -152,8 +144,11 @@ def _format_marker(marker, first=True):
# where the single item is itself it's own list. In that case we want skip
# the rest of this function so that we don't get extraneous () on the
# outside.
- if (isinstance(marker, list) and len(marker) == 1 and
- isinstance(marker[0], (list, tuple))):
+ if (
+ isinstance(marker, list)
+ and len(marker) == 1
+ and isinstance(marker[0], (list, tuple))
+ ):
return _format_marker(marker[0])
if isinstance(marker, list):
@@ -239,20 +234,20 @@ def _evaluate_markers(markers, environment):
def format_full_version(info):
- version = '{0.major}.{0.minor}.{0.micro}'.format(info)
+ version = "{0.major}.{0.minor}.{0.micro}".format(info)
kind = info.releaselevel
- if kind != 'final':
+ if kind != "final":
version += kind[0] + str(info.serial)
return version
def default_environment():
- if hasattr(sys, 'implementation'):
+ if hasattr(sys, "implementation"):
iver = format_full_version(sys.implementation.version)
implementation_name = sys.implementation.name
else:
- iver = '0'
- implementation_name = ''
+ iver = "0"
+ implementation_name = ""
return {
"implementation_name": implementation_name,
@@ -264,19 +259,19 @@ def default_environment():
"platform_version": platform.version(),
"python_full_version": platform.python_version(),
"platform_python_implementation": platform.python_implementation(),
- "python_version": platform.python_version()[:3],
+ "python_version": ".".join(platform.python_version_tuple()[:2]),
"sys_platform": sys.platform,
}
class Marker(object):
-
def __init__(self, marker):
try:
self._markers = _coerce_parse_result(MARKER.parseString(marker))
except ParseException as e:
err_str = "Invalid marker: {0!r}, parse error at {1!r}".format(
- marker, marker[e.loc:e.loc + 8])
+ marker, marker[e.loc : e.loc + 8]
+ )
raise InvalidMarker(err_str)
def __str__(self):
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/requirements.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/requirements.py
index 5b49341..8a0c2cb 100644
--- a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/requirements.py
+++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/requirements.py
@@ -38,8 +38,8 @@ IDENTIFIER = Combine(ALPHANUM + ZeroOrMore(IDENTIFIER_END))
NAME = IDENTIFIER("name")
EXTRA = IDENTIFIER
-URI = Regex(r'[^ ]+')("url")
-URL = (AT + URI)
+URI = Regex(r"[^ ]+")("url")
+URL = AT + URI
EXTRAS_LIST = EXTRA + ZeroOrMore(COMMA + EXTRA)
EXTRAS = (LBRACKET + Optional(EXTRAS_LIST) + RBRACKET)("extras")
@@ -48,28 +48,31 @@ VERSION_PEP440 = Regex(Specifier._regex_str, re.VERBOSE | re.IGNORECASE)
VERSION_LEGACY = Regex(LegacySpecifier._regex_str, re.VERBOSE | re.IGNORECASE)
VERSION_ONE = VERSION_PEP440 ^ VERSION_LEGACY
-VERSION_MANY = Combine(VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE),
- joinString=",", adjacent=False)("_raw_spec")
+VERSION_MANY = Combine(
+ VERSION_ONE + ZeroOrMore(COMMA + VERSION_ONE), joinString=",", adjacent=False
+)("_raw_spec")
_VERSION_SPEC = Optional(((LPAREN + VERSION_MANY + RPAREN) | VERSION_MANY))
-_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or '')
+_VERSION_SPEC.setParseAction(lambda s, l, t: t._raw_spec or "")
VERSION_SPEC = originalTextFor(_VERSION_SPEC)("specifier")
VERSION_SPEC.setParseAction(lambda s, l, t: t[1])
MARKER_EXPR = originalTextFor(MARKER_EXPR())("marker")
MARKER_EXPR.setParseAction(
- lambda s, l, t: Marker(s[t._original_start:t._original_end])
+ lambda s, l, t: Marker(s[t._original_start : t._original_end])
)
-MARKER_SEPERATOR = SEMICOLON
-MARKER = MARKER_SEPERATOR + MARKER_EXPR
+MARKER_SEPARATOR = SEMICOLON
+MARKER = MARKER_SEPARATOR + MARKER_EXPR
VERSION_AND_MARKER = VERSION_SPEC + Optional(MARKER)
URL_AND_MARKER = URL + Optional(MARKER)
-NAMED_REQUIREMENT = \
- NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER)
+NAMED_REQUIREMENT = NAME + Optional(EXTRAS) + (URL_AND_MARKER | VERSION_AND_MARKER)
REQUIREMENT = stringStart + NAMED_REQUIREMENT + stringEnd
+# setuptools.extern.pyparsing isn't thread safe during initialization, so we do it eagerly, see
+# issue #104
+REQUIREMENT.parseString("x[]")
class Requirement(object):
@@ -90,15 +93,21 @@ class Requirement(object):
req = REQUIREMENT.parseString(requirement_string)
except ParseException as e:
raise InvalidRequirement(
- "Invalid requirement, parse error at \"{0!r}\"".format(
- requirement_string[e.loc:e.loc + 8]))
+ 'Parse error at "{0!r}": {1}'.format(
+ requirement_string[e.loc : e.loc + 8], e.msg
+ )
+ )
self.name = req.name
if req.url:
parsed_url = urlparse.urlparse(req.url)
- if not (parsed_url.scheme and parsed_url.netloc) or (
- not parsed_url.scheme and not parsed_url.netloc):
- raise InvalidRequirement("Invalid URL given")
+ if parsed_url.scheme == "file":
+ if urlparse.urlunparse(parsed_url) != req.url:
+ raise InvalidRequirement("Invalid URL given")
+ elif not (parsed_url.scheme and parsed_url.netloc) or (
+ not parsed_url.scheme and not parsed_url.netloc
+ ):
+ raise InvalidRequirement("Invalid URL: {0}".format(req.url))
self.url = req.url
else:
self.url = None
@@ -117,6 +126,8 @@ class Requirement(object):
if self.url:
parts.append("@ {0}".format(self.url))
+ if self.marker:
+ parts.append(" ")
if self.marker:
parts.append("; {0}".format(self.marker))
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/specifiers.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/specifiers.py
index 7f5a76c..743576a 100644
--- a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/specifiers.py
+++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/specifiers.py
@@ -19,7 +19,6 @@ class InvalidSpecifier(ValueError):
class BaseSpecifier(with_metaclass(abc.ABCMeta, object)):
-
@abc.abstractmethod
def __str__(self):
"""
@@ -84,10 +83,7 @@ class _IndividualSpecifier(BaseSpecifier):
if not match:
raise InvalidSpecifier("Invalid specifier: '{0}'".format(spec))
- self._spec = (
- match.group("operator").strip(),
- match.group("version").strip(),
- )
+ self._spec = (match.group("operator").strip(), match.group("version").strip())
# Store whether or not this Specifier should accept prereleases
self._prereleases = prereleases
@@ -99,11 +95,7 @@ class _IndividualSpecifier(BaseSpecifier):
else ""
)
- return "<{0}({1!r}{2})>".format(
- self.__class__.__name__,
- str(self),
- pre,
- )
+ return "<{0}({1!r}{2})>".format(self.__class__.__name__, str(self), pre)
def __str__(self):
return "{0}{1}".format(*self._spec)
@@ -194,11 +186,12 @@ class _IndividualSpecifier(BaseSpecifier):
# If our version is a prerelease, and we were not set to allow
# prereleases, then we'll store it for later incase nothing
# else matches this specifier.
- if (parsed_version.is_prerelease and not
- (prereleases or self.prereleases)):
+ if parsed_version.is_prerelease and not (
+ prereleases or self.prereleases
+ ):
found_prereleases.append(version)
# Either this is not a prerelease, or we should have been
- # accepting prereleases from the begining.
+ # accepting prereleases from the beginning.
else:
yielded = True
yield version
@@ -213,8 +206,7 @@ class _IndividualSpecifier(BaseSpecifier):
class LegacySpecifier(_IndividualSpecifier):
- _regex_str = (
- r"""
+ _regex_str = r"""
(?P(==|!=|<=|>=|<|>))
\s*
(?P
@@ -225,10 +217,8 @@ class LegacySpecifier(_IndividualSpecifier):
# them, and a comma since it's a version separator.
)
"""
- )
- _regex = re.compile(
- r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
+ _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
_operators = {
"==": "equal",
@@ -269,13 +259,13 @@ def _require_version_compare(fn):
if not isinstance(prospective, Version):
return False
return fn(self, prospective, spec)
+
return wrapped
class Specifier(_IndividualSpecifier):
- _regex_str = (
- r"""
+ _regex_str = r"""
(?P(~=|==|!=|<=|>=|<|>|===))
(?P
(?:
@@ -367,10 +357,8 @@ class Specifier(_IndividualSpecifier):
)
)
"""
- )
- _regex = re.compile(
- r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
+ _regex = re.compile(r"^\s*" + _regex_str + r"\s*$", re.VERBOSE | re.IGNORECASE)
_operators = {
"~=": "compatible",
@@ -397,8 +385,7 @@ class Specifier(_IndividualSpecifier):
prefix = ".".join(
list(
itertools.takewhile(
- lambda x: (not x.startswith("post") and not
- x.startswith("dev")),
+ lambda x: (not x.startswith("post") and not x.startswith("dev")),
_version_split(spec),
)
)[:-1]
@@ -407,8 +394,9 @@ class Specifier(_IndividualSpecifier):
# Add the prefix notation to the end of our string
prefix += ".*"
- return (self._get_operator(">=")(prospective, spec) and
- self._get_operator("==")(prospective, prefix))
+ return self._get_operator(">=")(prospective, spec) and self._get_operator("==")(
+ prospective, prefix
+ )
@_require_version_compare
def _compare_equal(self, prospective, spec):
@@ -428,7 +416,7 @@ class Specifier(_IndividualSpecifier):
# Shorten the prospective version to be the same length as the spec
# so that we can determine if the specifier is a prefix of the
# prospective version or not.
- prospective = prospective[:len(spec)]
+ prospective = prospective[: len(spec)]
# Pad out our two sides with zeros so that they both equal the same
# length.
@@ -503,7 +491,7 @@ class Specifier(_IndividualSpecifier):
return False
# Ensure that we do not allow a local version of the version mentioned
- # in the specifier, which is techincally greater than, to match.
+ # in the specifier, which is technically greater than, to match.
if prospective.local is not None:
if Version(prospective.base_version) == Version(spec.base_version):
return False
@@ -567,27 +555,17 @@ def _pad_version(left, right):
right_split.append(list(itertools.takewhile(lambda x: x.isdigit(), right)))
# Get the rest of our versions
- left_split.append(left[len(left_split[0]):])
- right_split.append(right[len(right_split[0]):])
+ left_split.append(left[len(left_split[0]) :])
+ right_split.append(right[len(right_split[0]) :])
# Insert our padding
- left_split.insert(
- 1,
- ["0"] * max(0, len(right_split[0]) - len(left_split[0])),
- )
- right_split.insert(
- 1,
- ["0"] * max(0, len(left_split[0]) - len(right_split[0])),
- )
+ left_split.insert(1, ["0"] * max(0, len(right_split[0]) - len(left_split[0])))
+ right_split.insert(1, ["0"] * max(0, len(left_split[0]) - len(right_split[0])))
- return (
- list(itertools.chain(*left_split)),
- list(itertools.chain(*right_split)),
- )
+ return (list(itertools.chain(*left_split)), list(itertools.chain(*right_split)))
class SpecifierSet(BaseSpecifier):
-
def __init__(self, specifiers="", prereleases=None):
# Split on , to break each indidivual specifier into it's own item, and
# strip each item to remove leading/trailing whitespace.
@@ -721,10 +699,7 @@ class SpecifierSet(BaseSpecifier):
# given version is contained within all of them.
# Note: This use of all() here means that an empty set of specifiers
# will always return True, this is an explicit design decision.
- return all(
- s.contains(item, prereleases=prereleases)
- for s in self._specs
- )
+ return all(s.contains(item, prereleases=prereleases) for s in self._specs)
def filter(self, iterable, prereleases=None):
# Determine if we're forcing a prerelease or not, if we're not forcing
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/utils.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/utils.py
index 942387c..8841878 100644
--- a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/utils.py
+++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/utils.py
@@ -5,6 +5,8 @@ from __future__ import absolute_import, division, print_function
import re
+from .version import InvalidVersion, Version
+
_canonicalize_regex = re.compile(r"[-_.]+")
@@ -12,3 +14,44 @@ _canonicalize_regex = re.compile(r"[-_.]+")
def canonicalize_name(name):
# This is taken from PEP 503.
return _canonicalize_regex.sub("-", name).lower()
+
+
+def canonicalize_version(version):
+ """
+ This is very similar to Version.__str__, but has one subtle differences
+ with the way it handles the release segment.
+ """
+
+ try:
+ version = Version(version)
+ except InvalidVersion:
+ # Legacy versions cannot be normalized
+ return version
+
+ parts = []
+
+ # Epoch
+ if version.epoch != 0:
+ parts.append("{0}!".format(version.epoch))
+
+ # Release segment
+ # NB: This strips trailing '.0's to normalize
+ parts.append(re.sub(r"(\.0)+$", "", ".".join(str(x) for x in version.release)))
+
+ # Pre-release
+ if version.pre is not None:
+ parts.append("".join(str(x) for x in version.pre))
+
+ # Post-release
+ if version.post is not None:
+ parts.append(".post{0}".format(version.post))
+
+ # Development release
+ if version.dev is not None:
+ parts.append(".dev{0}".format(version.dev))
+
+ # Local version segment
+ if version.local is not None:
+ parts.append("+{0}".format(version.local))
+
+ return "".join(parts)
diff --git a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/version.py b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/version.py
index 83b5ee8..95157a1 100644
--- a/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/version.py
+++ b/venv/lib/python3.8/site-packages/setuptools/_vendor/packaging/version.py
@@ -10,14 +10,11 @@ import re
from ._structures import Infinity
-__all__ = [
- "parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"
-]
+__all__ = ["parse", "Version", "LegacyVersion", "InvalidVersion", "VERSION_PATTERN"]
_Version = collections.namedtuple(
- "_Version",
- ["epoch", "release", "dev", "pre", "post", "local"],
+ "_Version", ["epoch", "release", "dev", "pre", "post", "local"]
)
@@ -40,7 +37,6 @@ class InvalidVersion(ValueError):
class _BaseVersion(object):
-
def __hash__(self):
return hash(self._key)
@@ -70,7 +66,6 @@ class _BaseVersion(object):
class LegacyVersion(_BaseVersion):
-
def __init__(self, version):
self._version = str(version)
self._key = _legacy_cmpkey(self._version)
@@ -89,6 +84,26 @@ class LegacyVersion(_BaseVersion):
def base_version(self):
return self._version
+ @property
+ def epoch(self):
+ return -1
+
+ @property
+ def release(self):
+ return None
+
+ @property
+ def pre(self):
+ return None
+
+ @property
+ def post(self):
+ return None
+
+ @property
+ def dev(self):
+ return None
+
@property
def local(self):
return None
@@ -101,13 +116,19 @@ class LegacyVersion(_BaseVersion):
def is_postrelease(self):
return False
+ @property
+ def is_devrelease(self):
+ return False
-_legacy_version_component_re = re.compile(
- r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE,
-)
+
+_legacy_version_component_re = re.compile(r"(\d+ | [a-z]+ | \.| -)", re.VERBOSE)
_legacy_version_replacement_map = {
- "pre": "c", "preview": "c", "-": "final-", "rc": "c", "dev": "@",
+ "pre": "c",
+ "preview": "c",
+ "-": "final-",
+ "rc": "c",
+ "dev": "@",
}
@@ -154,6 +175,7 @@ def _legacy_cmpkey(version):
return epoch, parts
+
# Deliberately not anchored to the start and end of the string, to make it
# easier for 3rd party code to reuse
VERSION_PATTERN = r"""
@@ -190,10 +212,7 @@ VERSION_PATTERN = r"""
class Version(_BaseVersion):
- _regex = re.compile(
- r"^\s*" + VERSION_PATTERN + r"\s*$",
- re.VERBOSE | re.IGNORECASE,
- )
+ _regex = re.compile(r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE)
def __init__(self, version):
# Validate the version and parse it into pieces
@@ -205,18 +224,11 @@ class Version(_BaseVersion):
self._version = _Version(
epoch=int(match.group("epoch")) if match.group("epoch") else 0,
release=tuple(int(i) for i in match.group("release").split(".")),
- pre=_parse_letter_version(
- match.group("pre_l"),
- match.group("pre_n"),
- ),
+ pre=_parse_letter_version(match.group("pre_l"), match.group("pre_n")),
post=_parse_letter_version(
- match.group("post_l"),
- match.group("post_n1") or match.group("post_n2"),
- ),
- dev=_parse_letter_version(
- match.group("dev_l"),
- match.group("dev_n"),
+ match.group("post_l"), match.group("post_n1") or match.group("post_n2")
),
+ dev=_parse_letter_version(match.group("dev_l"), match.group("dev_n")),
local=_parse_local_version(match.group("local")),
)
@@ -237,32 +249,57 @@ class Version(_BaseVersion):
parts = []
# Epoch
- if self._version.epoch != 0:
- parts.append("{0}!".format(self._version.epoch))
+ if self.epoch != 0:
+ parts.append("{0}!".format(self.epoch))
# Release segment
- parts.append(".".join(str(x) for x in self._version.release))
+ parts.append(".".join(str(x) for x in self.release))
# Pre-release
- if self._version.pre is not None:
- parts.append("".join(str(x) for x in self._version.pre))
+ if self.pre is not None:
+ parts.append("".join(str(x) for x in self.pre))
# Post-release
- if self._version.post is not None:
- parts.append(".post{0}".format(self._version.post[1]))
+ if self.post is not None:
+ parts.append(".post{0}".format(self.post))
# Development release
- if self._version.dev is not None:
- parts.append(".dev{0}".format(self._version.dev[1]))
+ if self.dev is not None:
+ parts.append(".dev{0}".format(self.dev))
# Local version segment
- if self._version.local is not None:
- parts.append(
- "+{0}".format(".".join(str(x) for x in self._version.local))
- )
+ if self.local is not None:
+ parts.append("+{0}".format(self.local))
return "".join(parts)
+ @property
+ def epoch(self):
+ return self._version.epoch
+
+ @property
+ def release(self):
+ return self._version.release
+
+ @property
+ def pre(self):
+ return self._version.pre
+
+ @property
+ def post(self):
+ return self._version.post[1] if self._version.post else None
+
+ @property
+ def dev(self):
+ return self._version.dev[1] if self._version.dev else None
+
+ @property
+ def local(self):
+ if self._version.local:
+ return ".".join(str(x) for x in self._version.local)
+ else:
+ return None
+
@property
def public(self):
return str(self).split("+", 1)[0]
@@ -272,27 +309,25 @@ class Version(_BaseVersion):
parts = []
# Epoch
- if self._version.epoch != 0:
- parts.append("{0}!".format(self._version.epoch))
+ if self.epoch != 0:
+ parts.append("{0}!".format(self.epoch))
# Release segment
- parts.append(".".join(str(x) for x in self._version.release))
+ parts.append(".".join(str(x) for x in self.release))
return "".join(parts)
- @property
- def local(self):
- version_string = str(self)
- if "+" in version_string:
- return version_string.split("+", 1)[1]
-
@property
def is_prerelease(self):
- return bool(self._version.dev or self._version.pre)
+ return self.dev is not None or self.pre is not None
@property
def is_postrelease(self):
- return bool(self._version.post)
+ return self.post is not None
+
+ @property
+ def is_devrelease(self):
+ return self.dev is not None
def _parse_letter_version(letter, number):
@@ -326,7 +361,7 @@ def _parse_letter_version(letter, number):
return letter, int(number)
-_local_version_seperators = re.compile(r"[\._-]")
+_local_version_separators = re.compile(r"[\._-]")
def _parse_local_version(local):
@@ -336,7 +371,7 @@ def _parse_local_version(local):
if local is not None:
return tuple(
part.lower() if not part.isdigit() else int(part)
- for part in _local_version_seperators.split(local)
+ for part in _local_version_separators.split(local)
)
@@ -347,12 +382,7 @@ def _cmpkey(epoch, release, pre, post, dev, local):
# re-reverse it back into the correct order and make it a tuple and use
# that for our sorting key.
release = tuple(
- reversed(list(
- itertools.dropwhile(
- lambda x: x == 0,
- reversed(release),
- )
- ))
+ reversed(list(itertools.dropwhile(lambda x: x == 0, reversed(release))))
)
# We need to "trick" the sorting algorithm to put 1.0.dev0 before 1.0a0.
@@ -385,9 +415,6 @@ def _cmpkey(epoch, release, pre, post, dev, local):
# - Numeric segments sort numerically
# - Shorter versions sort before longer versions when the prefixes
# match exactly
- local = tuple(
- (i, "") if isinstance(i, int) else (-Infinity, i)
- for i in local
- )
+ local = tuple((i, "") if isinstance(i, int) else (-Infinity, i) for i in local)
return epoch, release, pre, post, dev, local
diff --git a/venv/lib/python3.8/site-packages/setuptools/archive_util.py b/venv/lib/python3.8/site-packages/setuptools/archive_util.py
index 8143604..0ce190b 100644
--- a/venv/lib/python3.8/site-packages/setuptools/archive_util.py
+++ b/venv/lib/python3.8/site-packages/setuptools/archive_util.py
@@ -25,7 +25,8 @@ def default_filter(src, dst):
return dst
-def unpack_archive(filename, extract_dir, progress_filter=default_filter,
+def unpack_archive(
+ filename, extract_dir, progress_filter=default_filter,
drivers=None):
"""Unpack `filename` to `extract_dir`, or raise ``UnrecognizedFormat``
@@ -133,10 +134,10 @@ def unpack_tarfile(filename, extract_dir, progress_filter=default_filter):
"""
try:
tarobj = tarfile.open(filename)
- except tarfile.TarError:
+ except tarfile.TarError as e:
raise UnrecognizedFormat(
"%s is not a compressed or uncompressed tar file" % (filename,)
- )
+ ) from e
with contextlib.closing(tarobj):
# don't do any chowning!
tarobj.chown = lambda *args: None
@@ -148,7 +149,8 @@ def unpack_tarfile(filename, extract_dir, progress_filter=default_filter):
# resolve any links and to extract the link targets as normal
# files
- while member is not None and (member.islnk() or member.issym()):
+ while member is not None and (
+ member.islnk() or member.issym()):
linkpath = member.linkname
if member.issym():
base = posixpath.dirname(member.name)
diff --git a/venv/lib/python3.8/site-packages/setuptools/build_meta.py b/venv/lib/python3.8/site-packages/setuptools/build_meta.py
index 10c4b52..4626681 100644
--- a/venv/lib/python3.8/site-packages/setuptools/build_meta.py
+++ b/venv/lib/python3.8/site-packages/setuptools/build_meta.py
@@ -38,7 +38,6 @@ import distutils
from setuptools.py31compat import TemporaryDirectory
from pkg_resources import parse_requirements
-from pkg_resources.py31compat import makedirs
__all__ = ['get_requires_for_build_sdist',
'get_requires_for_build_wheel',
@@ -48,6 +47,7 @@ __all__ = ['get_requires_for_build_sdist',
'__legacy__',
'SetupRequirementsError']
+
class SetupRequirementsError(BaseException):
def __init__(self, specifiers):
self.specifiers = specifiers
@@ -143,7 +143,8 @@ class _BuildMetaBackend(object):
def get_requires_for_build_wheel(self, config_settings=None):
config_settings = self._fix_config(config_settings)
- return self._get_build_requires(config_settings, requirements=['wheel'])
+ return self._get_build_requires(
+ config_settings, requirements=['wheel'])
def get_requires_for_build_sdist(self, config_settings=None):
config_settings = self._fix_config(config_settings)
@@ -160,8 +161,10 @@ class _BuildMetaBackend(object):
dist_infos = [f for f in os.listdir(dist_info_directory)
if f.endswith('.dist-info')]
- if (len(dist_infos) == 0 and
- len(_get_immediate_subdirectories(dist_info_directory)) == 1):
+ if (
+ len(dist_infos) == 0 and
+ len(_get_immediate_subdirectories(dist_info_directory)) == 1
+ ):
dist_info_directory = os.path.join(
dist_info_directory, os.listdir(dist_info_directory)[0])
@@ -186,14 +189,15 @@ class _BuildMetaBackend(object):
result_directory = os.path.abspath(result_directory)
# Build in a temporary directory, then copy to the target.
- makedirs(result_directory, exist_ok=True)
+ os.makedirs(result_directory, exist_ok=True)
with TemporaryDirectory(dir=result_directory) as tmp_dist_dir:
sys.argv = (sys.argv[:1] + setup_command +
['--dist-dir', tmp_dist_dir] +
config_settings["--global-option"])
self.run_setup()
- result_basename = _file_with_extension(tmp_dist_dir, result_extension)
+ result_basename = _file_with_extension(
+ tmp_dist_dir, result_extension)
result_path = os.path.join(result_directory, result_basename)
if os.path.exists(result_path):
# os.rename will fail overwriting on non-Unix.
@@ -202,7 +206,6 @@ class _BuildMetaBackend(object):
return result_basename
-
def build_wheel(self, wheel_directory, config_settings=None,
metadata_directory=None):
return self._build_with_temp_dir(['bdist_wheel'], '.whl',
@@ -217,9 +220,12 @@ class _BuildMetaBackend(object):
class _BuildMetaLegacyBackend(_BuildMetaBackend):
"""Compatibility backend for setuptools
- This is a version of setuptools.build_meta that endeavors to maintain backwards
- compatibility with pre-PEP 517 modes of invocation. It exists as a temporary
- bridge between the old packaging mechanism and the new packaging mechanism,
+ This is a version of setuptools.build_meta that endeavors
+ to maintain backwards
+ compatibility with pre-PEP 517 modes of invocation. It
+ exists as a temporary
+ bridge between the old packaging mechanism and the new
+ packaging mechanism,
and will eventually be removed.
"""
def run_setup(self, setup_script='setup.py'):
@@ -232,6 +238,12 @@ class _BuildMetaLegacyBackend(_BuildMetaBackend):
if script_dir not in sys.path:
sys.path.insert(0, script_dir)
+ # Some setup.py scripts (e.g. in pygame and numpy) use sys.argv[0] to
+ # get the directory of the source code. They expect it to refer to the
+ # setup.py script.
+ sys_argv_0 = sys.argv[0]
+ sys.argv[0] = setup_script
+
try:
super(_BuildMetaLegacyBackend,
self).run_setup(setup_script=setup_script)
@@ -242,6 +254,8 @@ class _BuildMetaLegacyBackend(_BuildMetaBackend):
# the original path so that the path manipulation does not persist
# within the hook after run_setup is called.
sys.path[:] = sys_path
+ sys.argv[0] = sys_argv_0
+
# The primary backend
_BACKEND = _BuildMetaBackend()
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__init__.py b/venv/lib/python3.8/site-packages/setuptools/command/__init__.py
index fe619e2..743f558 100644
--- a/venv/lib/python3.8/site-packages/setuptools/command/__init__.py
+++ b/venv/lib/python3.8/site-packages/setuptools/command/__init__.py
@@ -2,8 +2,7 @@ __all__ = [
'alias', 'bdist_egg', 'bdist_rpm', 'build_ext', 'build_py', 'develop',
'easy_install', 'egg_info', 'install', 'install_lib', 'rotate', 'saveopts',
'sdist', 'setopt', 'test', 'install_egg_info', 'install_scripts',
- 'register', 'bdist_wininst', 'upload_docs', 'upload', 'build_clib',
- 'dist_info',
+ 'bdist_wininst', 'upload_docs', 'build_clib', 'dist_info',
]
from distutils.command.bdist import bdist
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/__init__.cpython-38.pyc
index 83a282d..9563da5 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/alias.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/alias.cpython-38.pyc
index 224594a..250badb 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/alias.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/alias.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/bdist_egg.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/bdist_egg.cpython-38.pyc
index 4a381de..c04da07 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/bdist_egg.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/bdist_egg.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/bdist_rpm.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/bdist_rpm.cpython-38.pyc
index 84b19b9..307653a 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/bdist_rpm.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/bdist_rpm.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/bdist_wininst.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/bdist_wininst.cpython-38.pyc
index 6287ece..da599c7 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/bdist_wininst.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/bdist_wininst.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/build_clib.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/build_clib.cpython-38.pyc
index e840552..c486684 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/build_clib.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/build_clib.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/build_ext.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/build_ext.cpython-38.pyc
index 8c3b667..d908454 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/build_ext.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/build_ext.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/build_py.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/build_py.cpython-38.pyc
index f5a4723..6a89c40 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/build_py.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/build_py.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/develop.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/develop.cpython-38.pyc
index 30b347d..7a58408 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/develop.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/develop.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/dist_info.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/dist_info.cpython-38.pyc
index 3f02941..fc03342 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/dist_info.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/dist_info.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/easy_install.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/easy_install.cpython-38.pyc
index e48628c..10fd6fc 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/easy_install.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/easy_install.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/egg_info.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/egg_info.cpython-38.pyc
index f475cb7..a0fcb04 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/egg_info.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/egg_info.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/install.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/install.cpython-38.pyc
index 1d4479e..54e45d9 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/install.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/install.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/install_egg_info.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/install_egg_info.cpython-38.pyc
index e374a09..7cee205 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/install_egg_info.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/install_egg_info.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/install_lib.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/install_lib.cpython-38.pyc
index a10466b..0dbb56e 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/install_lib.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/install_lib.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/install_scripts.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/install_scripts.cpython-38.pyc
index 1f4f89e..8b9dc7f 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/install_scripts.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/install_scripts.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/py36compat.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/py36compat.cpython-38.pyc
index f13b42c..c2cf493 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/py36compat.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/py36compat.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/register.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/register.cpython-38.pyc
index 5af686d..01e33ef 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/register.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/register.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/rotate.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/rotate.cpython-38.pyc
index d638fb0..86c967c 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/rotate.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/rotate.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/saveopts.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/saveopts.cpython-38.pyc
index 5359098..1eba315 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/saveopts.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/saveopts.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/sdist.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/sdist.cpython-38.pyc
index ea51339..5f8dff5 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/sdist.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/sdist.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/setopt.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/setopt.cpython-38.pyc
index 6f4cc50..ac36b11 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/setopt.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/setopt.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/test.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/test.cpython-38.pyc
index f0491bd..5377fd0 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/test.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/test.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/upload.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/upload.cpython-38.pyc
index c998f7a..626925f 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/upload.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/upload.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/upload_docs.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/upload_docs.cpython-38.pyc
index a707496..15da24d 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/upload_docs.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/command/__pycache__/upload_docs.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/bdist_egg.py b/venv/lib/python3.8/site-packages/setuptools/command/bdist_egg.py
index 9f8df91..7af3165 100644
--- a/venv/lib/python3.8/site-packages/setuptools/command/bdist_egg.py
+++ b/venv/lib/python3.8/site-packages/setuptools/command/bdist_egg.py
@@ -11,13 +11,14 @@ import os
import re
import textwrap
import marshal
+import warnings
from setuptools.extern import six
from pkg_resources import get_build_platform, Distribution, ensure_directory
from pkg_resources import EntryPoint
from setuptools.extension import Library
-from setuptools import Command
+from setuptools import Command, SetuptoolsDeprecationWarning
try:
# Python 2.7 or >=3.2
@@ -54,10 +55,11 @@ def write_stub(resource, pyfile):
_stub_template = textwrap.dedent("""
def __bootstrap__():
global __bootstrap__, __loader__, __file__
- import sys, pkg_resources, imp
+ import sys, pkg_resources
+ from importlib.machinery import ExtensionFileLoader
__file__ = pkg_resources.resource_filename(__name__, %r)
__loader__ = None; del __bootstrap__, __loader__
- imp.load_dynamic(__name__,__file__)
+ ExtensionFileLoader(__name__,__file__).load_module()
__bootstrap__()
""").lstrip()
with open(pyfile, 'w') as f:
@@ -278,13 +280,19 @@ class bdist_egg(Command):
if ep is None:
return 'w' # not an eggsecutable, do it the usual way.
+ warnings.warn(
+ "Eggsecutables are deprecated and will be removed in a future "
+ "version.",
+ SetuptoolsDeprecationWarning
+ )
+
if not ep.attrs or ep.extras:
raise DistutilsSetupError(
"eggsecutable entry point (%r) cannot have 'extras' "
"or refer to a module" % (ep,)
)
- pyver = sys.version[:3]
+ pyver = '{}.{}'.format(*sys.version_info)
pkg = ep.module_name
full = '.'.join(ep.attrs)
base = ep.attrs[0]
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/bdist_wininst.py b/venv/lib/python3.8/site-packages/setuptools/command/bdist_wininst.py
index 073de97..ff4b634 100644
--- a/venv/lib/python3.8/site-packages/setuptools/command/bdist_wininst.py
+++ b/venv/lib/python3.8/site-packages/setuptools/command/bdist_wininst.py
@@ -1,4 +1,7 @@
import distutils.command.bdist_wininst as orig
+import warnings
+
+from setuptools import SetuptoolsDeprecationWarning
class bdist_wininst(orig.bdist_wininst):
@@ -14,6 +17,12 @@ class bdist_wininst(orig.bdist_wininst):
return cmd
def run(self):
+ warnings.warn(
+ "bdist_wininst is deprecated and will be removed in a future "
+ "version. Use bdist_wheel (wheel packages) instead.",
+ SetuptoolsDeprecationWarning
+ )
+
self._is_running = True
try:
orig.bdist_wininst.run(self)
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/build_clib.py b/venv/lib/python3.8/site-packages/setuptools/command/build_clib.py
index 09caff6..67ce244 100644
--- a/venv/lib/python3.8/site-packages/setuptools/command/build_clib.py
+++ b/venv/lib/python3.8/site-packages/setuptools/command/build_clib.py
@@ -25,9 +25,9 @@ class build_clib(orig.build_clib):
sources = build_info.get('sources')
if sources is None or not isinstance(sources, (list, tuple)):
raise DistutilsSetupError(
- "in 'libraries' option (library '%s'), "
- "'sources' must be present and must be "
- "a list of source filenames" % lib_name)
+ "in 'libraries' option (library '%s'), "
+ "'sources' must be present and must be "
+ "a list of source filenames" % lib_name)
sources = list(sources)
log.info("building '%s' library", lib_name)
@@ -38,9 +38,9 @@ class build_clib(orig.build_clib):
obj_deps = build_info.get('obj_deps', dict())
if not isinstance(obj_deps, dict):
raise DistutilsSetupError(
- "in 'libraries' option (library '%s'), "
- "'obj_deps' must be a dictionary of "
- "type 'source: list'" % lib_name)
+ "in 'libraries' option (library '%s'), "
+ "'obj_deps' must be a dictionary of "
+ "type 'source: list'" % lib_name)
dependencies = []
# Get the global dependencies that are specified by the '' key.
@@ -48,9 +48,9 @@ class build_clib(orig.build_clib):
global_deps = obj_deps.get('', list())
if not isinstance(global_deps, (list, tuple)):
raise DistutilsSetupError(
- "in 'libraries' option (library '%s'), "
- "'obj_deps' must be a dictionary of "
- "type 'source: list'" % lib_name)
+ "in 'libraries' option (library '%s'), "
+ "'obj_deps' must be a dictionary of "
+ "type 'source: list'" % lib_name)
# Build the list to be used by newer_pairwise_group
# each source will be auto-added to its dependencies.
@@ -60,39 +60,42 @@ class build_clib(orig.build_clib):
extra_deps = obj_deps.get(source, list())
if not isinstance(extra_deps, (list, tuple)):
raise DistutilsSetupError(
- "in 'libraries' option (library '%s'), "
- "'obj_deps' must be a dictionary of "
- "type 'source: list'" % lib_name)
+ "in 'libraries' option (library '%s'), "
+ "'obj_deps' must be a dictionary of "
+ "type 'source: list'" % lib_name)
src_deps.extend(extra_deps)
dependencies.append(src_deps)
expected_objects = self.compiler.object_filenames(
- sources,
- output_dir=self.build_temp
- )
+ sources,
+ output_dir=self.build_temp,
+ )
- if newer_pairwise_group(dependencies, expected_objects) != ([], []):
+ if (
+ newer_pairwise_group(dependencies, expected_objects)
+ != ([], [])
+ ):
# First, compile the source code to object files in the library
# directory. (This should probably change to putting object
# files in a temporary build directory.)
macros = build_info.get('macros')
include_dirs = build_info.get('include_dirs')
cflags = build_info.get('cflags')
- objects = self.compiler.compile(
- sources,
- output_dir=self.build_temp,
- macros=macros,
- include_dirs=include_dirs,
- extra_postargs=cflags,
- debug=self.debug
- )
+ self.compiler.compile(
+ sources,
+ output_dir=self.build_temp,
+ macros=macros,
+ include_dirs=include_dirs,
+ extra_postargs=cflags,
+ debug=self.debug
+ )
# Now "link" the object files together into a static library.
# (On Unix at least, this isn't really linking -- it just
# builds an archive. Whatever.)
self.compiler.create_static_lib(
- expected_objects,
- lib_name,
- output_dir=self.build_clib,
- debug=self.debug
- )
+ expected_objects,
+ lib_name,
+ output_dir=self.build_clib,
+ debug=self.debug
+ )
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/build_ext.py b/venv/lib/python3.8/site-packages/setuptools/command/build_ext.py
index daa8e4f..0eb29ad 100644
--- a/venv/lib/python3.8/site-packages/setuptools/command/build_ext.py
+++ b/venv/lib/python3.8/site-packages/setuptools/command/build_ext.py
@@ -14,7 +14,8 @@ from setuptools.extern import six
if six.PY2:
import imp
- EXTENSION_SUFFIXES = [s for s, _, tp in imp.get_suffixes() if tp == imp.C_EXTENSION]
+ EXTENSION_SUFFIXES = [
+ s for s, _, tp in imp.get_suffixes() if tp == imp.C_EXTENSION]
else:
from importlib.machinery import EXTENSION_SUFFIXES
@@ -29,7 +30,7 @@ except ImportError:
# make sure _config_vars is initialized
get_config_var("LDSHARED")
-from distutils.sysconfig import _config_vars as _CONFIG_VARS
+from distutils.sysconfig import _config_vars as _CONFIG_VARS # noqa
def _customize_compiler_for_shlib(compiler):
@@ -65,7 +66,9 @@ elif os.name != 'nt':
except ImportError:
pass
-if_dl = lambda s: s if have_rtld else ''
+
+def if_dl(s):
+ return s if have_rtld else ''
def get_abi3_suffix():
@@ -113,7 +116,7 @@ class build_ext(_build_ext):
if fullname in self.ext_map:
ext = self.ext_map[fullname]
use_abi3 = (
- six.PY3
+ not six.PY2
and getattr(ext, 'py_limited_api')
and get_abi3_suffix()
)
@@ -251,7 +254,8 @@ class build_ext(_build_ext):
'\n'.join([
"def __bootstrap__():",
" global __bootstrap__, __file__, __loader__",
- " import sys, os, pkg_resources, imp" + if_dl(", dl"),
+ " import sys, os, pkg_resources" + if_dl(", dl"),
+ " from importlib.machinery import ExtensionFileLoader",
" __file__ = pkg_resources.resource_filename"
"(__name__,%r)"
% os.path.basename(ext._file_name),
@@ -263,7 +267,8 @@ class build_ext(_build_ext):
" try:",
" os.chdir(os.path.dirname(__file__))",
if_dl(" sys.setdlopenflags(dl.RTLD_NOW)"),
- " imp.load_dynamic(__name__,__file__)",
+ " ExtensionFileLoader(__name__,",
+ " __file__).load_module()",
" finally:",
if_dl(" sys.setdlopenflags(old_flags)"),
" os.chdir(old_dir)",
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/build_py.py b/venv/lib/python3.8/site-packages/setuptools/command/build_py.py
index b0314fd..9d0288a 100644
--- a/venv/lib/python3.8/site-packages/setuptools/command/build_py.py
+++ b/venv/lib/python3.8/site-packages/setuptools/command/build_py.py
@@ -7,6 +7,7 @@ import textwrap
import io
import distutils.errors
import itertools
+import stat
from setuptools.extern import six
from setuptools.extern.six.moves import map, filter, filterfalse
@@ -20,6 +21,10 @@ except ImportError:
"do nothing"
+def make_writable(target):
+ os.chmod(target, os.stat(target).st_mode | stat.S_IWRITE)
+
+
class build_py(orig.build_py, Mixin2to3):
"""Enhanced 'build_py' command that includes data files with packages
@@ -121,6 +126,7 @@ class build_py(orig.build_py, Mixin2to3):
self.mkpath(os.path.dirname(target))
srcfile = os.path.join(src_dir, filename)
outf, copied = self.copy_file(srcfile, target)
+ make_writable(target)
srcfile = os.path.abspath(srcfile)
if (copied and
srcfile in self.distribution.convert_2to3_doctests):
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/develop.py b/venv/lib/python3.8/site-packages/setuptools/command/develop.py
index 009e4f9..e7e03cd 100644
--- a/venv/lib/python3.8/site-packages/setuptools/command/develop.py
+++ b/venv/lib/python3.8/site-packages/setuptools/command/develop.py
@@ -108,7 +108,7 @@ class develop(namespaces.DevelopInstaller, easy_install):
return path_to_setup
def install_for_development(self):
- if six.PY3 and getattr(self.distribution, 'use_2to3', False):
+ if not six.PY2 and getattr(self.distribution, 'use_2to3', False):
# If we run 2to3 we can not do this inplace:
# Ensure metadata is up-to-date
@@ -139,7 +139,6 @@ class develop(namespaces.DevelopInstaller, easy_install):
self.reinitialize_command('build_ext', inplace=1)
self.run_command('build_ext')
- self.install_site_py() # ensure that target dir is site-safe
if setuptools.bootstrap_install_from:
self.easy_install(setuptools.bootstrap_install_from)
setuptools.bootstrap_install_from = None
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/easy_install.py b/venv/lib/python3.8/site-packages/setuptools/command/easy_install.py
index 06c9827..bcbd4f5 100644
--- a/venv/lib/python3.8/site-packages/setuptools/command/easy_install.py
+++ b/venv/lib/python3.8/site-packages/setuptools/command/easy_install.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
"""
Easy Install
------------
@@ -64,7 +63,7 @@ from pkg_resources import (
Distribution, PathMetadata, EggMetadata, WorkingSet, DistributionNotFound,
VersionConflict, DEVELOP_DIST,
)
-import pkg_resources.py31compat
+import pkg_resources
__metaclass__ = type
@@ -121,7 +120,8 @@ else:
return False
-_one_liner = lambda text: textwrap.dedent(text).strip().replace('\n', '; ')
+def _one_liner(text):
+ return textwrap.dedent(text).strip().replace('\n', '; ')
class easy_install(Command):
@@ -156,19 +156,16 @@ class easy_install(Command):
"allow building eggs from local checkouts"),
('version', None, "print version information and exit"),
('no-find-links', None,
- "Don't load find-links defined in packages being installed")
+ "Don't load find-links defined in packages being installed"),
+ ('user', None, "install in user site-package '%s'" % site.USER_SITE)
]
boolean_options = [
'zip-ok', 'multi-version', 'exclude-scripts', 'upgrade', 'always-copy',
'editable',
- 'no-deps', 'local-snapshots-ok', 'version'
+ 'no-deps', 'local-snapshots-ok', 'version',
+ 'user'
]
- if site.ENABLE_USER_SITE:
- help_msg = "install in user site-package '%s'" % site.USER_SITE
- user_options.append(('user', None, help_msg))
- boolean_options.append('user')
-
negative_opt = {'always-unzip': 'zip-ok'}
create_index = PackageIndex
@@ -208,7 +205,6 @@ class easy_install(Command):
self.pth_file = self.always_copy_from = None
self.site_dirs = None
self.installed_projects = {}
- self.sitepy_installed = False
# Always read easy_install options, even if we are subclassed, or have
# an independent instance created. This ensures that defaults will
# always come from the standard configuration file(s)' "easy_install"
@@ -241,7 +237,7 @@ class easy_install(Command):
"""
Render the Setuptools version and installation details, then exit.
"""
- ver = sys.version[:3]
+ ver = '{}.{}'.format(*sys.version_info)
dist = get_distribution('setuptools')
tmpl = 'setuptools {dist.version} from {dist.location} (Python {ver})'
print(tmpl.format(**locals()))
@@ -272,6 +268,9 @@ class easy_install(Command):
self.config_vars['userbase'] = self.install_userbase
self.config_vars['usersite'] = self.install_usersite
+ elif self.user:
+ log.warn("WARNING: The user site-packages directory is disabled.")
+
self._fix_install_dir_for_user_site()
self.expand_basedirs()
@@ -356,8 +355,10 @@ class easy_install(Command):
self.optimize = int(self.optimize)
if not (0 <= self.optimize <= 2):
raise ValueError
- except ValueError:
- raise DistutilsOptionError("--optimize must be 0, 1, or 2")
+ except ValueError as e:
+ raise DistutilsOptionError(
+ "--optimize must be 0, 1, or 2"
+ ) from e
if self.editable and not self.build_directory:
raise DistutilsArgError(
@@ -410,7 +411,13 @@ class easy_install(Command):
]
self._expand_attrs(dirs)
- def run(self):
+ def run(self, show_deprecation=True):
+ if show_deprecation:
+ self.announce(
+ "WARNING: The easy_install command is deprecated "
+ "and will be removed in a future version.",
+ log.WARN,
+ )
if self.verbose != self.distribution.verbose:
log.set_verbosity(self.verbose)
try:
@@ -453,6 +460,12 @@ class easy_install(Command):
instdir = normalize_path(self.install_dir)
pth_file = os.path.join(instdir, 'easy-install.pth')
+ if not os.path.exists(instdir):
+ try:
+ os.makedirs(instdir)
+ except (OSError, IOError):
+ self.cant_write_to_target()
+
# Is it a configured, PYTHONPATH, implicit, or explicit site dir?
is_site_dir = instdir in self.all_site_dirs
@@ -472,8 +485,9 @@ class easy_install(Command):
self.cant_write_to_target()
if not is_site_dir and not self.multi_version:
- # Can't install non-multi to non-site dir
- raise DistutilsError(self.no_default_version_msg())
+ # Can't install non-multi to non-site dir with easy_install
+ pythonpath = os.environ.get('PYTHONPATH', '')
+ log.warn(self.__no_default_msg, self.install_dir, pythonpath)
if is_site_dir:
if self.pth_file is None:
@@ -481,12 +495,8 @@ class easy_install(Command):
else:
self.pth_file = None
- if instdir not in map(normalize_path, _pythonpath()):
- # only PYTHONPATH dirs need a site.py, so pretend it's there
- self.sitepy_installed = True
- elif self.multi_version and not os.path.exists(pth_file):
- self.sitepy_installed = True # don't need site.py in this case
- self.pth_file = None # and don't create a .pth file
+ if self.multi_version and not os.path.exists(pth_file):
+ self.pth_file = None # don't create a .pth file
self.install_dir = instdir
__cant_write_msg = textwrap.dedent("""
@@ -501,13 +511,13 @@ class easy_install(Command):
the distutils default setting) was:
%s
- """).lstrip()
+ """).lstrip() # noqa
__not_exists_id = textwrap.dedent("""
This directory does not currently exist. Please create it and try again, or
choose a different installation directory (using the -d or --install-dir
option).
- """).lstrip()
+ """).lstrip() # noqa
__access_msg = textwrap.dedent("""
Perhaps your account does not have write access to this directory? If the
@@ -523,7 +533,7 @@ class easy_install(Command):
https://setuptools.readthedocs.io/en/latest/easy_install.html
Please make the appropriate changes for your system and try again.
- """).lstrip()
+ """).lstrip() # noqa
def cant_write_to_target(self):
msg = self.__cant_write_msg % (sys.exc_info()[1], self.install_dir,)
@@ -551,7 +561,7 @@ class easy_install(Command):
if ok_exists:
os.unlink(ok_file)
dirname = os.path.dirname(ok_file)
- pkg_resources.py31compat.makedirs(dirname, exist_ok=True)
+ os.makedirs(dirname, exist_ok=True)
f = open(pth_file, 'w')
except (OSError, IOError):
self.cant_write_to_target()
@@ -643,9 +653,6 @@ class easy_install(Command):
os.path.exists(tmpdir) and rmtree(rmtree_safe(tmpdir))
def easy_install(self, spec, deps=False):
- if not self.editable:
- self.install_site_py()
-
with self._tmpdir() as tmpdir:
if not isinstance(spec, Requirement):
if URL_SCHEME(spec):
@@ -752,9 +759,9 @@ class easy_install(Command):
[requirement], self.local_index, self.easy_install
)
except DistributionNotFound as e:
- raise DistutilsError(str(e))
+ raise DistutilsError(str(e)) from e
except VersionConflict as e:
- raise DistutilsError(e.report())
+ raise DistutilsError(e.report()) from e
if self.always_copy or self.always_copy_from:
# Force all the relevant distros to be copied or activated
for dist in distros:
@@ -1087,13 +1094,13 @@ class easy_install(Command):
pkg_resources.require("%(name)s") # latest installed version
pkg_resources.require("%(name)s==%(version)s") # this exact version
pkg_resources.require("%(name)s>=%(version)s") # this version or higher
- """).lstrip()
+ """).lstrip() # noqa
__id_warning = textwrap.dedent("""
Note also that the installation directory must be on sys.path at runtime for
this to work. (e.g. by being the application's script directory, by being on
PYTHONPATH, or by being added to sys.path by your code.)
- """)
+ """) # noqa
def installation_report(self, req, dist, what="Installed"):
"""Helpful installation message for display to package users"""
@@ -1118,7 +1125,7 @@ class easy_install(Command):
%(python)s setup.py develop
See the setuptools documentation for the "develop" command for more info.
- """).lstrip()
+ """).lstrip() # noqa
def report_editable(self, spec, setup_script):
dirname = os.path.dirname(setup_script)
@@ -1143,7 +1150,9 @@ class easy_install(Command):
try:
run_setup(setup_script, args)
except SystemExit as v:
- raise DistutilsError("Setup script exited with %s" % (v.args[0],))
+ raise DistutilsError(
+ "Setup script exited with %s" % (v.args[0],)
+ ) from v
def build_and_install(self, setup_script, setup_base):
args = ['bdist_egg', '--dist-dir']
@@ -1180,8 +1189,7 @@ class easy_install(Command):
# to the setup.cfg file.
ei_opts = self.distribution.get_option_dict('easy_install').copy()
fetch_directives = (
- 'find_links', 'site_dirs', 'index_url', 'optimize',
- 'site_dirs', 'allow_hosts',
+ 'find_links', 'site_dirs', 'index_url', 'optimize', 'allow_hosts',
)
fetch_options = {}
for key, val in ei_opts.items():
@@ -1302,43 +1310,8 @@ class easy_install(Command):
https://setuptools.readthedocs.io/en/latest/easy_install.html#custom-installation-locations
- Please make the appropriate changes for your system and try again.""").lstrip()
-
- def no_default_version_msg(self):
- template = self.__no_default_msg
- return template % (self.install_dir, os.environ.get('PYTHONPATH', ''))
-
- def install_site_py(self):
- """Make sure there's a site.py in the target dir, if needed"""
-
- if self.sitepy_installed:
- return # already did it, or don't need to
-
- sitepy = os.path.join(self.install_dir, "site.py")
- source = resource_string("setuptools", "site-patch.py")
- source = source.decode('utf-8')
- current = ""
-
- if os.path.exists(sitepy):
- log.debug("Checking existing site.py in %s", self.install_dir)
- with io.open(sitepy) as strm:
- current = strm.read()
-
- if not current.startswith('def __boot():'):
- raise DistutilsError(
- "%s is not a setuptools-generated site.py; please"
- " remove it." % sitepy
- )
-
- if current != source:
- log.info("Creating %s", sitepy)
- if not self.dry_run:
- ensure_directory(sitepy)
- with io.open(sitepy, 'w', encoding='utf-8') as strm:
- strm.write(source)
- self.byte_compile([sitepy])
-
- self.sitepy_installed = True
+ Please make the appropriate changes for your system and try again.
+ """).strip()
def create_home_path(self):
"""Create directories under ~."""
@@ -1412,7 +1385,7 @@ def get_site_dirs():
os.path.join(
prefix,
"lib",
- "python" + sys.version[:3],
+ "python{}.{}".format(*sys.version_info),
"site-packages",
),
os.path.join(prefix, "lib", "site-python"),
@@ -1433,7 +1406,7 @@ def get_site_dirs():
home,
'Library',
'Python',
- sys.version[:3],
+ '{}.{}'.format(*sys.version_info),
'site-packages',
)
sitedirs.append(home_sp)
@@ -1562,7 +1535,7 @@ def get_exe_prefixes(exe_filename):
continue
if parts[0].upper() in ('PURELIB', 'PLATLIB'):
contents = z.read(name)
- if six.PY3:
+ if not six.PY2:
contents = contents.decode()
for pth in yield_lines(contents):
pth = pth.strip().replace('\\', '/')
@@ -2063,17 +2036,38 @@ class ScriptWriter:
template = textwrap.dedent(r"""
# EASY-INSTALL-ENTRY-SCRIPT: %(spec)r,%(group)r,%(name)r
- __requires__ = %(spec)r
import re
import sys
- from pkg_resources import load_entry_point
+
+ # for compatibility with easy_install; see #2198
+ __requires__ = %(spec)r
+
+ try:
+ from importlib.metadata import distribution
+ except ImportError:
+ try:
+ from importlib_metadata import distribution
+ except ImportError:
+ from pkg_resources import load_entry_point
+
+
+ def importlib_load_entry_point(spec, group, name):
+ dist_name, _, _ = spec.partition('==')
+ matches = (
+ entry_point
+ for entry_point in distribution(dist_name).entry_points
+ if entry_point.group == group and entry_point.name == name
+ )
+ return next(matches).load()
+
+
+ globals().setdefault('load_entry_point', importlib_load_entry_point)
+
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])
- sys.exit(
- load_entry_point(%(spec)r, %(group)r, %(name)r)()
- )
- """).lstrip()
+ sys.exit(load_entry_point(%(spec)r, %(group)r, %(name)r)())
+ """).lstrip()
command_spec_class = CommandSpec
@@ -2088,7 +2082,8 @@ class ScriptWriter:
@classmethod
def get_script_header(cls, script_text, executable=None, wininst=False):
# for backward compatibility
- warnings.warn("Use get_header", EasyInstallDeprecationWarning, stacklevel=2)
+ warnings.warn(
+ "Use get_header", EasyInstallDeprecationWarning, stacklevel=2)
if wininst:
executable = "python.exe"
return cls.get_header(script_text, executable)
@@ -2337,6 +2332,8 @@ def _patch_usage():
finally:
distutils.core.gen_usage = saved
+
class EasyInstallDeprecationWarning(SetuptoolsDeprecationWarning):
- """Class for warning about deprecations in EasyInstall in SetupTools. Not ignored by default, unlike DeprecationWarning."""
-
+ """
+ Warning for EasyInstall deprecations, bypassing suppression.
+ """
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/egg_info.py b/venv/lib/python3.8/site-packages/setuptools/command/egg_info.py
index 5d8f451..0855207 100644
--- a/venv/lib/python3.8/site-packages/setuptools/command/egg_info.py
+++ b/venv/lib/python3.8/site-packages/setuptools/command/egg_info.py
@@ -33,6 +33,7 @@ from setuptools.glob import glob
from setuptools.extern import packaging
from setuptools import SetuptoolsDeprecationWarning
+
def translate_pattern(glob):
"""
Translate a file path glob like '*.txt' in to a regular expression.
@@ -113,7 +114,7 @@ def translate_pattern(glob):
pat += sep
pat += r'\Z'
- return re.compile(pat, flags=re.MULTILINE|re.DOTALL)
+ return re.compile(pat, flags=re.MULTILINE | re.DOTALL)
class InfoCommon:
@@ -207,11 +208,11 @@ class egg_info(InfoCommon, Command):
list(
parse_requirements(spec % (self.egg_name, self.egg_version))
)
- except ValueError:
+ except ValueError as e:
raise distutils.errors.DistutilsOptionError(
"Invalid distribution name or version syntax: %s-%s" %
(self.egg_name, self.egg_version)
- )
+ ) from e
if self.egg_base is None:
dirs = self.distribution.package_dir
@@ -266,7 +267,7 @@ class egg_info(InfoCommon, Command):
to the file.
"""
log.info("writing %s to %s", what, filename)
- if six.PY3:
+ if not six.PY2:
data = data.encode("utf-8")
if not self.dry_run:
f = open(filename, 'wb')
@@ -637,7 +638,9 @@ def warn_depends_obsolete(cmd, basename, filename):
def _write_requirements(stream, reqs):
lines = yield_lines(reqs or ())
- append_cr = lambda line: line + '\n'
+
+ def append_cr(line):
+ return line + '\n'
lines = map(append_cr, lines)
stream.writelines(lines)
@@ -703,7 +706,8 @@ def get_pkg_info_revision():
Get a -r### off of PKG-INFO Version in case this is an sdist of
a subversion revision.
"""
- warnings.warn("get_pkg_info_revision is deprecated.", EggInfoDeprecationWarning)
+ warnings.warn(
+ "get_pkg_info_revision is deprecated.", EggInfoDeprecationWarning)
if os.path.exists('PKG-INFO'):
with io.open('PKG-INFO') as f:
for line in f:
@@ -714,4 +718,4 @@ def get_pkg_info_revision():
class EggInfoDeprecationWarning(SetuptoolsDeprecationWarning):
- """Class for warning about deprecations in eggInfo in setupTools. Not ignored by default, unlike DeprecationWarning."""
+ """Deprecated behavior warning for EggInfo, bypassing suppression."""
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/install.py b/venv/lib/python3.8/site-packages/setuptools/command/install.py
index 31a5ddb..72b9a3e 100644
--- a/venv/lib/python3.8/site-packages/setuptools/command/install.py
+++ b/venv/lib/python3.8/site-packages/setuptools/command/install.py
@@ -114,7 +114,7 @@ class install(orig.install):
args.insert(0, setuptools.bootstrap_install_from)
cmd.args = args
- cmd.run()
+ cmd.run(show_deprecation=False)
setuptools.bootstrap_install_from = None
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/install_lib.py b/venv/lib/python3.8/site-packages/setuptools/command/install_lib.py
index 07d6593..2e9d875 100644
--- a/venv/lib/python3.8/site-packages/setuptools/command/install_lib.py
+++ b/venv/lib/python3.8/site-packages/setuptools/command/install_lib.py
@@ -77,7 +77,8 @@ class install_lib(orig.install_lib):
if not hasattr(sys, 'implementation'):
return
- base = os.path.join('__pycache__', '__init__.' + sys.implementation.cache_tag)
+ base = os.path.join(
+ '__pycache__', '__init__.' + sys.implementation.cache_tag)
yield base + '.pyc'
yield base + '.pyo'
yield base + '.opt-1.pyc'
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/install_scripts.py b/venv/lib/python3.8/site-packages/setuptools/command/install_scripts.py
index 1623427..8c9a15e 100644
--- a/venv/lib/python3.8/site-packages/setuptools/command/install_scripts.py
+++ b/venv/lib/python3.8/site-packages/setuptools/command/install_scripts.py
@@ -32,8 +32,11 @@ class install_scripts(orig.install_scripts):
)
bs_cmd = self.get_finalized_command('build_scripts')
exec_param = getattr(bs_cmd, 'executable', None)
- bw_cmd = self.get_finalized_command("bdist_wininst")
- is_wininst = getattr(bw_cmd, '_is_running', False)
+ try:
+ bw_cmd = self.get_finalized_command("bdist_wininst")
+ is_wininst = getattr(bw_cmd, '_is_running', False)
+ except ImportError:
+ is_wininst = False
writer = ei.ScriptWriter
if is_wininst:
exec_param = "python.exe"
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/py36compat.py b/venv/lib/python3.8/site-packages/setuptools/command/py36compat.py
index 61063e7..2886055 100644
--- a/venv/lib/python3.8/site-packages/setuptools/command/py36compat.py
+++ b/venv/lib/python3.8/site-packages/setuptools/command/py36compat.py
@@ -132,5 +132,5 @@ class sdist_add_defaults:
if hasattr(sdist.sdist, '_add_defaults_standards'):
# disable the functionality already available upstream
- class sdist_add_defaults:
+ class sdist_add_defaults: # noqa
pass
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/register.py b/venv/lib/python3.8/site-packages/setuptools/command/register.py
index 98bc015..b8266b9 100644
--- a/venv/lib/python3.8/site-packages/setuptools/command/register.py
+++ b/venv/lib/python3.8/site-packages/setuptools/command/register.py
@@ -1,18 +1,18 @@
from distutils import log
import distutils.command.register as orig
+from setuptools.errors import RemovedCommandError
+
class register(orig.register):
- __doc__ = orig.register.__doc__
+ """Formerly used to register packages on PyPI."""
def run(self):
- try:
- # Make sure that we are using valid current name/version info
- self.run_command('egg_info')
- orig.register.run(self)
- finally:
- self.announce(
- "WARNING: Registering is deprecated, use twine to "
- "upload instead (https://pypi.org/p/twine/)",
- log.WARN
- )
+ msg = (
+ "The register command has been removed, use twine to upload "
+ + "instead (https://pypi.org/p/twine)"
+ )
+
+ self.announce("ERROR: " + msg, log.ERROR)
+
+ raise RemovedCommandError(msg)
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/rotate.py b/venv/lib/python3.8/site-packages/setuptools/command/rotate.py
index b89353f..e398834 100644
--- a/venv/lib/python3.8/site-packages/setuptools/command/rotate.py
+++ b/venv/lib/python3.8/site-packages/setuptools/command/rotate.py
@@ -36,8 +36,8 @@ class rotate(Command):
raise DistutilsOptionError("Must specify number of files to keep")
try:
self.keep = int(self.keep)
- except ValueError:
- raise DistutilsOptionError("--keep must be an integer")
+ except ValueError as e:
+ raise DistutilsOptionError("--keep must be an integer") from e
if isinstance(self.match, six.string_types):
self.match = [
convert_path(p.strip()) for p in self.match.split(',')
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/sdist.py b/venv/lib/python3.8/site-packages/setuptools/command/sdist.py
index dc25398..8c3438e 100644
--- a/venv/lib/python3.8/site-packages/setuptools/command/sdist.py
+++ b/venv/lib/python3.8/site-packages/setuptools/command/sdist.py
@@ -5,7 +5,7 @@ import sys
import io
import contextlib
-from setuptools.extern import six
+from setuptools.extern import six, ordered_set
from .py36compat import sdist_add_defaults
@@ -121,19 +121,40 @@ class sdist(sdist_add_defaults, orig.sdist):
if has_leaky_handle:
read_template = __read_template_hack
+ def _add_defaults_optional(self):
+ if six.PY2:
+ sdist_add_defaults._add_defaults_optional(self)
+ else:
+ super()._add_defaults_optional()
+ if os.path.isfile('pyproject.toml'):
+ self.filelist.append('pyproject.toml')
+
def _add_defaults_python(self):
"""getting python files"""
if self.distribution.has_pure_modules():
build_py = self.get_finalized_command('build_py')
self.filelist.extend(build_py.get_source_files())
- # This functionality is incompatible with include_package_data, and
- # will in fact create an infinite recursion if include_package_data
- # is True. Use of include_package_data will imply that
- # distutils-style automatic handling of package_data is disabled
- if not self.distribution.include_package_data:
- for _, src_dir, _, filenames in build_py.data_files:
- self.filelist.extend([os.path.join(src_dir, filename)
- for filename in filenames])
+ self._add_data_files(self._safe_data_files(build_py))
+
+ def _safe_data_files(self, build_py):
+ """
+ Extracting data_files from build_py is known to cause
+ infinite recursion errors when `include_package_data`
+ is enabled, so suppress it in that case.
+ """
+ if self.distribution.include_package_data:
+ return ()
+ return build_py.data_files
+
+ def _add_data_files(self, data_files):
+ """
+ Add data files as found in build_py.data_files.
+ """
+ self.filelist.extend(
+ os.path.join(src_dir, name)
+ for _, src_dir, _, filenames in data_files
+ for name in filenames
+ )
def _add_defaults_data_files(self):
try:
@@ -186,7 +207,7 @@ class sdist(sdist_add_defaults, orig.sdist):
manifest = open(self.manifest, 'rb')
for line in manifest:
# The manifest must contain UTF-8. See #303.
- if six.PY3:
+ if not six.PY2:
try:
line = line.decode('UTF-8')
except UnicodeDecodeError:
@@ -200,10 +221,12 @@ class sdist(sdist_add_defaults, orig.sdist):
manifest.close()
def check_license(self):
- """Checks if license_file' is configured and adds it to
- 'self.filelist' if the value contains a valid path.
+ """Checks if license_file' or 'license_files' is configured and adds any
+ valid paths to 'self.filelist'.
"""
+ files = ordered_set.OrderedSet()
+
opts = self.distribution.get_option_dict('metadata')
# ignore the source of the value
@@ -211,11 +234,19 @@ class sdist(sdist_add_defaults, orig.sdist):
if license_file is None:
log.debug("'license_file' option was not specified")
- return
+ else:
+ files.add(license_file)
- if not os.path.exists(license_file):
- log.warn("warning: Failed to find the configured license file '%s'",
- license_file)
- return
+ try:
+ files.update(self.distribution.metadata.license_files)
+ except TypeError:
+ log.warn("warning: 'license_files' option is malformed")
- self.filelist.append(license_file)
+ for f in files:
+ if not os.path.exists(f):
+ log.warn(
+ "warning: Failed to find the configured license file '%s'",
+ f)
+ files.remove(f)
+
+ self.filelist.extend(files)
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/test.py b/venv/lib/python3.8/site-packages/setuptools/command/test.py
index 973e4eb..2d83967 100644
--- a/venv/lib/python3.8/site-packages/setuptools/command/test.py
+++ b/venv/lib/python3.8/site-packages/setuptools/command/test.py
@@ -74,7 +74,7 @@ class NonDataProperty:
class test(Command):
"""Command to run unit tests after in-place build"""
- description = "run unit tests after in-place build"
+ description = "run unit tests after in-place build (deprecated)"
user_options = [
('test-module=', 'm', "Run 'test_suite' in specified module"),
@@ -129,7 +129,8 @@ class test(Command):
@contextlib.contextmanager
def project_on_sys_path(self, include_dists=[]):
- with_2to3 = six.PY3 and getattr(self.distribution, 'use_2to3', False)
+ with_2to3 = not six.PY2 and getattr(
+ self.distribution, 'use_2to3', False)
if with_2to3:
# If we run 2to3 we can not do this inplace:
@@ -214,6 +215,14 @@ class test(Command):
return itertools.chain(ir_d, tr_d, er_d)
def run(self):
+ self.announce(
+ "WARNING: Testing via this command is deprecated and will be "
+ "removed in a future version. Users looking for a generic test "
+ "entry point independent of test runner are encouraged to use "
+ "tox.",
+ log.WARN,
+ )
+
installed_dists = self.install_dists(self.distribution)
cmd = ' '.join(self._argv)
@@ -232,7 +241,7 @@ class test(Command):
# Purge modules under test from sys.modules. The test loader will
# re-import them from the build location. Required when 2to3 is used
# with namespace packages.
- if six.PY3 and getattr(self.distribution, 'use_2to3', False):
+ if not six.PY2 and getattr(self.distribution, 'use_2to3', False):
module = self.test_suite.split('.')[0]
if module in _namespace_packages:
del_modules = []
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/upload.py b/venv/lib/python3.8/site-packages/setuptools/command/upload.py
index 6db8888..ec7f81e 100644
--- a/venv/lib/python3.8/site-packages/setuptools/command/upload.py
+++ b/venv/lib/python3.8/site-packages/setuptools/command/upload.py
@@ -1,196 +1,17 @@
-import io
-import os
-import hashlib
-import getpass
-
-from base64 import standard_b64encode
-
from distutils import log
from distutils.command import upload as orig
-from distutils.spawn import spawn
-from distutils.errors import DistutilsError
-
-from setuptools.extern.six.moves.urllib.request import urlopen, Request
-from setuptools.extern.six.moves.urllib.error import HTTPError
-from setuptools.extern.six.moves.urllib.parse import urlparse
+from setuptools.errors import RemovedCommandError
class upload(orig.upload):
- """
- Override default upload behavior to obtain password
- in a variety of different ways.
- """
+ """Formerly used to upload packages to PyPI."""
+
def run(self):
- try:
- orig.upload.run(self)
- finally:
- self.announce(
- "WARNING: Uploading via this command is deprecated, use twine "
- "to upload instead (https://pypi.org/p/twine/)",
- log.WARN
- )
-
- def finalize_options(self):
- orig.upload.finalize_options(self)
- self.username = (
- self.username or
- getpass.getuser()
- )
- # Attempt to obtain password. Short circuit evaluation at the first
- # sign of success.
- self.password = (
- self.password or
- self._load_password_from_keyring() or
- self._prompt_for_password()
+ msg = (
+ "The upload command has been removed, use twine to upload "
+ + "instead (https://pypi.org/p/twine)"
)
- def upload_file(self, command, pyversion, filename):
- # Makes sure the repository URL is compliant
- schema, netloc, url, params, query, fragments = \
- urlparse(self.repository)
- if params or query or fragments:
- raise AssertionError("Incompatible url %s" % self.repository)
-
- if schema not in ('http', 'https'):
- raise AssertionError("unsupported schema " + schema)
-
- # Sign if requested
- if self.sign:
- gpg_args = ["gpg", "--detach-sign", "-a", filename]
- if self.identity:
- gpg_args[2:2] = ["--local-user", self.identity]
- spawn(gpg_args,
- dry_run=self.dry_run)
-
- # Fill in the data - send all the meta-data in case we need to
- # register a new release
- with open(filename, 'rb') as f:
- content = f.read()
-
- meta = self.distribution.metadata
-
- data = {
- # action
- ':action': 'file_upload',
- 'protocol_version': '1',
-
- # identify release
- 'name': meta.get_name(),
- 'version': meta.get_version(),
-
- # file content
- 'content': (os.path.basename(filename), content),
- 'filetype': command,
- 'pyversion': pyversion,
- 'md5_digest': hashlib.md5(content).hexdigest(),
-
- # additional meta-data
- 'metadata_version': str(meta.get_metadata_version()),
- 'summary': meta.get_description(),
- 'home_page': meta.get_url(),
- 'author': meta.get_contact(),
- 'author_email': meta.get_contact_email(),
- 'license': meta.get_licence(),
- 'description': meta.get_long_description(),
- 'keywords': meta.get_keywords(),
- 'platform': meta.get_platforms(),
- 'classifiers': meta.get_classifiers(),
- 'download_url': meta.get_download_url(),
- # PEP 314
- 'provides': meta.get_provides(),
- 'requires': meta.get_requires(),
- 'obsoletes': meta.get_obsoletes(),
- }
-
- data['comment'] = ''
-
- if self.sign:
- data['gpg_signature'] = (os.path.basename(filename) + ".asc",
- open(filename+".asc", "rb").read())
-
- # set up the authentication
- user_pass = (self.username + ":" + self.password).encode('ascii')
- # The exact encoding of the authentication string is debated.
- # Anyway PyPI only accepts ascii for both username or password.
- auth = "Basic " + standard_b64encode(user_pass).decode('ascii')
-
- # Build up the MIME payload for the POST data
- boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
- sep_boundary = b'\r\n--' + boundary.encode('ascii')
- end_boundary = sep_boundary + b'--\r\n'
- body = io.BytesIO()
- for key, value in data.items():
- title = '\r\nContent-Disposition: form-data; name="%s"' % key
- # handle multiple entries for the same name
- if not isinstance(value, list):
- value = [value]
- for value in value:
- if type(value) is tuple:
- title += '; filename="%s"' % value[0]
- value = value[1]
- else:
- value = str(value).encode('utf-8')
- body.write(sep_boundary)
- body.write(title.encode('utf-8'))
- body.write(b"\r\n\r\n")
- body.write(value)
- body.write(end_boundary)
- body = body.getvalue()
-
- msg = "Submitting %s to %s" % (filename, self.repository)
- self.announce(msg, log.INFO)
-
- # build the Request
- headers = {
- 'Content-type': 'multipart/form-data; boundary=%s' % boundary,
- 'Content-length': str(len(body)),
- 'Authorization': auth,
- }
-
- request = Request(self.repository, data=body,
- headers=headers)
- # send the data
- try:
- result = urlopen(request)
- status = result.getcode()
- reason = result.msg
- except HTTPError as e:
- status = e.code
- reason = e.msg
- except OSError as e:
- self.announce(str(e), log.ERROR)
- raise
-
- if status == 200:
- self.announce('Server response (%s): %s' % (status, reason),
- log.INFO)
- if self.show_response:
- text = getattr(self, '_read_pypi_response',
- lambda x: None)(result)
- if text is not None:
- msg = '\n'.join(('-' * 75, text, '-' * 75))
- self.announce(msg, log.INFO)
- else:
- msg = 'Upload failed (%s): %s' % (status, reason)
- self.announce(msg, log.ERROR)
- raise DistutilsError(msg)
-
- def _load_password_from_keyring(self):
- """
- Attempt to load password from keyring. Suppress Exceptions.
- """
- try:
- keyring = __import__('keyring')
- return keyring.get_password(self.repository, self.username)
- except Exception:
- pass
-
- def _prompt_for_password(self):
- """
- Prompt for a password on the tty. Suppress Exceptions.
- """
- try:
- return getpass.getpass()
- except (Exception, KeyboardInterrupt):
- pass
+ self.announce("ERROR: " + msg, log.ERROR)
+ raise RemovedCommandError(msg)
diff --git a/venv/lib/python3.8/site-packages/setuptools/command/upload_docs.py b/venv/lib/python3.8/site-packages/setuptools/command/upload_docs.py
index 07aa564..0351da7 100644
--- a/venv/lib/python3.8/site-packages/setuptools/command/upload_docs.py
+++ b/venv/lib/python3.8/site-packages/setuptools/command/upload_docs.py
@@ -24,7 +24,7 @@ from .upload import upload
def _encode(s):
- errors = 'surrogateescape' if six.PY3 else 'strict'
+ errors = 'strict' if six.PY2 else 'surrogateescape'
return s.encode('utf-8', errors)
@@ -127,8 +127,8 @@ class upload_docs(upload):
"""
Build up the MIME payload for the POST data
"""
- boundary = b'--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
- sep_boundary = b'\n--' + boundary
+ boundary = '--------------GHSKFJDLGDS7543FJKLFHRE75642756743254'
+ sep_boundary = b'\n--' + boundary.encode('ascii')
end_boundary = sep_boundary + b'--'
end_items = end_boundary, b"\n",
builder = functools.partial(
@@ -138,7 +138,7 @@ class upload_docs(upload):
part_groups = map(builder, data.items())
parts = itertools.chain.from_iterable(part_groups)
body_items = itertools.chain(parts, end_items)
- content_type = 'multipart/form-data; boundary=%s' % boundary.decode('ascii')
+ content_type = 'multipart/form-data; boundary=%s' % boundary
return b''.join(body_items), content_type
def upload_file(self, filename):
@@ -153,7 +153,7 @@ class upload_docs(upload):
# set up the authentication
credentials = _encode(self.username + ':' + self.password)
credentials = standard_b64encode(credentials)
- if six.PY3:
+ if not six.PY2:
credentials = credentials.decode('ascii')
auth = "Basic " + credentials
diff --git a/venv/lib/python3.8/site-packages/setuptools/config.py b/venv/lib/python3.8/site-packages/setuptools/config.py
index b662604..a8f8b6b 100644
--- a/venv/lib/python3.8/site-packages/setuptools/config.py
+++ b/venv/lib/python3.8/site-packages/setuptools/config.py
@@ -1,23 +1,65 @@
from __future__ import absolute_import, unicode_literals
+import ast
import io
import os
import sys
import warnings
import functools
+import importlib
from collections import defaultdict
from functools import partial
from functools import wraps
-from importlib import import_module
+import contextlib
from distutils.errors import DistutilsOptionError, DistutilsFileError
from setuptools.extern.packaging.version import LegacyVersion, parse
+from setuptools.extern.packaging.specifiers import SpecifierSet
from setuptools.extern.six import string_types, PY3
__metaclass__ = type
+class StaticModule:
+ """
+ Attempt to load the module by the name
+ """
+ def __init__(self, name):
+ spec = importlib.util.find_spec(name)
+ with open(spec.origin) as strm:
+ src = strm.read()
+ module = ast.parse(src)
+ vars(self).update(locals())
+ del self.self
+
+ def __getattr__(self, attr):
+ try:
+ return next(
+ ast.literal_eval(statement.value)
+ for statement in self.module.body
+ if isinstance(statement, ast.Assign)
+ for target in statement.targets
+ if isinstance(target, ast.Name) and target.id == attr
+ )
+ except Exception as e:
+ raise AttributeError(
+ "{self.name} has no attribute {attr}".format(**locals())
+ ) from e
+
+
+@contextlib.contextmanager
+def patch_path(path):
+ """
+ Add path to front of sys.path for the duration of the context.
+ """
+ try:
+ sys.path.insert(0, path)
+ yield
+ finally:
+ sys.path.remove(path)
+
+
def read_configuration(
filepath, find_others=False, ignore_option_errors=False):
"""Read given configuration file and returns options from it as a dict.
@@ -343,15 +385,16 @@ class ConfigHandler:
elif '' in package_dir:
# A custom parent directory was specified for all root modules
parent_path = os.path.join(os.getcwd(), package_dir[''])
- sys.path.insert(0, parent_path)
- try:
- module = import_module(module_name)
- value = getattr(module, attr_name)
- finally:
- sys.path = sys.path[1:]
+ with patch_path(parent_path):
+ try:
+ # attempt to load value statically
+ return getattr(StaticModule(module_name), attr_name)
+ except Exception:
+ # fallback to simple import
+ module = importlib.import_module(module_name)
- return value
+ return getattr(module, attr_name)
@classmethod
def _get_parser_compound(cls, *parse_methods):
@@ -482,6 +525,7 @@ class ConfigMetadataHandler(ConfigHandler):
'obsoletes': parse_list,
'classifiers': self._get_parser_compound(parse_file, parse_list),
'license': exclude_files_parser('license'),
+ 'license_files': parse_list,
'description': parse_file,
'long_description': parse_file,
'version': self._parse_version,
@@ -554,6 +598,7 @@ class ConfigOptionsHandler(ConfigHandler):
'packages': self._parse_packages,
'entry_points': self._parse_file,
'py_modules': parse_list,
+ 'python_requires': SpecifierSet,
}
def _parse_packages(self, value):
diff --git a/venv/lib/python3.8/site-packages/setuptools/dep_util.py b/venv/lib/python3.8/site-packages/setuptools/dep_util.py
index 2931c13..521eb71 100644
--- a/venv/lib/python3.8/site-packages/setuptools/dep_util.py
+++ b/venv/lib/python3.8/site-packages/setuptools/dep_util.py
@@ -1,5 +1,6 @@
from distutils.dep_util import newer_group
+
# yes, this is was almost entirely copy-pasted from
# 'newer_pairwise()', this is just another convenience
# function.
@@ -10,7 +11,8 @@ def newer_pairwise_group(sources_groups, targets):
of 'newer_group()'.
"""
if len(sources_groups) != len(targets):
- raise ValueError("'sources_group' and 'targets' must be the same length")
+ raise ValueError(
+ "'sources_group' and 'targets' must be the same length")
# build a pair of lists (sources_groups, targets) where source is newer
n_sources = []
diff --git a/venv/lib/python3.8/site-packages/setuptools/depends.py b/venv/lib/python3.8/site-packages/setuptools/depends.py
index 45e7052..a37675c 100644
--- a/venv/lib/python3.8/site-packages/setuptools/depends.py
+++ b/venv/lib/python3.8/site-packages/setuptools/depends.py
@@ -1,11 +1,13 @@
import sys
-import imp
import marshal
+import contextlib
from distutils.version import StrictVersion
-from imp import PKG_DIRECTORY, PY_COMPILED, PY_SOURCE, PY_FROZEN
from .py33compat import Bytecode
+from .py27compat import find_module, PY_COMPILED, PY_FROZEN, PY_SOURCE
+from . import py27compat
+
__all__ = [
'Require', 'find_module', 'get_module_constant', 'extract_constant'
@@ -15,7 +17,8 @@ __all__ = [
class Require:
"""A prerequisite to building or installing a distribution"""
- def __init__(self, name, requested_version, module, homepage='',
+ def __init__(
+ self, name, requested_version, module, homepage='',
attribute=None, format=None):
if format is None and requested_version is not None:
@@ -79,23 +82,15 @@ class Require:
return self.version_ok(version)
-def find_module(module, paths=None):
- """Just like 'imp.find_module()', but with package support"""
+def maybe_close(f):
+ @contextlib.contextmanager
+ def empty():
+ yield
+ return
+ if not f:
+ return empty()
- parts = module.split('.')
-
- while parts:
- part = parts.pop(0)
- f, path, (suffix, mode, kind) = info = imp.find_module(part, paths)
-
- if kind == PKG_DIRECTORY:
- parts = parts or ['__init__']
- paths = [path]
-
- elif parts:
- raise ImportError("Can't find %r in %s" % (parts, module))
-
- return info
+ return contextlib.closing(f)
def get_module_constant(module, symbol, default=-1, paths=None):
@@ -106,28 +101,23 @@ def get_module_constant(module, symbol, default=-1, paths=None):
constant. Otherwise, return 'default'."""
try:
- f, path, (suffix, mode, kind) = find_module(module, paths)
+ f, path, (suffix, mode, kind) = info = find_module(module, paths)
except ImportError:
# Module doesn't exist
return None
- try:
+ with maybe_close(f):
if kind == PY_COMPILED:
f.read(8) # skip magic & date
code = marshal.load(f)
elif kind == PY_FROZEN:
- code = imp.get_frozen_object(module)
+ code = py27compat.get_frozen_object(module, paths)
elif kind == PY_SOURCE:
code = compile(f.read(), path, 'exec')
else:
# Not something we can parse; we'll have to import it. :(
- if module not in sys.modules:
- imp.load_module(module, f, path, (suffix, mode, kind))
- return getattr(sys.modules[module], symbol, None)
-
- finally:
- if f:
- f.close()
+ imported = py27compat.get_module(module, paths, info)
+ return getattr(imported, symbol, None)
return extract_constant(code, symbol, default)
diff --git a/venv/lib/python3.8/site-packages/setuptools/dist.py b/venv/lib/python3.8/site-packages/setuptools/dist.py
index f0f030b..e813b11 100644
--- a/venv/lib/python3.8/site-packages/setuptools/dist.py
+++ b/venv/lib/python3.8/site-packages/setuptools/dist.py
@@ -19,19 +19,18 @@ import itertools
from collections import defaultdict
from email import message_from_file
-from distutils.errors import (
- DistutilsOptionError, DistutilsPlatformError, DistutilsSetupError,
-)
+from distutils.errors import DistutilsOptionError, DistutilsSetupError
from distutils.util import rfc822_escape
from distutils.version import StrictVersion
from setuptools.extern import six
from setuptools.extern import packaging
+from setuptools.extern import ordered_set
from setuptools.extern.six.moves import map, filter, filterfalse
from . import SetuptoolsDeprecationWarning
-from setuptools.depends import Require
+import setuptools
from setuptools import windows_support
from setuptools.monkey import get_unpatched
from setuptools.config import parse_configuration
@@ -161,7 +160,7 @@ def write_pkg_file(self, file):
if self.download_url:
write_field('Download-URL', self.download_url)
for project_url in self.project_urls.items():
- write_field('Project-URL', '%s, %s' % project_url)
+ write_field('Project-URL', '%s, %s' % project_url)
long_desc = rfc822_escape(self.get_long_description())
write_field('Description', long_desc)
@@ -205,11 +204,11 @@ def check_importable(dist, attr, value):
try:
ep = pkg_resources.EntryPoint.parse('x=' + value)
assert not ep.extras
- except (TypeError, ValueError, AttributeError, AssertionError):
+ except (TypeError, ValueError, AttributeError, AssertionError) as e:
raise DistutilsSetupError(
"%r must be importable 'module:attrs' string (got %r)"
% (attr, value)
- )
+ ) from e
def assert_string_list(dist, attr, value):
@@ -220,10 +219,10 @@ def assert_string_list(dist, attr, value):
assert isinstance(value, (list, tuple))
# verify that elements of value are strings
assert ''.join(value) != value
- except (TypeError, ValueError, AttributeError, AssertionError):
+ except (TypeError, ValueError, AttributeError, AssertionError) as e:
raise DistutilsSetupError(
"%r must be a list of strings (got %r)" % (attr, value)
- )
+ ) from e
def check_nsp(dist, attr, value):
@@ -248,12 +247,12 @@ def check_extras(dist, attr, value):
"""Verify that extras_require mapping is valid"""
try:
list(itertools.starmap(_check_extra, value.items()))
- except (TypeError, ValueError, AttributeError):
+ except (TypeError, ValueError, AttributeError) as e:
raise DistutilsSetupError(
"'extras_require' must be a dictionary whose values are "
"strings or lists of strings containing valid project/version "
"requirement specifiers."
- )
+ ) from e
def _check_extra(extra, reqs):
@@ -281,7 +280,9 @@ def check_requirements(dist, attr, value):
"{attr!r} must be a string or list of strings "
"containing valid project/version requirement specifiers; {error}"
)
- raise DistutilsSetupError(tmpl.format(attr=attr, error=error))
+ raise DistutilsSetupError(
+ tmpl.format(attr=attr, error=error)
+ ) from error
def check_specifier(dist, attr, value):
@@ -293,7 +294,9 @@ def check_specifier(dist, attr, value):
"{attr!r} must be a string "
"containing valid version specifiers; {error}"
)
- raise DistutilsSetupError(tmpl.format(attr=attr, error=error))
+ raise DistutilsSetupError(
+ tmpl.format(attr=attr, error=error)
+ ) from error
def check_entry_points(dist, attr, value):
@@ -301,7 +304,7 @@ def check_entry_points(dist, attr, value):
try:
pkg_resources.EntryPoint.parse_map(value)
except ValueError as e:
- raise DistutilsSetupError(e)
+ raise DistutilsSetupError(e) from e
def check_test_suite(dist, attr, value):
@@ -337,7 +340,7 @@ _Distribution = get_unpatched(distutils.core.Distribution)
class Distribution(_Distribution):
- """Distribution with support for features, tests, and package data
+ """Distribution with support for tests and package data
This is an enhanced version of 'distutils.dist.Distribution' that
effectively adds the following new optional keyword arguments to 'setup()':
@@ -364,21 +367,6 @@ class Distribution(_Distribution):
EasyInstall and requests one of your extras, the corresponding
additional requirements will be installed if needed.
- 'features' **deprecated** -- a dictionary mapping option names to
- 'setuptools.Feature'
- objects. Features are a portion of the distribution that can be
- included or excluded based on user options, inter-feature dependencies,
- and availability on the current system. Excluded features are omitted
- from all setup commands, including source and binary distributions, so
- you can create multiple distributions from the same source tree.
- Feature names should be valid Python identifiers, except that they may
- contain the '-' (minus) sign. Features can be included or excluded
- via the command line options '--with-X' and '--without-X', where 'X' is
- the name of the feature. Whether a feature is included by default, and
- whether you are allowed to control this from the command line, is
- determined by the Feature object. See the 'Feature' class for more
- information.
-
'test_suite' -- the name of a test suite to run for the 'test' command.
If the user runs 'python setup.py test', the package will be installed,
and the named test suite will be run. The format is the same as
@@ -400,14 +388,14 @@ class Distribution(_Distribution):
for manipulating the distribution's contents. For example, the 'include()'
and 'exclude()' methods can be thought of as in-place add and subtract
commands that add or remove packages, modules, extensions, and so on from
- the distribution. They are used by the feature subsystem to configure the
- distribution for the included and excluded features.
+ the distribution.
"""
_DISTUTILS_UNSUPPORTED_METADATA = {
'long_description_content_type': None,
'project_urls': dict,
- 'provides_extras': set,
+ 'provides_extras': ordered_set.OrderedSet,
+ 'license_files': ordered_set.OrderedSet,
}
_patched_dist = None
@@ -430,10 +418,6 @@ class Distribution(_Distribution):
if not have_package_data:
self.package_data = {}
attrs = attrs or {}
- if 'features' in attrs or 'require_features' in attrs:
- Feature.warn_deprecated()
- self.require_features = []
- self.features = {}
self.dist_files = []
# Filter-out setuptools' specific options.
self.src_root = attrs.pop("src_root", None)
@@ -459,30 +443,40 @@ class Distribution(_Distribution):
value = default() if default else None
setattr(self.metadata, option, value)
- if isinstance(self.metadata.version, numbers.Number):
- # Some people apparently take "version number" too literally :)
- self.metadata.version = str(self.metadata.version)
+ self.metadata.version = self._normalize_version(
+ self._validate_version(self.metadata.version))
+ self._finalize_requires()
- if self.metadata.version is not None:
+ @staticmethod
+ def _normalize_version(version):
+ if isinstance(version, setuptools.sic) or version is None:
+ return version
+
+ normalized = str(packaging.version.Version(version))
+ if version != normalized:
+ tmpl = "Normalizing '{version}' to '{normalized}'"
+ warnings.warn(tmpl.format(**locals()))
+ return normalized
+ return version
+
+ @staticmethod
+ def _validate_version(version):
+ if isinstance(version, numbers.Number):
+ # Some people apparently take "version number" too literally :)
+ version = str(version)
+
+ if version is not None:
try:
- ver = packaging.version.Version(self.metadata.version)
- normalized_version = str(ver)
- if self.metadata.version != normalized_version:
- warnings.warn(
- "Normalizing '%s' to '%s'" % (
- self.metadata.version,
- normalized_version,
- )
- )
- self.metadata.version = normalized_version
+ packaging.version.Version(version)
except (packaging.version.InvalidVersion, TypeError):
warnings.warn(
"The version specified (%r) is an invalid version, this "
"may not work as expected with newer versions of "
"setuptools, pip, and PyPI. Please see PEP 440 for more "
- "details." % self.metadata.version
+ "details." % version
)
- self._finalize_requires()
+ return setuptools.sic(version)
+ return version
def _finalize_requires(self):
"""
@@ -569,7 +563,7 @@ class Distribution(_Distribution):
from setuptools.extern.six.moves.configparser import ConfigParser
# Ignore install directory options if we have a venv
- if six.PY3 and sys.prefix != sys.base_prefix:
+ if not six.PY2 and sys.prefix != sys.base_prefix:
ignore_options = [
'install-base', 'install-platbase', 'install-lib',
'install-platlib', 'install-purelib', 'install-headers',
@@ -591,7 +585,7 @@ class Distribution(_Distribution):
with io.open(filename, encoding='utf-8') as reader:
if DEBUG:
self.announce(" reading {filename}".format(**locals()))
- (parser.read_file if six.PY3 else parser.readfp)(reader)
+ (parser.readfp if six.PY2 else parser.read_file)(reader)
for section in parser.sections():
options = parser.options(section)
opt_dict = self.get_option_dict(section)
@@ -619,8 +613,8 @@ class Distribution(_Distribution):
setattr(self, opt, strtobool(val))
else:
setattr(self, opt, val)
- except ValueError as msg:
- raise DistutilsOptionError(msg)
+ except ValueError as e:
+ raise DistutilsOptionError(e) from e
@staticmethod
def _try_str(val):
@@ -634,7 +628,7 @@ class Distribution(_Distribution):
Ref #1653
"""
- if six.PY3:
+ if not six.PY2:
return val
try:
return val.encode()
@@ -686,8 +680,8 @@ class Distribution(_Distribution):
raise DistutilsOptionError(
"error in %s: command '%s' has no such option '%s'"
% (source, command_name, option))
- except ValueError as msg:
- raise DistutilsOptionError(msg)
+ except ValueError as e:
+ raise DistutilsOptionError(e) from e
def parse_config_files(self, filenames=None, ignore_option_errors=False):
"""Parses configuration files from various levels
@@ -700,17 +694,6 @@ class Distribution(_Distribution):
ignore_option_errors=ignore_option_errors)
self._finalize_requires()
- def parse_command_line(self):
- """Process features after parsing command line options"""
- result = _Distribution.parse_command_line(self)
- if self.features:
- self._finalize_features()
- return result
-
- def _feature_attrname(self, name):
- """Convert feature name to corresponding option attribute name"""
- return 'with_' + name.replace('-', '_')
-
def fetch_build_eggs(self, requires):
"""Resolve pre-setup requirements"""
resolved_dists = pkg_resources.working_set.resolve(
@@ -723,15 +706,28 @@ class Distribution(_Distribution):
return resolved_dists
def finalize_options(self):
- _Distribution.finalize_options(self)
- if self.features:
- self._set_global_opts_from_features()
+ """
+ Allow plugins to apply arbitrary operations to the
+ distribution. Each hook may optionally define a 'order'
+ to influence the order of execution. Smaller numbers
+ go first and the default is 0.
+ """
+ group = 'setuptools.finalize_distribution_options'
+ def by_order(hook):
+ return getattr(hook, 'order', 0)
+ eps = map(lambda e: e.load(), pkg_resources.iter_entry_points(group))
+ for ep in sorted(eps, key=by_order):
+ ep(self)
+
+ def _finalize_setup_keywords(self):
for ep in pkg_resources.iter_entry_points('distutils.setup_keywords'):
value = getattr(self, ep.name, None)
if value is not None:
ep.require(installer=self.fetch_build_egg)
ep.load()(self, ep.name, value)
+
+ def _finalize_2to3_doctests(self):
if getattr(self, 'convert_2to3_doctests', None):
# XXX may convert to set here when we can rely on set being builtin
self.convert_2to3_doctests = [
@@ -758,76 +754,8 @@ class Distribution(_Distribution):
def fetch_build_egg(self, req):
"""Fetch an egg needed for building"""
- from setuptools.command.easy_install import easy_install
- dist = self.__class__({'script_args': ['easy_install']})
- opts = dist.get_option_dict('easy_install')
- opts.clear()
- opts.update(
- (k, v)
- for k, v in self.get_option_dict('easy_install').items()
- if k in (
- # don't use any other settings
- 'find_links', 'site_dirs', 'index_url',
- 'optimize', 'site_dirs', 'allow_hosts',
- ))
- if self.dependency_links:
- links = self.dependency_links[:]
- if 'find_links' in opts:
- links = opts['find_links'][1] + links
- opts['find_links'] = ('setup', links)
- install_dir = self.get_egg_cache_dir()
- cmd = easy_install(
- dist, args=["x"], install_dir=install_dir,
- exclude_scripts=True,
- always_copy=False, build_directory=None, editable=False,
- upgrade=False, multi_version=True, no_report=True, user=False
- )
- cmd.ensure_finalized()
- return cmd.easy_install(req)
-
- def _set_global_opts_from_features(self):
- """Add --with-X/--without-X options based on optional features"""
-
- go = []
- no = self.negative_opt.copy()
-
- for name, feature in self.features.items():
- self._set_feature(name, None)
- feature.validate(self)
-
- if feature.optional:
- descr = feature.description
- incdef = ' (default)'
- excdef = ''
- if not feature.include_by_default():
- excdef, incdef = incdef, excdef
-
- new = (
- ('with-' + name, None, 'include ' + descr + incdef),
- ('without-' + name, None, 'exclude ' + descr + excdef),
- )
- go.extend(new)
- no['without-' + name] = 'with-' + name
-
- self.global_options = self.feature_options = go + self.global_options
- self.negative_opt = self.feature_negopt = no
-
- def _finalize_features(self):
- """Add/remove features and resolve dependencies between them"""
-
- # First, flag all the enabled items (and thus their dependencies)
- for name, feature in self.features.items():
- enabled = self.feature_is_included(name)
- if enabled or (enabled is None and feature.include_by_default()):
- feature.include_in(self)
- self._set_feature(name, 1)
-
- # Then disable the rest, so that off-by-default features don't
- # get flagged as errors when they're required by an enabled feature
- for name, feature in self.features.items():
- if not self.feature_is_included(name):
- feature.exclude_from(self)
- self._set_feature(name, 0)
+ from setuptools.installer import fetch_build_egg
+ return fetch_build_egg(self, req)
def get_command_class(self, command):
"""Pluggable version of get_command_class()"""
@@ -858,25 +786,6 @@ class Distribution(_Distribution):
self.cmdclass[ep.name] = cmdclass
return _Distribution.get_command_list(self)
- def _set_feature(self, name, status):
- """Set feature's inclusion status"""
- setattr(self, self._feature_attrname(name), status)
-
- def feature_is_included(self, name):
- """Return 1 if feature is included, 0 if excluded, 'None' if unknown"""
- return getattr(self, self._feature_attrname(name))
-
- def include_feature(self, name):
- """Request inclusion of feature named 'name'"""
-
- if self.feature_is_included(name) == 0:
- descr = self.features[name].description
- raise DistutilsOptionError(
- descr + " is required, but was excluded or is not available"
- )
- self.features[name].include_in(self)
- self._set_feature(name, 1)
-
def include(self, **attrs):
"""Add items to distribution that are named in keyword arguments
@@ -938,10 +847,10 @@ class Distribution(_Distribution):
)
try:
old = getattr(self, name)
- except AttributeError:
+ except AttributeError as e:
raise DistutilsSetupError(
"%s: No such distribution setting" % name
- )
+ ) from e
if old is not None and not isinstance(old, sequence):
raise DistutilsSetupError(
name + ": this setting cannot be changed via include/exclude"
@@ -958,10 +867,10 @@ class Distribution(_Distribution):
)
try:
old = getattr(self, name)
- except AttributeError:
+ except AttributeError as e:
raise DistutilsSetupError(
"%s: No such distribution setting" % name
- )
+ ) from e
if old is None:
setattr(self, name, value)
elif not isinstance(old, sequence):
@@ -1121,160 +1030,6 @@ class Distribution(_Distribution):
sys.stdout.detach(), encoding, errors, newline, line_buffering)
-class Feature:
- """
- **deprecated** -- The `Feature` facility was never completely implemented
- or supported, `has reported issues
- `_ and will be removed in
- a future version.
-
- A subset of the distribution that can be excluded if unneeded/wanted
-
- Features are created using these keyword arguments:
-
- 'description' -- a short, human readable description of the feature, to
- be used in error messages, and option help messages.
-
- 'standard' -- if true, the feature is included by default if it is
- available on the current system. Otherwise, the feature is only
- included if requested via a command line '--with-X' option, or if
- another included feature requires it. The default setting is 'False'.
-
- 'available' -- if true, the feature is available for installation on the
- current system. The default setting is 'True'.
-
- 'optional' -- if true, the feature's inclusion can be controlled from the
- command line, using the '--with-X' or '--without-X' options. If
- false, the feature's inclusion status is determined automatically,
- based on 'availabile', 'standard', and whether any other feature
- requires it. The default setting is 'True'.
-
- 'require_features' -- a string or sequence of strings naming features
- that should also be included if this feature is included. Defaults to
- empty list. May also contain 'Require' objects that should be
- added/removed from the distribution.
-
- 'remove' -- a string or list of strings naming packages to be removed
- from the distribution if this feature is *not* included. If the
- feature *is* included, this argument is ignored. This argument exists
- to support removing features that "crosscut" a distribution, such as
- defining a 'tests' feature that removes all the 'tests' subpackages
- provided by other features. The default for this argument is an empty
- list. (Note: the named package(s) or modules must exist in the base
- distribution when the 'setup()' function is initially called.)
-
- other keywords -- any other keyword arguments are saved, and passed to
- the distribution's 'include()' and 'exclude()' methods when the
- feature is included or excluded, respectively. So, for example, you
- could pass 'packages=["a","b"]' to cause packages 'a' and 'b' to be
- added or removed from the distribution as appropriate.
-
- A feature must include at least one 'requires', 'remove', or other
- keyword argument. Otherwise, it can't affect the distribution in any way.
- Note also that you can subclass 'Feature' to create your own specialized
- feature types that modify the distribution in other ways when included or
- excluded. See the docstrings for the various methods here for more detail.
- Aside from the methods, the only feature attributes that distributions look
- at are 'description' and 'optional'.
- """
-
- @staticmethod
- def warn_deprecated():
- msg = (
- "Features are deprecated and will be removed in a future "
- "version. See https://github.com/pypa/setuptools/issues/65."
- )
- warnings.warn(msg, DistDeprecationWarning, stacklevel=3)
-
- def __init__(
- self, description, standard=False, available=True,
- optional=True, require_features=(), remove=(), **extras):
- self.warn_deprecated()
-
- self.description = description
- self.standard = standard
- self.available = available
- self.optional = optional
- if isinstance(require_features, (str, Require)):
- require_features = require_features,
-
- self.require_features = [
- r for r in require_features if isinstance(r, str)
- ]
- er = [r for r in require_features if not isinstance(r, str)]
- if er:
- extras['require_features'] = er
-
- if isinstance(remove, str):
- remove = remove,
- self.remove = remove
- self.extras = extras
-
- if not remove and not require_features and not extras:
- raise DistutilsSetupError(
- "Feature %s: must define 'require_features', 'remove', or "
- "at least one of 'packages', 'py_modules', etc."
- )
-
- def include_by_default(self):
- """Should this feature be included by default?"""
- return self.available and self.standard
-
- def include_in(self, dist):
- """Ensure feature and its requirements are included in distribution
-
- You may override this in a subclass to perform additional operations on
- the distribution. Note that this method may be called more than once
- per feature, and so should be idempotent.
-
- """
-
- if not self.available:
- raise DistutilsPlatformError(
- self.description + " is required, "
- "but is not available on this platform"
- )
-
- dist.include(**self.extras)
-
- for f in self.require_features:
- dist.include_feature(f)
-
- def exclude_from(self, dist):
- """Ensure feature is excluded from distribution
-
- You may override this in a subclass to perform additional operations on
- the distribution. This method will be called at most once per
- feature, and only after all included features have been asked to
- include themselves.
- """
-
- dist.exclude(**self.extras)
-
- if self.remove:
- for item in self.remove:
- dist.exclude_package(item)
-
- def validate(self, dist):
- """Verify that feature makes sense in context of distribution
-
- This method is called by the distribution just before it parses its
- command line. It checks to ensure that the 'remove' attribute, if any,
- contains only valid package/module names that are present in the base
- distribution when 'setup()' is called. You may override it in a
- subclass to perform any other required validation of the feature
- against a target distribution.
- """
-
- for item in self.remove:
- if not dist.has_contents_for(item):
- raise DistutilsSetupError(
- "%s wants to be able to remove %s, but the distribution"
- " doesn't contain any packages or modules under %s"
- % (self.description, item, item)
- )
-
-
class DistDeprecationWarning(SetuptoolsDeprecationWarning):
"""Class for warning about deprecations in dist in
setuptools. Not ignored by default, unlike DeprecationWarning."""
diff --git a/venv/lib/python3.8/site-packages/setuptools/extern/__init__.py b/venv/lib/python3.8/site-packages/setuptools/extern/__init__.py
index cb2fa32..4e79aa1 100644
--- a/venv/lib/python3.8/site-packages/setuptools/extern/__init__.py
+++ b/venv/lib/python3.8/site-packages/setuptools/extern/__init__.py
@@ -43,13 +43,6 @@ class VendorImporter:
__import__(extant)
mod = sys.modules[extant]
sys.modules[fullname] = mod
- # mysterious hack:
- # Remove the reference to the extant package/module
- # on later Python versions to cause relative imports
- # in the vendor package to resolve the same modules
- # as those going through this importer.
- if sys.version_info >= (3, ):
- del sys.modules[extant]
return mod
except ImportError:
pass
@@ -69,5 +62,5 @@ class VendorImporter:
sys.meta_path.append(self)
-names = 'six', 'packaging', 'pyparsing',
+names = 'six', 'packaging', 'pyparsing', 'ordered_set',
VendorImporter(__name__, names, 'setuptools._vendor').install()
diff --git a/venv/lib/python3.8/site-packages/setuptools/extern/__pycache__/__init__.cpython-38.pyc b/venv/lib/python3.8/site-packages/setuptools/extern/__pycache__/__init__.cpython-38.pyc
index 1301a0d..ae57320 100644
Binary files a/venv/lib/python3.8/site-packages/setuptools/extern/__pycache__/__init__.cpython-38.pyc and b/venv/lib/python3.8/site-packages/setuptools/extern/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib/python3.8/site-packages/setuptools/glibc.py b/venv/lib/python3.8/site-packages/setuptools/glibc.py
deleted file mode 100644
index a134591..0000000
--- a/venv/lib/python3.8/site-packages/setuptools/glibc.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# This file originally from pip:
-# https://github.com/pypa/pip/blob/8f4f15a5a95d7d5b511ceaee9ed261176c181970/src/pip/_internal/utils/glibc.py
-from __future__ import absolute_import
-
-import ctypes
-import re
-import warnings
-
-
-def glibc_version_string():
- "Returns glibc version string, or None if not using glibc."
-
- # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen
- # manpage says, "If filename is NULL, then the returned handle is for the
- # main program". This way we can let the linker do the work to figure out
- # which libc our process is actually using.
- process_namespace = ctypes.CDLL(None)
- try:
- gnu_get_libc_version = process_namespace.gnu_get_libc_version
- except AttributeError:
- # Symbol doesn't exist -> therefore, we are not linked to
- # glibc.
- return None
-
- # Call gnu_get_libc_version, which returns a string like "2.5"
- gnu_get_libc_version.restype = ctypes.c_char_p
- version_str = gnu_get_libc_version()
- # py2 / py3 compatibility:
- if not isinstance(version_str, str):
- version_str = version_str.decode("ascii")
-
- return version_str
-
-
-# Separated out from have_compatible_glibc for easier unit testing
-def check_glibc_version(version_str, required_major, minimum_minor):
- # Parse string and check against requested version.
- #
- # We use a regexp instead of str.split because we want to discard any
- # random junk that might come after the minor version -- this might happen
- # in patched/forked versions of glibc (e.g. Linaro's version of glibc
- # uses version strings like "2.20-2014.11"). See gh-3588.
- m = re.match(r"(?P