From 4cf2dd5b32ac078773413093c9fc76242e228f48 Mon Sep 17 00:00:00 2001 From: Kenneth Reitz Date: Fri, 30 May 2014 09:35:25 -0400 Subject: [PATCH] removed old pip vendoring style --- vendor/pip-1.5.6/AUTHORS.txt | 120 - vendor/pip-1.5.6/CHANGES.txt | 937 --- vendor/pip-1.5.6/LICENSE.txt | 20 - vendor/pip-1.5.6/MANIFEST.in | 9 - vendor/pip-1.5.6/PKG-INFO | 91 - vendor/pip-1.5.6/PROJECT.txt | 11 - vendor/pip-1.5.6/README.rst | 10 - vendor/pip-1.5.6/docs/configuration.rst | 8 - vendor/pip-1.5.6/docs/cookbook.rst | 8 - vendor/pip-1.5.6/docs/development.rst | 126 - .../pip-1.5.6/docs/distribute_setuptools.rst | 69 - vendor/pip-1.5.6/docs/index.rst | 25 - vendor/pip-1.5.6/docs/installing.rst | 88 - vendor/pip-1.5.6/docs/logic.rst | 8 - vendor/pip-1.5.6/docs/news.rst | 5 - vendor/pip-1.5.6/docs/quickstart.rst | 56 - vendor/pip-1.5.6/docs/reference/index.rst | 17 - vendor/pip-1.5.6/docs/reference/pip.rst | 80 - .../pip-1.5.6/docs/reference/pip_freeze.rst | 46 - .../pip-1.5.6/docs/reference/pip_install.rst | 439 -- vendor/pip-1.5.6/docs/reference/pip_list.rst | 45 - .../pip-1.5.6/docs/reference/pip_search.rst | 36 - vendor/pip-1.5.6/docs/reference/pip_show.rst | 37 - .../docs/reference/pip_uninstall.rst | 37 - vendor/pip-1.5.6/docs/reference/pip_wheel.rst | 37 - vendor/pip-1.5.6/docs/usage.rst | 8 - vendor/pip-1.5.6/docs/user_guide.rst | 509 -- vendor/pip-1.5.6/pip/__init__.py | 277 - vendor/pip-1.5.6/pip/__main__.py | 7 - vendor/pip-1.5.6/pip/_vendor/__init__.py | 8 - .../pip/_vendor/_markerlib/__init__.py | 16 - .../pip/_vendor/_markerlib/markers.py | 119 - .../pip/_vendor/colorama/__init__.py | 7 - vendor/pip-1.5.6/pip/_vendor/colorama/ansi.py | 50 - .../pip/_vendor/colorama/ansitowin32.py | 190 - .../pip/_vendor/colorama/initialise.py | 56 - .../pip-1.5.6/pip/_vendor/colorama/win32.py | 137 - .../pip-1.5.6/pip/_vendor/colorama/winterm.py | 120 - .../pip-1.5.6/pip/_vendor/distlib/__init__.py | 23 - .../pip/_vendor/distlib/_backport/__init__.py | 6 - .../pip/_vendor/distlib/_backport/misc.py | 41 - .../pip/_vendor/distlib/_backport/shutil.py | 761 --- .../_vendor/distlib/_backport/sysconfig.cfg | 84 - .../_vendor/distlib/_backport/sysconfig.py | 788 --- .../pip/_vendor/distlib/_backport/tarfile.py | 2607 --------- .../pip-1.5.6/pip/_vendor/distlib/compat.py | 1064 ---- .../pip-1.5.6/pip/_vendor/distlib/database.py | 1301 ----- vendor/pip-1.5.6/pip/_vendor/distlib/index.py | 488 -- .../pip-1.5.6/pip/_vendor/distlib/locators.py | 1194 ---- .../pip-1.5.6/pip/_vendor/distlib/manifest.py | 364 -- .../pip-1.5.6/pip/_vendor/distlib/markers.py | 190 - .../pip-1.5.6/pip/_vendor/distlib/metadata.py | 1026 ---- .../pip/_vendor/distlib/resources.py | 317 -- .../pip-1.5.6/pip/_vendor/distlib/scripts.py | 323 -- vendor/pip-1.5.6/pip/_vendor/distlib/t32.exe | Bin 91136 -> 0 bytes vendor/pip-1.5.6/pip/_vendor/distlib/t64.exe | Bin 94720 -> 0 bytes vendor/pip-1.5.6/pip/_vendor/distlib/util.py | 1575 ------ .../pip-1.5.6/pip/_vendor/distlib/version.py | 721 --- vendor/pip-1.5.6/pip/_vendor/distlib/w32.exe | Bin 87040 -> 0 bytes vendor/pip-1.5.6/pip/_vendor/distlib/w64.exe | Bin 91648 -> 0 bytes vendor/pip-1.5.6/pip/_vendor/distlib/wheel.py | 958 ---- .../pip/_vendor/html5lib/__init__.py | 23 - .../pip/_vendor/html5lib/constants.py | 3104 ---------- .../pip/_vendor/html5lib/filters/__init__.py | 0 .../pip/_vendor/html5lib/filters/_base.py | 12 - .../filters/alphabeticalattributes.py | 20 - .../html5lib/filters/inject_meta_charset.py | 65 - .../pip/_vendor/html5lib/filters/lint.py | 93 - .../_vendor/html5lib/filters/optionaltags.py | 205 - .../pip/_vendor/html5lib/filters/sanitizer.py | 12 - .../_vendor/html5lib/filters/whitespace.py | 38 - .../pip/_vendor/html5lib/html5parser.py | 2713 --------- .../pip/_vendor/html5lib/ihatexml.py | 285 - .../pip/_vendor/html5lib/inputstream.py | 881 --- .../pip/_vendor/html5lib/sanitizer.py | 271 - .../_vendor/html5lib/serializer/__init__.py | 16 - .../html5lib/serializer/htmlserializer.py | 320 -- .../pip/_vendor/html5lib/tokenizer.py | 1731 ------ .../_vendor/html5lib/treeadapters/__init__.py | 0 .../pip/_vendor/html5lib/treeadapters/sax.py | 44 - .../_vendor/html5lib/treebuilders/__init__.py | 76 - .../_vendor/html5lib/treebuilders/_base.py | 377 -- .../pip/_vendor/html5lib/treebuilders/dom.py | 227 - .../_vendor/html5lib/treebuilders/etree.py | 337 -- .../html5lib/treebuilders/etree_lxml.py | 369 -- .../_vendor/html5lib/treewalkers/__init__.py | 57 - .../pip/_vendor/html5lib/treewalkers/_base.py | 200 - .../pip/_vendor/html5lib/treewalkers/dom.py | 46 - .../pip/_vendor/html5lib/treewalkers/etree.py | 138 - .../html5lib/treewalkers/genshistream.py | 69 - .../_vendor/html5lib/treewalkers/lxmletree.py | 208 - .../_vendor/html5lib/treewalkers/pulldom.py | 63 - .../pip/_vendor/html5lib/trie/__init__.py | 12 - .../pip/_vendor/html5lib/trie/_base.py | 37 - .../pip/_vendor/html5lib/trie/datrie.py | 44 - .../pip-1.5.6/pip/_vendor/html5lib/trie/py.py | 67 - .../pip-1.5.6/pip/_vendor/html5lib/utils.py | 82 - vendor/pip-1.5.6/pip/_vendor/pkg_resources.py | 2762 --------- vendor/pip-1.5.6/pip/_vendor/re-vendor.py | 34 - .../pip/_vendor/requests/__init__.py | 77 - .../pip/_vendor/requests/adapters.py | 388 -- vendor/pip-1.5.6/pip/_vendor/requests/api.py | 120 - vendor/pip-1.5.6/pip/_vendor/requests/auth.py | 193 - .../pip-1.5.6/pip/_vendor/requests/cacert.pem | 5026 ----------------- .../pip-1.5.6/pip/_vendor/requests/certs.py | 24 - .../pip-1.5.6/pip/_vendor/requests/compat.py | 115 - .../pip-1.5.6/pip/_vendor/requests/cookies.py | 454 -- .../pip/_vendor/requests/exceptions.py | 75 - .../pip-1.5.6/pip/_vendor/requests/hooks.py | 45 - .../pip-1.5.6/pip/_vendor/requests/models.py | 803 --- .../pip/_vendor/requests/packages/__init__.py | 3 - .../requests/packages/chardet/__init__.py | 32 - .../requests/packages/chardet/big5freq.py | 925 --- .../requests/packages/chardet/big5prober.py | 42 - .../requests/packages/chardet/chardetect.py | 46 - .../packages/chardet/chardistribution.py | 231 - .../packages/chardet/charsetgroupprober.py | 106 - .../packages/chardet/charsetprober.py | 62 - .../packages/chardet/codingstatemachine.py | 61 - .../requests/packages/chardet/compat.py | 34 - .../requests/packages/chardet/constants.py | 39 - .../requests/packages/chardet/cp949prober.py | 44 - .../requests/packages/chardet/escprober.py | 86 - .../requests/packages/chardet/escsm.py | 242 - .../requests/packages/chardet/eucjpprober.py | 90 - .../requests/packages/chardet/euckrfreq.py | 596 -- .../requests/packages/chardet/euckrprober.py | 42 - .../requests/packages/chardet/euctwfreq.py | 428 -- .../requests/packages/chardet/euctwprober.py | 41 - .../requests/packages/chardet/gb2312freq.py | 472 -- .../requests/packages/chardet/gb2312prober.py | 41 - .../requests/packages/chardet/hebrewprober.py | 283 - .../requests/packages/chardet/jisfreq.py | 569 -- .../requests/packages/chardet/jpcntx.py | 219 - .../packages/chardet/langbulgarianmodel.py | 229 - .../packages/chardet/langcyrillicmodel.py | 329 -- .../packages/chardet/langgreekmodel.py | 225 - .../packages/chardet/langhebrewmodel.py | 201 - .../packages/chardet/langhungarianmodel.py | 225 - .../packages/chardet/langthaimodel.py | 200 - .../requests/packages/chardet/latin1prober.py | 139 - .../packages/chardet/mbcharsetprober.py | 86 - .../packages/chardet/mbcsgroupprober.py | 54 - .../requests/packages/chardet/mbcssm.py | 575 -- .../packages/chardet/sbcharsetprober.py | 120 - .../packages/chardet/sbcsgroupprober.py | 69 - .../requests/packages/chardet/sjisprober.py | 91 - .../packages/chardet/universaldetector.py | 170 - .../requests/packages/chardet/utf8prober.py | 76 - .../requests/packages/urllib3/__init__.py | 58 - .../requests/packages/urllib3/_collections.py | 205 - .../requests/packages/urllib3/connection.py | 204 - .../packages/urllib3/connectionpool.py | 710 --- .../packages/urllib3/contrib/__init__.py | 0 .../packages/urllib3/contrib/ntlmpool.py | 120 - .../packages/urllib3/contrib/pyopenssl.py | 422 -- .../requests/packages/urllib3/exceptions.py | 126 - .../requests/packages/urllib3/fields.py | 177 - .../requests/packages/urllib3/filepost.py | 100 - .../packages/urllib3/packages/__init__.py | 4 - .../packages/urllib3/packages/ordered_dict.py | 260 - .../requests/packages/urllib3/packages/six.py | 385 -- .../packages/ssl_match_hostname/__init__.py | 13 - .../ssl_match_hostname/_implementation.py | 105 - .../requests/packages/urllib3/poolmanager.py | 258 - .../requests/packages/urllib3/request.py | 141 - .../requests/packages/urllib3/response.py | 308 - .../packages/urllib3/util/__init__.py | 27 - .../packages/urllib3/util/connection.py | 45 - .../requests/packages/urllib3/util/request.py | 68 - .../packages/urllib3/util/response.py | 13 - .../requests/packages/urllib3/util/ssl_.py | 133 - .../requests/packages/urllib3/util/timeout.py | 234 - .../requests/packages/urllib3/util/url.py | 162 - .../pip/_vendor/requests/sessions.py | 637 --- .../pip/_vendor/requests/status_codes.py | 88 - .../pip/_vendor/requests/structures.py | 127 - .../pip-1.5.6/pip/_vendor/requests/utils.py | 673 --- vendor/pip-1.5.6/pip/_vendor/six.py | 646 --- .../pip-1.5.6/pip/backwardcompat/__init__.py | 138 - vendor/pip-1.5.6/pip/basecommand.py | 201 - vendor/pip-1.5.6/pip/baseparser.py | 224 - vendor/pip-1.5.6/pip/cmdoptions.py | 371 -- vendor/pip-1.5.6/pip/commands/__init__.py | 88 - vendor/pip-1.5.6/pip/commands/bundle.py | 42 - vendor/pip-1.5.6/pip/commands/completion.py | 59 - vendor/pip-1.5.6/pip/commands/freeze.py | 114 - vendor/pip-1.5.6/pip/commands/help.py | 33 - vendor/pip-1.5.6/pip/commands/install.py | 314 - vendor/pip-1.5.6/pip/commands/list.py | 162 - vendor/pip-1.5.6/pip/commands/search.py | 132 - vendor/pip-1.5.6/pip/commands/show.py | 80 - vendor/pip-1.5.6/pip/commands/uninstall.py | 59 - vendor/pip-1.5.6/pip/commands/unzip.py | 7 - vendor/pip-1.5.6/pip/commands/wheel.py | 195 - vendor/pip-1.5.6/pip/commands/zip.py | 351 -- vendor/pip-1.5.6/pip/download.py | 644 --- vendor/pip-1.5.6/pip/exceptions.py | 46 - vendor/pip-1.5.6/pip/index.py | 990 ---- vendor/pip-1.5.6/pip/locations.py | 172 - vendor/pip-1.5.6/pip/log.py | 276 - vendor/pip-1.5.6/pip/pep425tags.py | 102 - vendor/pip-1.5.6/pip/req.py | 1931 ------- vendor/pip-1.5.6/pip/runner.py | 18 - vendor/pip-1.5.6/pip/status_codes.py | 6 - vendor/pip-1.5.6/pip/util.py | 720 --- vendor/pip-1.5.6/pip/vcs/__init__.py | 251 - vendor/pip-1.5.6/pip/vcs/bazaar.py | 131 - vendor/pip-1.5.6/pip/vcs/git.py | 194 - vendor/pip-1.5.6/pip/vcs/mercurial.py | 151 - vendor/pip-1.5.6/pip/vcs/subversion.py | 273 - vendor/pip-1.5.6/pip/wheel.py | 560 -- vendor/pip-1.5.6/setup.cfg | 11 - vendor/pip-1.5.6/setup.py | 82 - 214 files changed, 63158 deletions(-) delete mode 100644 vendor/pip-1.5.6/AUTHORS.txt delete mode 100644 vendor/pip-1.5.6/CHANGES.txt delete mode 100644 vendor/pip-1.5.6/LICENSE.txt delete mode 100644 vendor/pip-1.5.6/MANIFEST.in delete mode 100644 vendor/pip-1.5.6/PKG-INFO delete mode 100644 vendor/pip-1.5.6/PROJECT.txt delete mode 100644 vendor/pip-1.5.6/README.rst delete mode 100644 vendor/pip-1.5.6/docs/configuration.rst delete mode 100644 vendor/pip-1.5.6/docs/cookbook.rst delete mode 100644 vendor/pip-1.5.6/docs/development.rst delete mode 100644 vendor/pip-1.5.6/docs/distribute_setuptools.rst delete mode 100644 vendor/pip-1.5.6/docs/index.rst delete mode 100644 vendor/pip-1.5.6/docs/installing.rst delete mode 100644 vendor/pip-1.5.6/docs/logic.rst delete mode 100644 vendor/pip-1.5.6/docs/news.rst delete mode 100644 vendor/pip-1.5.6/docs/quickstart.rst delete mode 100644 vendor/pip-1.5.6/docs/reference/index.rst delete mode 100644 vendor/pip-1.5.6/docs/reference/pip.rst delete mode 100644 vendor/pip-1.5.6/docs/reference/pip_freeze.rst delete mode 100644 vendor/pip-1.5.6/docs/reference/pip_install.rst delete mode 100644 vendor/pip-1.5.6/docs/reference/pip_list.rst delete mode 100644 vendor/pip-1.5.6/docs/reference/pip_search.rst delete mode 100644 vendor/pip-1.5.6/docs/reference/pip_show.rst delete mode 100644 vendor/pip-1.5.6/docs/reference/pip_uninstall.rst delete mode 100644 vendor/pip-1.5.6/docs/reference/pip_wheel.rst delete mode 100644 vendor/pip-1.5.6/docs/usage.rst delete mode 100644 vendor/pip-1.5.6/docs/user_guide.rst delete mode 100755 vendor/pip-1.5.6/pip/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/__main__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/_markerlib/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/_markerlib/markers.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/colorama/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/colorama/ansi.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/colorama/ansitowin32.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/colorama/initialise.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/colorama/win32.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/colorama/winterm.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/_backport/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/_backport/misc.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/_backport/shutil.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/_backport/sysconfig.cfg delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/_backport/sysconfig.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/_backport/tarfile.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/compat.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/database.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/index.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/locators.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/manifest.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/markers.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/metadata.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/resources.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/scripts.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/t32.exe delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/t64.exe delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/util.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/version.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/w32.exe delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/w64.exe delete mode 100644 vendor/pip-1.5.6/pip/_vendor/distlib/wheel.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/constants.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/filters/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/filters/_base.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/filters/alphabeticalattributes.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/filters/inject_meta_charset.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/filters/lint.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/filters/optionaltags.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/filters/sanitizer.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/filters/whitespace.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/html5parser.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/ihatexml.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/inputstream.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/sanitizer.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/serializer/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/serializer/htmlserializer.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/tokenizer.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/treeadapters/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/treeadapters/sax.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/treebuilders/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/treebuilders/_base.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/treebuilders/dom.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/treebuilders/etree.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/treebuilders/etree_lxml.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/treewalkers/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/treewalkers/_base.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/treewalkers/dom.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/treewalkers/etree.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/treewalkers/genshistream.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/treewalkers/lxmletree.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/treewalkers/pulldom.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/trie/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/trie/_base.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/trie/datrie.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/trie/py.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/html5lib/utils.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/pkg_resources.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/re-vendor.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/adapters.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/api.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/auth.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/cacert.pem delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/certs.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/compat.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/cookies.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/exceptions.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/hooks.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/models.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/big5freq.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/big5prober.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/chardetect.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/chardistribution.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/charsetgroupprober.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/charsetprober.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/codingstatemachine.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/compat.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/constants.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/cp949prober.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/escprober.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/escsm.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/eucjpprober.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/euckrfreq.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/euckrprober.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/euctwfreq.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/euctwprober.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/gb2312freq.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/gb2312prober.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/hebrewprober.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/jisfreq.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/jpcntx.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/langbulgarianmodel.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/langcyrillicmodel.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/langgreekmodel.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/langhebrewmodel.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/langhungarianmodel.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/langthaimodel.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/latin1prober.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/mbcharsetprober.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/mbcsgroupprober.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/mbcssm.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/sbcharsetprober.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/sbcsgroupprober.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/sjisprober.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/universaldetector.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/chardet/utf8prober.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/_collections.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/connection.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/connectionpool.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/contrib/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/contrib/ntlmpool.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/contrib/pyopenssl.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/exceptions.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/fields.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/filepost.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/packages/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/packages/ordered_dict.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/packages/six.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/packages/ssl_match_hostname/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/packages/ssl_match_hostname/_implementation.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/poolmanager.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/request.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/response.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/util/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/util/connection.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/util/request.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/util/response.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/util/ssl_.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/util/timeout.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/packages/urllib3/util/url.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/sessions.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/status_codes.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/structures.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/requests/utils.py delete mode 100644 vendor/pip-1.5.6/pip/_vendor/six.py delete mode 100644 vendor/pip-1.5.6/pip/backwardcompat/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/basecommand.py delete mode 100644 vendor/pip-1.5.6/pip/baseparser.py delete mode 100644 vendor/pip-1.5.6/pip/cmdoptions.py delete mode 100644 vendor/pip-1.5.6/pip/commands/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/commands/bundle.py delete mode 100644 vendor/pip-1.5.6/pip/commands/completion.py delete mode 100644 vendor/pip-1.5.6/pip/commands/freeze.py delete mode 100644 vendor/pip-1.5.6/pip/commands/help.py delete mode 100644 vendor/pip-1.5.6/pip/commands/install.py delete mode 100644 vendor/pip-1.5.6/pip/commands/list.py delete mode 100644 vendor/pip-1.5.6/pip/commands/search.py delete mode 100644 vendor/pip-1.5.6/pip/commands/show.py delete mode 100644 vendor/pip-1.5.6/pip/commands/uninstall.py delete mode 100644 vendor/pip-1.5.6/pip/commands/unzip.py delete mode 100644 vendor/pip-1.5.6/pip/commands/wheel.py delete mode 100644 vendor/pip-1.5.6/pip/commands/zip.py delete mode 100644 vendor/pip-1.5.6/pip/download.py delete mode 100644 vendor/pip-1.5.6/pip/exceptions.py delete mode 100644 vendor/pip-1.5.6/pip/index.py delete mode 100644 vendor/pip-1.5.6/pip/locations.py delete mode 100644 vendor/pip-1.5.6/pip/log.py delete mode 100644 vendor/pip-1.5.6/pip/pep425tags.py delete mode 100644 vendor/pip-1.5.6/pip/req.py delete mode 100644 vendor/pip-1.5.6/pip/runner.py delete mode 100644 vendor/pip-1.5.6/pip/status_codes.py delete mode 100644 vendor/pip-1.5.6/pip/util.py delete mode 100644 vendor/pip-1.5.6/pip/vcs/__init__.py delete mode 100644 vendor/pip-1.5.6/pip/vcs/bazaar.py delete mode 100644 vendor/pip-1.5.6/pip/vcs/git.py delete mode 100644 vendor/pip-1.5.6/pip/vcs/mercurial.py delete mode 100644 vendor/pip-1.5.6/pip/vcs/subversion.py delete mode 100644 vendor/pip-1.5.6/pip/wheel.py delete mode 100644 vendor/pip-1.5.6/setup.cfg delete mode 100644 vendor/pip-1.5.6/setup.py diff --git a/vendor/pip-1.5.6/AUTHORS.txt b/vendor/pip-1.5.6/AUTHORS.txt deleted file mode 100644 index 3d62f01..0000000 --- a/vendor/pip-1.5.6/AUTHORS.txt +++ /dev/null @@ -1,120 +0,0 @@ -Alex Gaynor -Alex Grönholm -Alex Morega -Alexandre Conrad -Andrey Bulgakov -Anrs Hu -Anton Patrushev -Antti Kaihola -Armin Ronacher -Aziz Köksal -Ben Rosser -Bernardo B. Marques -Bradley Ayers -Brian Rosner -Carl Meyer -Chris McDonough -Christian Oudard -Clay McClure -Cody Soyland -Craig Kerstiens -Cristian Sorinel -Dan Sully -Daniel Holth -Dave Abrahams -David (d1b) -David Aguilar -David Evans -David Pursehouse -dengzhp -Dmitry Gladkov -Donald Stufft -Endoh Takanao -enoch -Erik M. Bray -Francesco -Gabriel de Perthuis -Garry Polley -Geoffrey Lehée -George Song -Georgi Valkov -Herbert Pfennig -hetmankp -Hugo Lopes Tavares -Hynek Schlawack -Ian Bicking -Igor Sobreira -Ionel Maries Cristian -Jakub Vysoky -James Cleveland -Jannis Leidel -Jakub Stasiak -Jay Graves -Jeff Dairiki -John-Scott Atlakson -Jon Parise -Jonas Nockert -Jon Parise -Jorge Niedbalski -Josh Bronson -Josh Hansen -Kamal Bin Mustafa -Kelsey Hightower -Kenneth Belitzky -Kenneth Reitz -Kevin Frommelt -Kumar McMillan -Lev Givon -Lincoln de Sousa -Luke Macken -Masklinn -Marc Abramowitz -Marc Tamlyn -Marcus Smith -Markus Hametner -Matt Maker -Maxime Rouyrre -Michael Williamson -Miguel Araujo Perez -Monty Taylor -Nick Stenning -Nowell Strite -Oliver Tonnhofer -Olivier Girardot -Ollie Rutherfurd -Oren Held -Patrick Jenkins -Patrick Dubroy -Paul Moore -Paul Nasrat -Paul Oswald -Paul van der Linden -Peter Waller -Phil Freo -Phil Whelan -Piet Delport -Preston Holmes -Przemek Wrzos -Qiangning Hong -Rafael Caricio -Rene Dudfield -Roey Berman -Ronny Pfannschmidt -Rory McCann -Ross Brattain -Sergey Vasilyev -Seth Woodworth -Simon Cross -Stavros Korokithakis -Stéphane Klein -Steven Myint -Takayuki SHIMIZUKAWA -Thomas Fenzl -Thomas Johansson -Toshio Kuratomi -Travis Swicegood -Vinay Sajip -Vitaly Babiy -W. Trevor King -Wil Tan -Hsiaoming Yang diff --git a/vendor/pip-1.5.6/CHANGES.txt b/vendor/pip-1.5.6/CHANGES.txt deleted file mode 100644 index 2405601..0000000 --- a/vendor/pip-1.5.6/CHANGES.txt +++ /dev/null @@ -1,937 +0,0 @@ -**1.5.6 (2014-05-16)** - - -* Upgrade requests to 2.3.0 to fix an issue with proxies on Python 3.4.1 - (PR #1821). - - -**1.5.5 (2014-05-03)** - - -* Fixes #1632. Uninstall issues on debianized pypy, specifically issues with - setuptools upgrades. (PR #1743) - -* Update documentation to point at https://bootstrap.pypa.io/get-pip.py for - bootstrapping pip. - -* Update docs to point to https://pip.pypa.io/ - -* Upgrade the bundled projects (distlib==0.1.8, html5lib==1.0b3, six==1.6.1, - colorama==0.3.1, setuptools==3.4.4). - - -**1.5.4 (2014-02-21)** - - -* Correct deprecation warning for ``pip install --build`` to only notify when - the `--build` value is different than the default. - - -**1.5.3 (2014-02-20)** - - -* **DEPRECATION** ``pip install --build`` and ``pip install --no-clean`` are now - deprecated. See Issue #906 for discussion. - -* Fixed #1112. Couldn't download directly from wheel paths/urls, and when wheel - downloads did occur using requirement specifiers, dependencies weren't - downloaded (PR #1527) - -* Fixed #1320. ``pip wheel`` was not downloading wheels that already existed (PR - #1524) - -* Fixed #1111. ``pip install --download`` was failing using local - ``--find-links`` (PR #1524) - -* Workaround for Python bug http://bugs.python.org/issue20053 (PR #1544) - -* Don't pass a unicode __file__ to setup.py on Python 2.x (PR #1583) - -* Verify that the Wheel version is compatible with this pip (PR #1569) - - -**1.5.2 (2014-01-26)** - - -* Upgraded the vendored ``pkg_resources`` and ``_markerlib`` to setuptools 2.1. - -* Fixed an error that prevented accessing PyPI when pyopenssl, ndg-httpsclient, - and pyasn1 are installed - -* Fixed an issue that caused trailing comments to be incorrectly included as - part of the URL in a requirements file - - -**1.5.1 (2014-01-20)** - - -* pip now only requires setuptools (any setuptools, not a certain version) when - installing distributions from src (i.e. not from wheel). (Pull #1434). - -* `get-pip.py` now installs setuptools, when it's not already installed (Pull - #1475) - -* Don't decode downloaded files that have a ``Content-Encoding`` header. (Pull - #1435) - -* Fix to correctly parse wheel filenames with single digit versions. (Pull - #1445) - -* If `--allow-unverified` is used assume it also means `--allow-external`. (Pull - #1457) - - -**1.5 (2014-01-01)** - - -* **BACKWARD INCOMPATIBLE** pip no longer supports the ``--use-mirrors``, - ``-M``, and ``--mirrors`` flags. The mirroring support has been removed. In - order to use a mirror specify it as the primary index with ``-i`` or - ``--index-url``, or as an additional index with ``--extra-index-url``. (Pull #1098, CVE-2013-5123) - -* **BACKWARD INCOMPATIBLE** pip no longer will scrape insecure external urls by - default nor will it install externally hosted files by default. Users may opt - into installing externally hosted or insecure files or urls using - ``--allow-external PROJECT`` and ``--allow-unverified PROJECT``. (Pull #1055) - -* **BACKWARD INCOMPATIBLE** pip no longer respects dependency links by default. - Users may opt into respecting them again using ``--process-dependency-links``. - -* **DEPRECATION** ``pip install --no-install`` and ``pip install - --no-download`` are now formally deprecated. See Issue #906 for discussion on - possible alternatives, or lack thereof, in future releases. - -* **DEPRECATION** ``pip zip`` and ``pip unzip`` are now formally deprecated. - -* pip will now install Mac OSX platform wheels from PyPI. (Pull #1278) - -* pip now generates the appropriate platform-specific console scripts when - installing wheels. (Pull #1251) - -* Pip now confirms a wheel is supported when installing directly from a path or - url. (Pull #1315) - -* Fixed #1097, ``--ignore-installed`` now behaves again as designed, after it was - unintentionally broke in v0.8.3 when fixing Issue #14 (Pull #1352). - -* Fixed a bug where global scripts were being removed when uninstalling --user - installed packages (Pull #1353). - -* Fixed #1163, --user wasn't being respected when installing scripts from wheels (Pull #1176). - -* Fixed #1150, we now assume '_' means '-' in versions from wheel filenames (Pull #1158). - -* Fixed #219, error when using --log with a failed install (Pull #1205). - -* Fixed #1131, logging was buffered and choppy in Python 3. - -* Fixed #70, --timeout was being ignored (Pull #1202). - -* Fixed #772, error when setting PIP_EXISTS_ACTION (Pull #1201). - -* Added colors to the logging output in order to draw attention to important - warnings and errors. (Pull #1109) - -* Added warnings when using an insecure index, find-link, or dependency link. (Pull #1121) - -* Added support for installing packages from a subdirectory using the ``subdirectory`` - editable option. ( Pull #1082 ) - -* Fixed #1192. "TypeError: bad operand type for unary" in some cases when - installing wheels using --find-links (Pull #1218). - -* Fixed #1133 and #317. Archive contents are now written based on system - defaults and umask (i.e. permissions are not preserved), except that regular - files with any execute permissions have the equivalent of "chmod +x" applied - after being written (Pull #1146). - -* PreviousBuildDirError now returns a non-zero exit code and prevents the - previous build dir from being cleaned in all cases (Pull #1162). - -* Renamed --allow-insecure to --allow-unverified, however the old name will - continue to work for a period of time (Pull #1257). - -* Fixed #1006, error when installing local projects with symlinks in - Python 3. (Pull #1311) - -* The previously hidden ``--log-file`` otion, is now shown as a general option. - (Pull #1316) - - -**1.4.1 (2013-08-07)** - - -* **New Signing Key** Release 1.4.1 is using a different key than normal with - fingerprint: 7C6B 7C5D 5E2B 6356 A926 F04F 6E3C BCE9 3372 DCFA -* Fixed issues with installing from pybundle files (Pull #1116). -* Fixed error when sysconfig module throws an exception (Pull #1095). -* Don't ignore already installed pre-releases (Pull #1076). -* Fixes related to upgrading setuptools (Pull #1092). -* Fixes so that --download works with wheel archives (Pull #1113). -* Fixes related to recognizing and cleaning global build dirs (Pull #1080). - - -**1.4 (2013-07-23)** - - -* **BACKWARD INCOMPATIBLE** pip now only installs stable versions by default, - and offers a new ``--pre`` option to also find pre-release and development - versions. (Pull #834) - -* **BACKWARD INCOMPATIBLE** Dropped support for Python 2.5. The minimum - supported Python version for pip 1.4 is Python 2.6. - -* Added support for installing and building wheel archives. - Thanks Daniel Holth, Marcus Smith, Paul Moore, and Michele Lacchia - (Pull #845) - -* Applied security patch to pip's ssl support related to certificate DNS - wildcard matching (http://bugs.python.org/issue17980). - -* To satisfy pip's setuptools requirement, pip now recommends setuptools>=0.8, - not distribute. setuptools and distribute are now merged into one project - called 'setuptools'. (Pull #1003) - -* pip will now warn when installing a file that is either hosted externally to - the index or cannot be verified with a hash. In the future pip will default - to not installing them and will require the flags --allow-external NAME, and - --allow-insecure NAME respectively. (Pull #985) - -* If an already-downloaded or cached file has a bad hash, re-download it rather - than erroring out. (Issue #963). - -* ``pip bundle`` and support for installing from pybundle files is now - considered deprecated and will be removed in pip v1.5. - -* Fixed a number of issues (#413, #709, #634, #602, and #939) related to - cleaning up and not reusing build directories. (Pull #865, #948) - -* Added a User Agent so that pip is identifiable in logs. (Pull #901) - -* Added ssl and --user support to get-pip.py. Thanks Gabriel de Perthuis. - (Pull #895) - -* Fixed the proxy support, which was broken in pip 1.3.x (Pull #840) - -* Fixed issue #32 - pip fails when server does not send content-type header. - Thanks Hugo Lopes Tavares and Kelsey Hightower (Pull #872). - -* "Vendorized" distlib as pip.vendor.distlib (https://distlib.readthedocs.org/). - -* Fixed git VCS backend with git 1.8.3. (Pull #967) - - -**1.3.1 (2013-03-08)** - - -* Fixed a major backward incompatible change of parsing URLs to externally - hosted packages that got accidentily included in 1.3. - - -**1.3 (2013-03-07)** - - -* SSL Cert Verification; Make https the default for PyPI access. - Thanks James Cleveland, Giovanni Bajo, Marcus Smith and many others (Pull #791, CVE-2013-1629). - -* Added "pip list" for listing installed packages and the latest version - available. Thanks Rafael Caricio, Miguel Araujo, Dmitry Gladkov (Pull #752) - -* Fixed security issues with pip's use of temp build directories. - Thanks David (d1b) and Thomas Guttler. (Pull #780, CVE-2013-1888) - -* Improvements to sphinx docs and cli help. (Pull #773) - -* Fixed issue #707, dealing with OS X temp dir handling, which was causing - global NumPy installs to fail. (Pull #768) - -* Split help output into general vs command-specific option groups. - Thanks Georgi Valkov. (Pull #744; Pull #721 contains preceding refactor) - -* Fixed dependency resolution when installing from archives with uppercase - project names. (Pull #724) - -* Fixed problem where re-installs always occurred when using file:// find-links. - (Pulls #683/#702) - -* "pip install -v" now shows the full download url, not just the archive name. - Thanks Marc Abramowitz (Pull #687) - -* Fix to prevent unnecessary PyPI redirects. Thanks Alex Gronholm (Pull #695) - -* Fixed issue #670 - install failure under Python 3 when the same version - of a package is found under 2 different URLs. Thanks Paul Moore (Pull #671) - -* Fix git submodule recursive updates. Thanks Roey Berman. (Pulls #674) - -* Explicitly ignore rel='download' links while looking for html pages. - Thanks Maxime R. (Pull #677) - -* --user/--upgrade install options now work together. Thanks 'eevee' for - discovering the problem. (Pull #705) - -* Added check in ``install --download`` to prevent re-downloading if the target - file already exists. Thanks Andrey Bulgakov. (Pull #669) - -* Added support for bare paths (including relative paths) as argument to - `--find-links`. Thanks Paul Moore for draft patch. - -* Added support for --no-index in requirements files. - -* Added "pip show" command to get information about an installed package. - Fixes #131. Thanks Kelsey Hightower and Rafael Caricio. - -* Added `--root` option for "pip install" to specify root directory. Behaves - like the same option in distutils but also plays nice with pip's egg-info. - Thanks Przemek Wrzos. (Issue #253 / Pull #693) - - -**1.2.1 (2012-09-06)** - - -* Fixed a regression introduced in 1.2 about raising an exception when - not finding any files to uninstall in the current environment. Thanks for - the fix, Marcus Smith. - - -**1.2 (2012-09-01)** - - -* **Dropped support for Python 2.4** The minimum supported Python version is - now Python 2.5. - -* Fixed issue #605 - pypi mirror support broken on some DNS responses. Thanks - philwhin. - -* Fixed issue #355 - pip uninstall removes files it didn't install. Thanks - pjdelport. - -* Fixed issues #493, #494, #440, and #573 related to improving support for the - user installation scheme. Thanks Marcus Smith. - -* Write failure log to temp file if default location is not writable. Thanks - andreigc. - -* Pull in submodules for git editable checkouts. Fixes #289 and #421. Thanks - Hsiaoming Yang and Markus Hametner. - -* Use a temporary directory as the default build location outside of a - virtualenv. Fixes issues #339 and #381. Thanks Ben Rosser. - -* Added support for specifying extras with local editables. Thanks Nick - Stenning. - -* Added ``--egg`` flag to request egg-style rather than flat installation. Refs - issue #3. Thanks Kamal Bin Mustafa. - -* Fixed issue #510 - prevent e.g. ``gmpy2-2.0.tar.gz`` from matching a request - to ``pip install gmpy``; sdist filename must begin with full project name - followed by a dash. Thanks casevh for the report. - -* Fixed issue #504 - allow package URLS to have querystrings. Thanks W. - Trevor King. - -* Fixed issue #58 - pip freeze now falls back to non-editable format rather - than blowing up if it can't determine the origin repository of an editable. - Thanks Rory McCann. - -* Added a `__main__.py` file to enable `python -m pip` on Python versions - that support it. Thanks Alexey Luchko. - -* Fixed issue #487 - upgrade from VCS url of project that does exist on - index. Thanks Andrew Knapp for the report. - -* Fixed issue #486 - fix upgrade from VCS url of project with no distribution - on index. Thanks Andrew Knapp for the report. - -* Fixed issue #427 - clearer error message on a malformed VCS url. Thanks - Thomas Fenzl. - -* Added support for using any of the built in guaranteed algorithms in - ``hashlib`` as a checksum hash. - -* Fixed issue #321 - Raise an exception if current working directory can't be - found or accessed. - -* Fixed issue #82 - Removed special casing of the user directory and use the - Python default instead. - -* Fixed #436 - Only warn about version conflicts if there is actually one. - This re-enables using ``==dev`` in requirements files. - -* Moved tests to be run on Travis CI: http://travis-ci.org/pypa/pip - -* Added a better help formatter. - - -**1.1 (2012-02-16)** - - -* Fixed issue #326 - don't crash when a package's setup.py emits UTF-8 and - then fails. Thanks Marc Abramowitz. - -* Added ``--target`` option for installing directly to arbitrary directory. - Thanks Stavros Korokithakis. - -* Added support for authentication with Subversion repositories. Thanks - Qiangning Hong. - -* Fixed issue #315 - ``--download`` now downloads dependencies as well. - Thanks Qiangning Hong. - -* Errors from subprocesses will display the current working directory. - Thanks Antti Kaihola. - -* Fixed issue #369 - compatibility with Subversion 1.7. Thanks Qiangning - Hong. Note that setuptools remains incompatible with Subversion 1.7; to - get the benefits of pip's support you must use Distribute rather than - setuptools. - -* Fixed issue #57 - ignore py2app-generated OS X mpkg zip files in finder. - Thanks Rene Dudfield. - -* Fixed issue #182 - log to ~/Library/Logs/ by default on OS X framework - installs. Thanks Dan Callahan for report and patch. - -* Fixed issue #310 - understand version tags without minor version ("py3") - in sdist filenames. Thanks Stuart Andrews for report and Olivier Girardot for - patch. - -* Fixed issue #7 - Pip now supports optionally installing setuptools - "extras" dependencies; e.g. "pip install Paste[openid]". Thanks Matt Maker - and Olivier Girardot. - -* Fixed issue #391 - freeze no longer borks on requirements files with - --index-url or --find-links. Thanks Herbert Pfennig. - -* Fixed issue #288 - handle symlinks properly. Thanks lebedov for the patch. - -* Fixed issue #49 - pip install -U no longer reinstalls the same versions of - packages. Thanks iguananaut for the pull request. - -* Removed ``-E``/``--environment`` option and ``PIP_RESPECT_VIRTUALENV``; - both use a restart-in-venv mechanism that's broken, and neither one is - useful since every virtualenv now has pip inside it. Replace ``pip -E - path/to/venv install Foo`` with ``virtualenv path/to/venv && - path/to/venv/pip install Foo``. - -* Fixed issue #366 - pip throws IndexError when it calls `scraped_rel_links` - -* Fixed issue #22 - pip search should set and return a userful shell status code - -* Fixed issue #351 and #365 - added global ``--exists-action`` command line - option to easier script file exists conflicts, e.g. from editable - requirements from VCS that have a changed repo URL. - - -**1.0.2 (2011-07-16)** - - -* Fixed docs issues. -* Fixed issue #295 - Reinstall a package when using the ``install -I`` option -* Fixed issue #283 - Finds a Git tag pointing to same commit as origin/master -* Fixed issue #279 - Use absolute path for path to docs in setup.py -* Fixed issue #314 - Correctly handle exceptions on Python3. -* Fixed issue #320 - Correctly parse ``--editable`` lines in requirements files - - -**1.0.1 (2011-04-30)** - - -* Start to use git-flow. -* Fixed issue #274 - `find_command` should not raise AttributeError -* Fixed issue #273 - respect Content-Disposition header. Thanks Bradley Ayers. -* Fixed issue #233 - pathext handling on Windows. -* Fixed issue #252 - svn+svn protocol. -* Fixed issue #44 - multiple CLI searches. -* Fixed issue #266 - current working directory when running setup.py clean. - - -**1.0 (2011-04-04)** - - -* Added Python 3 support! Huge thanks to Vinay Sajip, Vitaly Babiy, Kelsey - Hightower, and Alex Gronholm, among others. - -* Download progress only shown on a real TTY. Thanks Alex Morega. - -* Fixed finding of VCS binaries to not be fooled by same-named directories. - Thanks Alex Morega. - -* Fixed uninstall of packages from system Python for users of Debian/Ubuntu - python-setuptools package (workaround until fixed in Debian and Ubuntu). - -* Added `get-pip.py `_ - installer. Simply download and execute it, using the Python interpreter of - your choice:: - - $ curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py - $ python get-pip.py - - This may have to be run as root. - - .. note:: - - Make sure you have `distribute `_ - installed before using the installer! - - -**0.8.3** - - -* Moved main repository to Github: https://github.com/pypa/pip - -* Transferred primary maintenance from Ian to Jannis Leidel, Carl Meyer, Brian Rosner - -* Fixed issue #14 - No uninstall-on-upgrade with URL package. Thanks Oliver Tonnhofer - -* Fixed issue #163 - Egg name not properly resolved. Thanks Igor Sobreira - -* Fixed issue #178 - Non-alphabetical installation of requirements. Thanks Igor Sobreira - -* Fixed issue #199 - Documentation mentions --index instead of --index-url. Thanks Kelsey Hightower - -* Fixed issue #204 - rmtree undefined in mercurial.py. Thanks Kelsey Hightower - -* Fixed bug in Git vcs backend that would break during reinstallation. - -* Fixed bug in Mercurial vcs backend related to pip freeze and branch/tag resolution. - -* Fixed bug in version string parsing related to the suffix "-dev". - - -**0.8.2** - - -* Avoid redundant unpacking of bundles (from pwaller) - -* Fixed issue #32, #150, #161 - Fixed checking out the correct - tag/branch/commit when updating an editable Git requirement. - -* Fixed issue #49 - Added ability to install version control requirements - without making them editable, e.g.:: - - pip install git+https://github.com/pypa/pip/ - -* Fixed issue #175 - Correctly locate build and source directory on Mac OS X. - -* Added ``git+https://`` scheme to Git VCS backend. - - -**0.8.1** - - -* Added global --user flag as shortcut for --install-option="--user". From - Ronny Pfannschmidt. - -* Added support for `PyPI mirrors `_ as - defined in `PEP 381 `_, from - Jannis Leidel. - -* Fixed issue #138 - Git revisions ignored. Thanks John-Scott Atlakson. - -* Fixed issue #95 - Initial editable install of github package from a tag fails. Thanks John-Scott Atlakson. - -* Fixed issue #107 - Can't install if a directory in cwd has the same name as the package you're installing. - -* Fixed issue #39 - --install-option="--prefix=~/.local" ignored with -e. - Thanks Ronny Pfannschmidt and Wil Tan. - - -**0.8** - - -* Track which ``build/`` directories pip creates, never remove directories - it doesn't create. From Hugo Lopes Tavares. - -* Pip now accepts file:// index URLs. Thanks Dave Abrahams. - -* Various cleanup to make test-running more consistent and less fragile. - Thanks Dave Abrahams. - -* Real Windows support (with passing tests). Thanks Dave Abrahams. - -* ``pip-2.7`` etc. scripts are created (Python-version specific scripts) - -* ``contrib/build-standalone`` script creates a runnable ``.zip`` form of - pip, from Jannis Leidel - -* Editable git repos are updated when reinstalled - -* Fix problem with ``--editable`` when multiple ``.egg-info/`` directories - are found. - -* A number of VCS-related fixes for ``pip freeze``, from Hugo Lopes Tavares. - -* Significant test framework changes, from Hugo Lopes Tavares. - - -**0.7.2** - - -* Set zip_safe=False to avoid problems some people are encountering where - pip is installed as a zip file. - - -**0.7.1** - - -* Fixed opening of logfile with no directory name. Thanks Alexandre Conrad. - -* Temporary files are consistently cleaned up, especially after - installing bundles, also from Alex Conrad. - -* Tests now require at least ScriptTest 1.0.3. - - -**0.7** - - -* Fixed uninstallation on Windows -* Added ``pip search`` command. -* Tab-complete names of installed distributions for ``pip uninstall``. -* Support tab-completion when there is a global-option before the - subcommand. -* Install header files in standard (scheme-default) location when installing - outside a virtualenv. Install them to a slightly more consistent - non-standard location inside a virtualenv (since the standard location is - a non-writable symlink to the global location). -* pip now logs to a central location by default (instead of creating - ``pip-log.txt`` all over the place) and constantly overwrites the - file in question. On Unix and Mac OS X this is ``'$HOME/.pip/pip.log'`` - and on Windows it's ``'%HOME%\\pip\\pip.log'``. You are still able to - override this location with the ``$PIP_LOG_FILE`` environment variable. - For a complete (appended) logfile use the separate ``'--log'`` command line - option. -* Fixed an issue with Git that left an editable packge as a checkout of a - remote branch, even if the default behaviour would have been fine, too. -* Fixed installing from a Git tag with older versions of Git. -* Expand "~" in logfile and download cache paths. -* Speed up installing from Mercurial repositories by cloning without - updating the working copy multiple times. -* Fixed installing directly from directories (e.g. - ``pip install path/to/dir/``). -* Fixed installing editable packages with ``svn+ssh`` URLs. -* Don't print unwanted debug information when running the freeze command. -* Create log file directory automatically. Thanks Alexandre Conrad. -* Make test suite easier to run successfully. Thanks Dave Abrahams. -* Fixed "pip install ." and "pip install .."; better error for directory - without setup.py. Thanks Alexandre Conrad. -* Support Debian/Ubuntu "dist-packages" in zip command. Thanks duckx. -* Fix relative --src folder. Thanks Simon Cross. -* Handle missing VCS with an error message. Thanks Alexandre Conrad. -* Added --no-download option to install; pairs with --no-install to separate - download and installation into two steps. Thanks Simon Cross. -* Fix uninstalling from requirements file containing -f, -i, or - --extra-index-url. -* Leftover build directories are now removed. Thanks Alexandre Conrad. - - -**0.6.3** - - -* Fixed import error on Windows with regard to the backwards compatibility - package - - -**0.6.2** - - -* Fixed uninstall when /tmp is on a different filesystem. - -* Fixed uninstallation of distributions with namespace packages. - - -**0.6.1** - - -* Added support for the ``https`` and ``http-static`` schemes to the - Mercurial and ``ftp`` scheme to the Bazaar backend. - -* Fixed uninstallation of scripts installed with easy_install. - -* Fixed an issue in the package finder that could result in an - infinite loop while looking for links. - -* Fixed issue with ``pip bundle`` and local files (which weren't being - copied into the bundle), from Whit Morriss. - - -**0.6** - - -* Add ``pip uninstall`` and uninstall-before upgrade (from Carl - Meyer). - -* Extended configurability with config files and environment variables. - -* Allow packages to be upgraded, e.g., ``pip install Package==0.1`` - then ``pip install Package==0.2``. - -* Allow installing/upgrading to Package==dev (fix "Source version does not - match target version" errors). - -* Added command and option completion for bash and zsh. - -* Extended integration with virtualenv by providing an option to - automatically use an active virtualenv and an option to warn if no active - virtualenv is found. - -* Fixed a bug with pip install --download and editable packages, where - directories were being set with 0000 permissions, now defaults to 755. - -* Fixed uninstallation of easy_installed console_scripts. - -* Fixed uninstallation on Mac OS X Framework layout installs - -* Fixed bug preventing uninstall of editables with source outside venv. - -* Creates download cache directory if not existing. - - -**0.5.1** - - -* Fixed a couple little bugs, with git and with extensions. - - -**0.5** - - -* Added ability to override the default log file name (``pip-log.txt``) - with the environmental variable ``$PIP_LOG_FILE``. - -* Made the freeze command print installed packages to stdout instead of - writing them to a file. Use simple redirection (e.g. - ``pip freeze > stable-req.txt``) to get a file with requirements. - -* Fixed problem with freezing editable packages from a Git repository. - -* Added support for base URLs using ```` when parsing - HTML pages. - -* Fixed installing of non-editable packages from version control systems. - -* Fixed issue with Bazaar's bzr+ssh scheme. - -* Added --download-dir option to the install command to retrieve package - archives. If given an editable package it will create an archive of it. - -* Added ability to pass local file and directory paths to ``--find-links``, - e.g. ``--find-links=file:///path/to/my/private/archive`` - -* Reduced the amount of console log messages when fetching a page to find a - distribution was problematic. The full messages can be found in pip-log.txt. - -* Added ``--no-deps`` option to install ignore package dependencies - -* Added ``--no-index`` option to ignore the package index (PyPI) temporarily - -* Fixed installing editable packages from Git branches. - -* Fixes freezing of editable packages from Mercurial repositories. - -* Fixed handling read-only attributes of build files, e.g. of Subversion and - Bazaar on Windows. - -* When downloading a file from a redirect, use the redirected - location's extension to guess the compression (happens specifically - when redirecting to a bitbucket.org tip.gz file). - -* Editable freeze URLs now always use revision hash/id rather than tip or - branch names which could move. - -* Fixed comparison of repo URLs so incidental differences such as - presence/absence of final slashes or quoted/unquoted special - characters don't trigger "ignore/switch/wipe/backup" choice. - -* Fixed handling of attempt to checkout editable install to a - non-empty, non-repo directory. - - -**0.4** - - -* Make ``-e`` work better with local hg repositories - -* Construct PyPI URLs the exact way easy_install constructs URLs (you - might notice this if you use a custom index that is - slash-sensitive). - -* Improvements on Windows (from `Ionel Maries Cristian - `_). - -* Fixed problem with not being able to install private git repositories. - -* Make ``pip zip`` zip all its arguments, not just the first. - -* Fix some filename issues on Windows. - -* Allow the ``-i`` and ``--extra-index-url`` options in requirements - files. - -* Fix the way bundle components are unpacked and moved around, to make - bundles work. - -* Adds ``-s`` option to allow the access to the global site-packages if a - virtualenv is to be created. - -* Fixed support for Subversion 1.6. - - -**0.3.1** - - -* Improved virtualenv restart and various path/cleanup problems on win32. - -* Fixed a regression with installing from svn repositories (when not - using ``-e``). - -* Fixes when installing editable packages that put their source in a - subdirectory (like ``src/``). - -* Improve ``pip -h`` - - -**0.3** - - -* Added support for editable packages created from Git, Mercurial and Bazaar - repositories and ability to freeze them. Refactored support for version - control systems. - -* Do not use ``sys.exit()`` from inside the code, instead use a - return. This will make it easier to invoke programmatically. - -* Put the install record in ``Package.egg-info/installed-files.txt`` - (previously they went in - ``site-packages/install-record-Package.txt``). - -* Fix a problem with ``pip freeze`` not including ``-e svn+`` when an - svn structure is peculiar. - -* Allow ``pip -E`` to work with a virtualenv that uses a different - version of Python than the parent environment. - -* Fixed Win32 virtualenv (``-E``) option. - -* Search the links passed in with ``-f`` for packages. - -* Detect zip files, even when the file doesn't have a ``.zip`` - extension and it is served with the wrong Content-Type. - -* Installing editable from existing source now works, like ``pip - install -e some/path/`` will install the package in ``some/path/``. - Most importantly, anything that package requires will also be - installed by pip. - -* Add a ``--path`` option to ``pip un/zip``, so you can avoid zipping - files that are outside of where you expect. - -* Add ``--simulate`` option to ``pip zip``. - - -**0.2.1** - - -* Fixed small problem that prevented using ``pip.py`` without actually - installing pip. - -* Fixed ``--upgrade``, which would download and appear to install - upgraded packages, but actually just reinstall the existing package. - -* Fixed Windows problem with putting the install record in the right - place, and generating the ``pip`` script with Setuptools. - -* Download links that include embedded spaces or other unsafe - characters (those characters get %-encoded). - -* Fixed use of URLs in requirement files, and problems with some blank - lines. - -* Turn some tar file errors into warnings. - - -**0.2** - - -* Renamed to ``pip``, and to install you now do ``pip install - PACKAGE`` - -* Added command ``pip zip PACKAGE`` and ``pip unzip PACKAGE``. This - is particularly intended for Google App Engine to manage libraries - to stay under the 1000-file limit. - -* Some fixes to bundles, especially editable packages and when - creating a bundle using unnamed packages (like just an svn - repository without ``#egg=Package``). - - -**0.1.4** - - -* Added an option ``--install-option`` to pass options to pass - arguments to ``setup.py install`` - -* ``.svn/`` directories are no longer included in bundles, as these - directories are specific to a version of svn -- if you build a - bundle on a system with svn 1.5, you can't use the checkout on a - system with svn 1.4. Instead a file ``svn-checkout.txt`` is - included that notes the original location and revision, and the - command you can use to turn it back into an svn checkout. (Probably - unpacking the bundle should, maybe optionally, recreate this - information -- but that is not currently implemented, and it would - require network access.) - -* Avoid ambiguities over project name case, where for instance - MyPackage and mypackage would be considered different packages. - This in particular caused problems on Macs, where ``MyPackage/`` and - ``mypackage/`` are the same directory. - -* Added support for an environmental variable - ``$PIP_DOWNLOAD_CACHE`` which will cache package downloads, so - future installations won't require large downloads. Network access - is still required, but just some downloads will be avoided when - using this. - - -**0.1.3** - - -* Always use ``svn checkout`` (not ``export``) so that - ``tag_svn_revision`` settings give the revision of the package. - -* Don't update checkouts that came from ``.pybundle`` files. - - -**0.1.2** - - -* Improve error text when there are errors fetching HTML pages when - seeking packages. - -* Improve bundles: include empty directories, make them work with - editable packages. - -* If you use ``-E env`` and the environment ``env/`` doesn't exist, a - new virtual environment will be created. - -* Fix ``dependency_links`` for finding packages. - - -**0.1.1** - - -* Fixed a NameError exception when running pip outside of a - virtualenv environment. - -* Added HTTP proxy support (from Prabhu Ramachandran) - -* Fixed use of ``hashlib.md5`` on python2.5+ (also from Prabhu - Ramachandran) - - -**0.1** - - -* Initial release diff --git a/vendor/pip-1.5.6/LICENSE.txt b/vendor/pip-1.5.6/LICENSE.txt deleted file mode 100644 index 40d8cda..0000000 --- a/vendor/pip-1.5.6/LICENSE.txt +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2008-2014 The pip developers (see AUTHORS.txt file) - -Permission is hereby granted, free of charge, to any person obtaining -a copy of this software and associated documentation files (the -"Software"), to deal in the Software without restriction, including -without limitation the rights to use, copy, modify, merge, publish, -distribute, sublicense, and/or sell copies of the Software, and to -permit persons to whom the Software is furnished to do so, subject to -the following conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/vendor/pip-1.5.6/MANIFEST.in b/vendor/pip-1.5.6/MANIFEST.in deleted file mode 100644 index 7f84811..0000000 --- a/vendor/pip-1.5.6/MANIFEST.in +++ /dev/null @@ -1,9 +0,0 @@ -include AUTHORS.txt -include LICENSE.txt -include CHANGES.txt -include PROJECT.txt -include pip/cacert.pem -recursive-include docs *.rst -recursive-include docs *.html -recursive-exclude docs/_build *.rst -prune docs/_build/_sources diff --git a/vendor/pip-1.5.6/PKG-INFO b/vendor/pip-1.5.6/PKG-INFO deleted file mode 100644 index c08706c..0000000 --- a/vendor/pip-1.5.6/PKG-INFO +++ /dev/null @@ -1,91 +0,0 @@ -Metadata-Version: 1.1 -Name: pip -Version: 1.5.6 -Summary: A tool for installing and managing Python packages. -Home-page: https://pip.pypa.io/ -Author: The pip developers -Author-email: python-virtualenv@groups.google.com -License: MIT -Description: - Project Info - ============ - - * Project Page: https://github.com/pypa/pip - * Install howto: https://pip.pypa.io/en/latest/installing.html - * Changelog: https://pip.pypa.io/en/latest/news.html - * Bug Tracking: https://github.com/pypa/pip/issues - * Mailing list: http://groups.google.com/group/python-virtualenv - * Docs: https://pip.pypa.io/ - * User IRC: #pypa on Freenode. - * Dev IRC: #pypa-dev on Freenode. - - Quickstart - ========== - - First, :doc:`Install pip `. - - Install a package from `PyPI`_: - - :: - - $ pip install SomePackage - [...] - Successfully installed SomePackage - - Show what files were installed: - - :: - - $ pip show --files SomePackage - Name: SomePackage - Version: 1.0 - Location: /my/env/lib/pythonx.x/site-packages - Files: - ../somepackage/__init__.py - [...] - - List what packages are outdated: - - :: - - $ pip list --outdated - SomePackage (Current: 1.0 Latest: 2.0) - - Upgrade a package: - - :: - - $ pip install --upgrade SomePackage - [...] - Found existing installation: SomePackage 1.0 - Uninstalling SomePackage: - Successfully uninstalled SomePackage - Running setup.py install for SomePackage - Successfully installed SomePackage - - Uninstall a package: - - :: - - $ pip uninstall SomePackage - Uninstalling SomePackage: - /my/env/lib/pythonx.x/site-packages/somepackage - Proceed (y/n)? y - Successfully uninstalled SomePackage - - - .. _PyPI: http://pypi.python.org/pypi/ - -Keywords: easy_install distutils setuptools egg virtualenv -Platform: UNKNOWN -Classifier: Development Status :: 5 - Production/Stable -Classifier: Intended Audience :: Developers -Classifier: License :: OSI Approved :: MIT License -Classifier: Topic :: Software Development :: Build Tools -Classifier: Programming Language :: Python :: 2 -Classifier: Programming Language :: Python :: 2.6 -Classifier: Programming Language :: Python :: 2.7 -Classifier: Programming Language :: Python :: 3 -Classifier: Programming Language :: Python :: 3.1 -Classifier: Programming Language :: Python :: 3.2 -Classifier: Programming Language :: Python :: 3.3 diff --git a/vendor/pip-1.5.6/PROJECT.txt b/vendor/pip-1.5.6/PROJECT.txt deleted file mode 100644 index 60f6c1e..0000000 --- a/vendor/pip-1.5.6/PROJECT.txt +++ /dev/null @@ -1,11 +0,0 @@ -Project Info -============ - -* Project Page: https://github.com/pypa/pip -* Install howto: https://pip.pypa.io/en/latest/installing.html -* Changelog: https://pip.pypa.io/en/latest/news.html -* Bug Tracking: https://github.com/pypa/pip/issues -* Mailing list: http://groups.google.com/group/python-virtualenv -* Docs: https://pip.pypa.io/ -* User IRC: #pypa on Freenode. -* Dev IRC: #pypa-dev on Freenode. diff --git a/vendor/pip-1.5.6/README.rst b/vendor/pip-1.5.6/README.rst deleted file mode 100644 index 5707824..0000000 --- a/vendor/pip-1.5.6/README.rst +++ /dev/null @@ -1,10 +0,0 @@ -pip -=== - -.. image:: https://pypip.in/v/pip/badge.png - :target: https://pypi.python.org/pypi/pip - -.. image:: https://secure.travis-ci.org/pypa/pip.png?branch=develop - :target: http://travis-ci.org/pypa/pip - -For documentation, see https://pip.pypa.io/ diff --git a/vendor/pip-1.5.6/docs/configuration.rst b/vendor/pip-1.5.6/docs/configuration.rst deleted file mode 100644 index e1d0746..0000000 --- a/vendor/pip-1.5.6/docs/configuration.rst +++ /dev/null @@ -1,8 +0,0 @@ -:orphan: - -Configuration -============= - -This content is now covered in the :doc:`User Guide ` - - diff --git a/vendor/pip-1.5.6/docs/cookbook.rst b/vendor/pip-1.5.6/docs/cookbook.rst deleted file mode 100644 index 3da030c..0000000 --- a/vendor/pip-1.5.6/docs/cookbook.rst +++ /dev/null @@ -1,8 +0,0 @@ -:orphan: - -============ -Cookbook -============ - -This content is now covered in the :doc:`User Guide ` - diff --git a/vendor/pip-1.5.6/docs/development.rst b/vendor/pip-1.5.6/docs/development.rst deleted file mode 100644 index a0cc8d6..0000000 --- a/vendor/pip-1.5.6/docs/development.rst +++ /dev/null @@ -1,126 +0,0 @@ -=========== -Development -=========== - -Pull Requests -============= - -Submit Pull Requests against the `develop` branch. - -Provide a good description of what you're doing and why. - -Provide tests that cover your changes and try to run the tests locally first. - -Automated Testing -================= - -All pull requests and merges to 'develop' branch are tested in `Travis `_ -based on our `.travis.yml file `_. - -Usually, a link to your specific travis build appears in pull requests, but if not, -you can find it on our `travis pull requests page `_ - -The only way to trigger Travis to run again for a pull request, is to submit another change to the pull branch. - -We also have Jenkins CI that runs regularly for certain python versions on windows and centos. - -Running tests -============= - -OS Requirements: subversion, bazaar, git, and mercurial. - -Python Requirements: tox or pytest, virtualenv, scripttest, and mock - -Ways to run the tests locally: - -:: - - $ tox -e py33 # The preferred way to run the tests, can use pyNN to - # run for a particular version or leave off the -e to - # run for all versions. - $ python setup.py test # Using the setuptools test plugin - $ py.test # Using py.test directly - $ tox # Using tox against pip's tox.ini - - -Getting Involved -================ - -The pip project welcomes help in the following ways: - -- Making Pull Requests for code, tests, or docs. -- Commenting on open issues and pull requests. -- Helping to answer questions on the mailing list. - -If you want to become an official maintainer, start by helping out. - -Later, when you think you're ready, get in touch with one of the maintainers, -and they will initiate a vote. - -Release Process -=============== - -This process includes virtualenv, since pip releases necessitate a virtualenv release. - -As an example, the instructions assume we're releasing pip-1.4, and virtualenv-1.10. - -1. Upgrade setuptools, if needed: - - #. Upgrade setuptools in ``virtualenv/develop`` using the :ref:`Refresh virtualenv` process. - #. Create a pull request against ``pip/develop`` with a modified ``.travis.yml`` file that installs virtualenv from ``virtualenv/develop``, to confirm the travis builds are still passing. - -2. Create Release branches: - - #. Create ``pip/release-1.4`` branch. - #. In ``pip/develop``, change ``pip.version`` to '1.5.dev1'. - #. Create ``virtualenv/release-1.10`` branch. - #. In ``virtualenv/develop``, change ``virtualenv.version`` to '1.11.dev1'. - -3. Prepare "rcX": - - #. In ``pip/release-1.4``, change ``pip.version`` to '1.4rcX', and tag with '1.4rcX'. - #. Build a pip sdist from ``pip/release-1.4``, and build it into ``virtualenv/release-1.10`` using the :ref:`Refresh virtualenv` process. - #. In ``virtualenv/release-1.10``, change ``virtualenv.version`` to '1.10rcX', and tag with '1.10rcX'. - -4. Announce ``pip-1.4rcX`` and ``virtualenv-1.10rcX`` with the :ref:`RC Install Instructions` and elicit feedback. - -5. Apply fixes to 'rcX': - - #. Apply fixes to ``pip/release-1.4`` and ``virtualenv/release-1.10`` - #. Periodically merge fixes to ``pip/develop`` and ``virtualenv/develop`` - -6. Repeat #4 thru #6 if needed. - -7. Final Release: - - #. In ``pip/release-1.4``, change ``pip.version`` to '1.4', and tag with '1.4'. - #. Merge ``pip/release-1.4`` to ``pip/master``. - #. Build a pip sdist from ``pip/release-1.4``, and load it into ``virtualenv/release-1.10`` using the :ref:`Refresh virtualenv` process. - #. Merge ``vitualenv/release-1.10`` to ``virtualenv/develop``. - #. In ``virtualenv/release-1.10``, change ``virtualenv.version`` to '1.10', and tag with '1.10'. - #. Merge ``virtualenv/release-1.10`` to ``virtualenv/master`` - #. Build and upload pip and virtualenv sdists to PyPI. - -.. _`Refresh virtualenv`: - -Refresh virtualenv -++++++++++++++++++ - -#. Update the embedded versions of pip and setuptools in ``virtualenv_support``. -#. Run ``bin/rebuild-script.py`` to rebuild virtualenv based on the latest versions. - - -.. _`RC Install Instructions`: - -RC Install Instructions -+++++++++++++++++++++++ - -:: - - $ curl -L -O https://github.com/pypa/virtualenv/archive/1.10rc1.tar.gz - $ echo " 1.10rc1.tar.gz" | md5sum -c - 1.10rc1.tar.gz: OK - $ tar zxf 1.10rc1.tar.gz - $ python virtualenv-1.10rc1/virtualenv.py myVE - $ myVE/bin/pip install SomePackage - diff --git a/vendor/pip-1.5.6/docs/distribute_setuptools.rst b/vendor/pip-1.5.6/docs/distribute_setuptools.rst deleted file mode 100644 index f47dbf8..0000000 --- a/vendor/pip-1.5.6/docs/distribute_setuptools.rst +++ /dev/null @@ -1,69 +0,0 @@ -:orphan: - -"ImportError: No module named setuptools" -+++++++++++++++++++++++++++++++++++++++++ - -Although using ``pip install --upgrade setuptools`` to upgrade from distribute -to setuptools works in isolation, it's possible to get "ImportError: No module -named setuptools" when using pip<1.4 to upgrade a package that depends on -setuptools or distribute. - -e.g. when running a command like this: `pip install --upgrade pyramid` - -Solution -~~~~~~~~ - -To prevent the problem in *new* environments (that aren't broken yet): - -* Option 1: - - * *First* run `pip install -U setuptools`, - * *Then* run the command to upgrade your package (e.g. `pip install --upgrade pyramid`) - -* Option 2: - - * Upgrade pip using :ref:`get-pip ` - * *Then* run the command to upgrade your package (e.g. `pip install --upgrade pyramid`) - -To fix the problem once it's occurred, you'll need to manually install the new -setuptools, then rerun the upgrade that failed. - -1. Download `ez_setup.py` (https://bitbucket.org/pypa/setuptools/downloads/ez_setup.py) -2. Run `python ez_setup.py` -3. Then rerun your upgrade (e.g. `pip install --upgrade pyramid`) - - -Cause -~~~~~ - -distribute-0.7.3 is just an empty wrapper that only serves to require the new -setuptools (setuptools>=0.7) so that it will be installed. (If you don't know -yet, the "new setuptools" is a merge of distribute and setuptools back into one -project). - -distribute-0.7.3 does its job well, when the upgrade is done in isolation. -E.g. if you're currently on distribute-0.6.X, then running `pip install -U -setuptools` works fine to upgrade you to setuptools>=0.7. - -The problem occurs when: - -1. you are currently using an older distribute (i.e. 0.6.X) -2. and you try to use pip to upgrade a package that *depends* on setuptools or - distribute. - -As part of the upgrade process, pip builds an install list that ends up -including distribute-0.7.3 and setuptools>=0.7 , but they can end up being -separated by other dependencies in the list, so what can happen is this: - -1. pip uninstalls the existing distribute -2. pip installs distribute-0.7.3 (which has no importable setuptools, that pip - *needs* internally to function) -3. pip moves on to install another dependency (before setuptools>=0.7) and is - unable to proceed without the setuptools package - -Note that pip v1.4 has fixes to prevent this. distribute-0.7.3 (or -setuptools>=0.7) by themselves cannot prevent this kind of problem. - - -.. _setuptools: https://pypi.python.org/pypi/setuptools -.. _distribute: https://pypi.python.org/pypi/distribute diff --git a/vendor/pip-1.5.6/docs/index.rst b/vendor/pip-1.5.6/docs/index.rst deleted file mode 100644 index e17f9e8..0000000 --- a/vendor/pip-1.5.6/docs/index.rst +++ /dev/null @@ -1,25 +0,0 @@ -pip -=== - -`User list `_ | -`Dev list `_ | -`Github `_ | -`PyPI `_ | -User IRC: #pypa | -Dev IRC: #pypa-dev - -The `PyPA recommended -`_ -tool for installing and managing Python packages. - -.. toctree:: - :maxdepth: 2 - - quickstart - installing - user_guide - reference/index - development - news - - diff --git a/vendor/pip-1.5.6/docs/installing.rst b/vendor/pip-1.5.6/docs/installing.rst deleted file mode 100644 index ab00835..0000000 --- a/vendor/pip-1.5.6/docs/installing.rst +++ /dev/null @@ -1,88 +0,0 @@ -.. _`Installation`: - -Installation -============ - -Python & OS Support -------------------- - -pip works with CPython versions 2.6, 2.7, 3.1, 3.2, 3.3, 3.4 and also pypy. - -pip works on Unix/Linux, OS X, and Windows. - -.. note:: - - Python 2.5 was supported through v1.3.1, and Python 2.4 was supported through v1.1. - - -.. _`get-pip`: - -Install pip ------------ - -To install or upgrade pip, securely download `get-pip.py -`_. [1]_ - -Then run the following (which may require administrator access):: - - python get-pip.py - -If `setuptools`_ (or `distribute`_) is not already installed, ``get-pip.py`` will -install `setuptools`_ for you. [2]_ - -To upgrade an existing `setuptools`_ (or `distribute`_), run ``pip install -U setuptools`` [3]_ - - -Upgrade pip ------------ - -On Linux or OS X: - -:: - - pip install -U pip - - -On Windows [4]_: - -:: - - python -m pip install -U pip - - - -Using Package Managers ----------------------- - -On Linux, pip will generally be available for the system install of python using -the system package manager, although often the latest version will be -unavailable. - -On Debian and Ubuntu:: - - sudo apt-get install python-pip - -On Fedora:: - - sudo yum install python-pip - - ----- - -.. [1] "Secure" in this context means using a modern browser or a - tool like `curl` that verifies SSL certificates when downloading from - https URLs. - -.. [2] Beginning with pip v1.5.1, ``get-pip.py`` stopped requiring setuptools to - be installed first. - -.. [3] Although using ``pip install --upgrade setuptools`` to upgrade from - distribute to setuptools works in isolation, it's possible to get - "ImportError: No module named setuptools" when using pip<1.4 to upgrade a - package that depends on setuptools or distribute. See :doc:`here for - details `. - -.. [4] https://github.com/pypa/pip/issues/1299 - -.. _setuptools: https://pypi.python.org/pypi/setuptools -.. _distribute: https://pypi.python.org/pypi/distribute diff --git a/vendor/pip-1.5.6/docs/logic.rst b/vendor/pip-1.5.6/docs/logic.rst deleted file mode 100644 index 0c27d8c..0000000 --- a/vendor/pip-1.5.6/docs/logic.rst +++ /dev/null @@ -1,8 +0,0 @@ -:orphan: - -================ -Internal Details -================ - -This content is now covered in the :doc:`Reference Guide ` - diff --git a/vendor/pip-1.5.6/docs/news.rst b/vendor/pip-1.5.6/docs/news.rst deleted file mode 100644 index f329111..0000000 --- a/vendor/pip-1.5.6/docs/news.rst +++ /dev/null @@ -1,5 +0,0 @@ -============= -Release Notes -============= - -.. include:: ../CHANGES.txt diff --git a/vendor/pip-1.5.6/docs/quickstart.rst b/vendor/pip-1.5.6/docs/quickstart.rst deleted file mode 100644 index 84a9bb8..0000000 --- a/vendor/pip-1.5.6/docs/quickstart.rst +++ /dev/null @@ -1,56 +0,0 @@ -Quickstart -========== - -First, :doc:`Install pip `. - -Install a package from `PyPI`_: - -:: - - $ pip install SomePackage - [...] - Successfully installed SomePackage - -Show what files were installed: - -:: - - $ pip show --files SomePackage - Name: SomePackage - Version: 1.0 - Location: /my/env/lib/pythonx.x/site-packages - Files: - ../somepackage/__init__.py - [...] - -List what packages are outdated: - -:: - - $ pip list --outdated - SomePackage (Current: 1.0 Latest: 2.0) - -Upgrade a package: - -:: - - $ pip install --upgrade SomePackage - [...] - Found existing installation: SomePackage 1.0 - Uninstalling SomePackage: - Successfully uninstalled SomePackage - Running setup.py install for SomePackage - Successfully installed SomePackage - -Uninstall a package: - -:: - - $ pip uninstall SomePackage - Uninstalling SomePackage: - /my/env/lib/pythonx.x/site-packages/somepackage - Proceed (y/n)? y - Successfully uninstalled SomePackage - - -.. _PyPI: http://pypi.python.org/pypi/ diff --git a/vendor/pip-1.5.6/docs/reference/index.rst b/vendor/pip-1.5.6/docs/reference/index.rst deleted file mode 100644 index 8322f8f..0000000 --- a/vendor/pip-1.5.6/docs/reference/index.rst +++ /dev/null @@ -1,17 +0,0 @@ -=============== -Reference Guide -=============== - -.. toctree:: - :maxdepth: 2 - - pip - pip_install - pip_uninstall - pip_freeze - pip_list - pip_show - pip_search - pip_wheel - - diff --git a/vendor/pip-1.5.6/docs/reference/pip.rst b/vendor/pip-1.5.6/docs/reference/pip.rst deleted file mode 100644 index 3becdfd..0000000 --- a/vendor/pip-1.5.6/docs/reference/pip.rst +++ /dev/null @@ -1,80 +0,0 @@ - -pip ---- - -.. contents:: - -Usage -***** - -:: - - pip [options] - - -Description -*********** - - -.. _`Logging`: - -Logging -======= - -Console logging -~~~~~~~~~~~~~~~ - -pip offers :ref:`-v, --verbose <--verbose>` and :ref:`-q, --quiet <--quiet>` -to control the console log level. Each option can be used multiple times and -used together. One ``-v`` increases the verbosity by one, whereas one ``-q`` decreases it by -one. - -The series of log levels, in order, are as follows:: - - VERBOSE_DEBUG, DEBUG, INFO, NOTIFY, WARN, ERROR, FATAL - -``NOTIFY`` is the default level. - -A few examples on how the parameters work to affect the level: - -* specifying nothing results in ``NOTIFY`` -* ``-v`` results in ``INFO`` -* ``-vv`` results in ``DEBUG`` -* ``-q`` results in ``WARN`` -* ``-vq`` results in ``NOTIFY`` - -The most practical use case for users is either ``-v`` or ``-vv`` to see -additional logging to help troubleshoot an issue. - - -.. _`FileLogging`: - -File logging -~~~~~~~~~~~~ - -pip offers the :ref:`--log <--log>` option for specifying a file where a maximum -verbosity log will be kept. This option is empty by default. This log appends -to previous logging. - -Additionally, when commands fail (i.e. return a non-zero exit code), pip writes -a "failure log" for the failed command. This log overwrites previous -logging. The default location is as follows: - -* On Unix and Mac OS X: :file:`$HOME/.pip/pip.log` -* On Windows, the configuration file is: :file:`%HOME%\\pip\\pip.log` - -The option for the failure log, is :ref:`--log-file <--log-file>`. - -Both logs add a line per execution to specify the date and what pip executable wrote the log. - -Like all pip options, ``--log`` and ``log-file``, can also be set as an environment -variable, or placed into the pip config file. See the :ref:`Configuration` -section. - -.. _`General Options`: - -General Options -*************** - -.. pip-general-options:: - diff --git a/vendor/pip-1.5.6/docs/reference/pip_freeze.rst b/vendor/pip-1.5.6/docs/reference/pip_freeze.rst deleted file mode 100644 index 360b69d..0000000 --- a/vendor/pip-1.5.6/docs/reference/pip_freeze.rst +++ /dev/null @@ -1,46 +0,0 @@ - -.. _`pip freeze`: - -pip freeze ------------ - -.. contents:: - -Usage -***** - -.. pip-command-usage:: freeze - - -Description -*********** - -.. pip-command-description:: freeze - - -Options -******* - -.. pip-command-options:: freeze - - -Examples -******** - -1) Generate output suitable for a requirements file. - - :: - - $ pip freeze - Jinja2==2.6 - Pygments==1.5 - Sphinx==1.1.3 - docutils==0.9.1 - - -2) Generate a requirements file and then install from it in another environment. - - :: - - $ env1/bin/pip freeze > requirements.txt - $ env2/bin/pip install -r requirements.txt diff --git a/vendor/pip-1.5.6/docs/reference/pip_install.rst b/vendor/pip-1.5.6/docs/reference/pip_install.rst deleted file mode 100644 index 11c596d..0000000 --- a/vendor/pip-1.5.6/docs/reference/pip_install.rst +++ /dev/null @@ -1,439 +0,0 @@ - -.. _`pip install`: - -pip install ------------ - -.. contents:: - -Usage -***** - -.. pip-command-usage:: install - -Description -*********** - -.. pip-command-description:: install - - -.. _`Requirements File Format`: - -Requirements File Format -++++++++++++++++++++++++ - -Each line of the requirements file indicates something to be installed, -and like arguments to :ref:`pip install`, the following forms are supported:: - - - - [-e] - [-e] - -See the :ref:`pip install Examples` for examples of all these forms. - -A line beginning with ``#`` is treated as a comment and ignored. - -Additionally, the following Package Index Options are supported: - - * :ref:`-i, --index-url <--index-url>` - * :ref:`--extra-index-url <--extra-index-url>` - * :ref:`--no-index <--no-index>` - * :ref:`-f, --find-links <--find-links>` - * :ref:`--allow-external <--allow-external>` - * :ref:`--allow-all-external <--allow-external>` - * :ref:`--allow-unverified <--allow-unverified>` - -For example, to specify :ref:`--no-index <--no-index>` and 2 :ref:`--find-links <--find-links>` locations: - -:: - ---no-index ---find-links /my/local/archives ---find-links http://some.archives.com/archives - - -Lastly, if you wish, you can refer to other requirements files, like this:: - - -r more_requirements.txt - -.. _`Requirement Specifiers`: - -Requirement Specifiers -++++++++++++++++++++++ - -pip supports installing from "requirement specifiers" as implemented in -`pkg_resources Requirements `_ - -Some Examples: - - :: - - 'FooProject >= 1.2' - Fizzy [foo, bar] - 'PickyThing<1.6,>1.9,!=1.9.6,<2.0a0,==2.4c1' - SomethingWhoseVersionIDontCareAbout - -.. note:: - - Use single or double quotes around specifiers to avoid ``>`` and ``<`` being - interpreted as shell redirects. e.g. ``pip install 'FooProject>=1.2'``. - - - - -.. _`Pre Release Versions`: - -Pre-release Versions -++++++++++++++++++++ - -Starting with v1.4, pip will only install stable versions as specified by -`PEP426`_ by default. If a version cannot be parsed as a compliant `PEP426`_ -version then it is assumed to be a pre-release. - -If a Requirement specifier includes a pre-release or development version -(e.g. ``>=0.0.dev0``) then pip will allow pre-release and development versions -for that requirement. This does not include the != flag. - -The ``pip install`` command also supports a :ref:`--pre ` flag -that will enable installing pre-releases and development releases. - - -.. _PEP426: http://www.python.org/dev/peps/pep-0426 - -.. _`Externally Hosted Files`: - -Externally Hosted Files -+++++++++++++++++++++++ - -Starting with v1.4, pip will warn about installing any file that does not come -from the primary index. As of version 1.5, pip defaults to ignoring these files -unless asked to consider them. - -The ``pip install`` command supports a -:ref:`--allow-external PROJECT <--allow-external>` option that will enable -installing links that are linked directly from the simple index but to an -external host that also have a supported hash fragment. Externally hosted -files for all projects may be enabled using the -:ref:`--allow-all-external <--allow-all-external>` flag to the ``pip install`` -command. - -The ``pip install`` command also supports a -:ref:`--allow-unverified PROJECT <--allow-unverified>` option that will enable -installing insecurely linked files. These are either directly linked (as above) -files without a hash, or files that are linked from either the home page or the -download url of a package. - -These options can be used in a requirements file. Assuming some fictional -`ExternalPackage` that is hosted external and unverified, then your requirements -file would be like so:: - - --allow-external ExternalPackage - --allow-unverified ExternalPackage - ExternalPackage - - -.. _`VCS Support`: - -VCS Support -+++++++++++ - -pip supports installing from Git, Mercurial, Subversion and Bazaar, and detects -the type of VCS using url prefixes: "git+", "hg+", "bzr+", "svn+". - -pip requires a working VCS command on your path: git, hg, svn, or bzr. - -VCS projects can be installed in :ref:`editable mode ` (using -the :ref:`--editable ` option) or not. - -* For editable installs, the clone location by default is "/src/SomeProject" in virtual environments, and "/src/SomeProject" - for global installs. The :ref:`--src ` option can be used to - modify this location. -* For non-editable installs, the project is built locally in a temp dir and then - installed normally. - -The url suffix "egg=" is used by pip in it's dependency logic to -identify the project prior to pip downloading and analyzing the metadata. - -Git -~~~ - -pip currently supports cloning over ``git``, ``git+https`` and ``git+ssh``: - -Here are the supported forms:: - - [-e] git+git://git.myproject.org/MyProject#egg=MyProject - [-e] git+https://git.myproject.org/MyProject#egg=MyProject - [-e] git+ssh://git.myproject.org/MyProject#egg=MyProject - -e git+git@git.myproject.org:MyProject#egg=MyProject - -Passing branch names, a commit hash or a tag name is possible like so:: - - [-e] git://git.myproject.org/MyProject.git@master#egg=MyProject - [-e] git://git.myproject.org/MyProject.git@v1.0#egg=MyProject - [-e] git://git.myproject.org/MyProject.git@da39a3ee5e6b4b0d3255bfef95601890afd80709#egg=MyProject - -Mercurial -~~~~~~~~~ - -The supported schemes are: ``hg+http``, ``hg+https``, -``hg+static-http`` and ``hg+ssh``. - -Here are the supported forms:: - - [-e] hg+http://hg.myproject.org/MyProject#egg=MyProject - [-e] hg+https://hg.myproject.org/MyProject#egg=MyProject - [-e] hg+ssh://hg.myproject.org/MyProject#egg=MyProject - -You can also specify a revision number, a revision hash, a tag name or a local -branch name like so:: - - [-e] hg+http://hg.myproject.org/MyProject@da39a3ee5e6b#egg=MyProject - [-e] hg+http://hg.myproject.org/MyProject@2019#egg=MyProject - [-e] hg+http://hg.myproject.org/MyProject@v1.0#egg=MyProject - [-e] hg+http://hg.myproject.org/MyProject@special_feature#egg=MyProject - -Subversion -~~~~~~~~~~ - -pip supports the URL schemes ``svn``, ``svn+svn``, ``svn+http``, ``svn+https``, ``svn+ssh``. - -You can also give specific revisions to an SVN URL, like so:: - - [-e] svn+svn://svn.myproject.org/svn/MyProject#egg=MyProject - [-e] svn+http://svn.myproject.org/svn/MyProject/trunk@2019#egg=MyProject - -which will check out revision 2019. ``@{20080101}`` would also check -out the revision from 2008-01-01. You can only check out specific -revisions using ``-e svn+...``. - -Bazaar -~~~~~~ - -pip supports Bazaar using the ``bzr+http``, ``bzr+https``, ``bzr+ssh``, -``bzr+sftp``, ``bzr+ftp`` and ``bzr+lp`` schemes. - -Here are the supported forms:: - - [-e] bzr+http://bzr.myproject.org/MyProject/trunk#egg=MyProject - [-e] bzr+sftp://user@myproject.org/MyProject/trunk#egg=MyProject - [-e] bzr+ssh://user@myproject.org/MyProject/trunk#egg=MyProject - [-e] bzr+ftp://user@myproject.org/MyProject/trunk#egg=MyProject - [-e] bzr+lp:MyProject#egg=MyProject - -Tags or revisions can be installed like so:: - - [-e] bzr+https://bzr.myproject.org/MyProject/trunk@2019#egg=MyProject - [-e] bzr+http://bzr.myproject.org/MyProject/trunk@v1.0#egg=MyProject - - -Finding Packages -++++++++++++++++ - -pip searches for packages on `PyPI`_ using the -`http simple interface `_, -which is documented `here `_ -and `there `_ - -pip offers a number of Package Index Options for modifying how packages are found. - -See the :ref:`pip install Examples`. - - -.. _`SSL Certificate Verification`: - -SSL Certificate Verification -++++++++++++++++++++++++++++ - -Starting with v1.3, pip provides SSL certificate verification over https, for the purpose -of providing secure, certified downloads from PyPI. - - -Hash Verification -+++++++++++++++++ - -PyPI provides md5 hashes in the hash fragment of package download urls. - -pip supports checking this, as well as any of the -guaranteed hashlib algorithms (sha1, sha224, sha384, sha256, sha512, md5). - -The hash fragment is case sensitive (i.e. sha1 not SHA1). - -This check is only intended to provide basic download corruption protection. -It is not intended to provide security against tampering. For that, -see :ref:`SSL Certificate Verification` - - -Download Cache -++++++++++++++ - -pip offers a :ref:`--download-cache ` option for -installs to prevent redundant downloads of archives from PyPI. - -The point of this cache is *not* to circumvent the index crawling process, but -to *just* prevent redundant downloads. - -Items are stored in this cache based on the url the archive was found at, not -simply the archive name. - -If you want a fast/local install solution that circumvents crawling PyPI, see -the :ref:`Fast & Local Installs`. - -Like all options, :ref:`--download-cache `, can also -be set as an environment variable, or placed into the pip config file. See the -:ref:`Configuration` section. - - -.. _`editable-installs`: - -"Editable" Installs -+++++++++++++++++++ - -"Editable" installs are fundamentally `"setuptools develop mode" -`_ -installs. - -You can install local projects or VCS projects in "editable" mode:: - -$ pip install -e path/to/SomeProject -$ pip install -e git+http://repo/my_project.git#egg=SomeProject - -For local projects, the "SomeProject.egg-info" directory is created relative to -the project path. This is one advantage over just using ``setup.py develop``, -which creates the "egg-info" directly relative the current working directory. - - - -Controlling setup_requires -++++++++++++++++++++++++++ - -Setuptools offers the ``setup_requires`` `setup() keyword -`_ -for specifying dependencies that need to be present in order for the `setup.py` -script to run. Internally, Setuptools uses ``easy_install`` to fulfill these -dependencies. - -pip has no way to control how these dependencies are located. None of the -Package Index Options have an effect. - -The solution is to configure a "system" or "personal" `Distutils configuration -file -`_ to -manage the fulfillment. - -For example, to have the dependency located at an alternate index, add this: - -:: - - [easy_install] - index_url = https://my.index-mirror.com - -To have the dependency located from a local directory and not crawl PyPI, add this: - -:: - - [easy_install] - allow_hosts = '' - find_links = file:///path/to/local/archives - - - -Options -******* - -.. pip-command-options:: install - -.. pip-index-options:: - - -.. _`pip install Examples`: - -Examples -******** - -1) Install `SomePackage` and it's dependencies from `PyPI`_ using :ref:`Requirement Specifiers` - - :: - - $ pip install SomePackage # latest version - $ pip install SomePackage==1.0.4 # specific version - $ pip install 'SomePackage>=1.0.4' # minimum version - - -2) Install a list of requirements specified in a file. See the :ref:`Requirements files `. - - :: - - $ pip install -r requirements.txt - - -3) Upgrade an already installed `SomePackage` to the latest from PyPI. - - :: - - $ pip install --upgrade SomePackage - - -4) Install a local project in "editable" mode. See the section on :ref:`Editable Installs `. - - :: - - $ pip install -e . # project in current directory - $ pip install -e path/to/project # project in another directory - - -5) Install a project from VCS in "editable" mode. See the sections on :ref:`VCS Support ` and :ref:`Editable Installs `. - - :: - - $ pip install -e git+https://git.repo/some_pkg.git#egg=SomePackage # from git - $ pip install -e hg+https://hg.repo/some_pkg.git#egg=SomePackage # from mercurial - $ pip install -e svn+svn://svn.repo/some_pkg/trunk/#egg=SomePackage # from svn - $ pip install -e git+https://git.repo/some_pkg.git@feature#egg=SomePackage # from 'feature' branch - $ pip install -e git+https://git.repo/some_repo.git@egg=subdir&subdirectory=subdir_path # install a python package from a repo subdirectory - -6) Install a package with `setuptools extras`_. - - :: - - $ pip install SomePackage[PDF] - $ pip install SomePackage[PDF]==3.0 - $ pip install -e .[PDF]==3.0 # editable project in current directory - - -7) Install a particular source archive file. - - :: - - $ pip install ./downloads/SomePackage-1.0.4.tar.gz - $ pip install http://my.package.repo/SomePackage-1.0.4.zip - - -8) Install from alternative package repositories. - - Install from a different index, and not `PyPI`_ :: - - $ pip install --index-url http://my.package.repo/simple/ SomePackage - - Search an additional index during install, in addition to `PyPI`_ :: - - $ pip install --extra-index-url http://my.package.repo/simple SomePackage - - Install from a local flat directory containing archives (and don't scan indexes):: - - $ pip install --no-index --find-links=file:///local/dir/ SomePackage - $ pip install --no-index --find-links=/local/dir/ SomePackage - $ pip install --no-index --find-links=relative/dir/ SomePackage - - -9) Find pre-release and development versions, in addition to stable versions. By default, pip only finds stable versions. - - :: - - $ pip install --pre SomePackage - - - -.. _PyPI: http://pypi.python.org/pypi/ -.. _setuptools extras: http://packages.python.org/setuptools/setuptools.html#declaring-extras-optional-features-with-their-own-dependencies diff --git a/vendor/pip-1.5.6/docs/reference/pip_list.rst b/vendor/pip-1.5.6/docs/reference/pip_list.rst deleted file mode 100644 index feb5f21..0000000 --- a/vendor/pip-1.5.6/docs/reference/pip_list.rst +++ /dev/null @@ -1,45 +0,0 @@ -.. _`pip list`: - -pip list ---------- - -.. contents:: - -Usage -***** - -.. pip-command-usage:: list - -Description -*********** - -.. pip-command-description:: list - -Options -******* - -.. pip-command-options:: list - -.. pip-index-options:: - - -Examples -******** - -1) List installed packages. - - :: - - $ pip list - Pygments (1.5) - docutils (0.9.1) - Sphinx (1.1.2) - Jinja2 (2.6) - -2) List outdated packages (excluding editables), and the latest version available - - :: - - $ pip list --outdated - docutils (Current: 0.9.1 Latest: 0.10) - Sphinx (Current: 1.1.2 Latest: 1.1.3) diff --git a/vendor/pip-1.5.6/docs/reference/pip_search.rst b/vendor/pip-1.5.6/docs/reference/pip_search.rst deleted file mode 100644 index 4a2a2dd..0000000 --- a/vendor/pip-1.5.6/docs/reference/pip_search.rst +++ /dev/null @@ -1,36 +0,0 @@ -.. _`pip search`: - -pip search ----------- - -.. contents:: - -Usage -***** - -.. pip-command-usage:: search - - -Description -*********** - -.. pip-command-description:: search - -Options -******* - -.. pip-command-options:: search - - -Examples -******** - -1. Search for "peppercorn" - - :: - - $ pip search peppercorn - pepperedform - Helpers for using peppercorn with formprocess. - peppercorn - A library for converting a token stream into [...] - -.. _`pip wheel`: diff --git a/vendor/pip-1.5.6/docs/reference/pip_show.rst b/vendor/pip-1.5.6/docs/reference/pip_show.rst deleted file mode 100644 index 0fc5058..0000000 --- a/vendor/pip-1.5.6/docs/reference/pip_show.rst +++ /dev/null @@ -1,37 +0,0 @@ -.. _`pip show`: - -pip show --------- - -.. contents:: - -Usage -***** - -.. pip-command-usage:: show - -Description -*********** - -.. pip-command-description:: show - - -Options -******* - -.. pip-command-options:: show - - -Examples -******** - -1. Show information about a package: - - :: - - $ pip show sphinx - --- - Name: Sphinx - Version: 1.1.3 - Location: /my/env/lib/pythonx.x/site-packages - Requires: Pygments, Jinja2, docutils diff --git a/vendor/pip-1.5.6/docs/reference/pip_uninstall.rst b/vendor/pip-1.5.6/docs/reference/pip_uninstall.rst deleted file mode 100644 index 7025981..0000000 --- a/vendor/pip-1.5.6/docs/reference/pip_uninstall.rst +++ /dev/null @@ -1,37 +0,0 @@ -.. _`pip uninstall`: - -pip uninstall -------------- - -.. contents:: - -Usage -***** - -.. pip-command-usage:: uninstall - -Description -*********** - -.. pip-command-description:: uninstall - -Options -******* - -.. pip-command-options:: uninstall - - -Examples -******** - -1) Uninstall a package. - - :: - - $ pip uninstall simplejson - Uninstalling simplejson: - /home/me/env/lib/python2.7/site-packages/simplejson - /home/me/env/lib/python2.7/site-packages/simplejson-2.2.1-py2.7.egg-info - Proceed (y/n)? y - Successfully uninstalled simplejson - diff --git a/vendor/pip-1.5.6/docs/reference/pip_wheel.rst b/vendor/pip-1.5.6/docs/reference/pip_wheel.rst deleted file mode 100644 index e64f383..0000000 --- a/vendor/pip-1.5.6/docs/reference/pip_wheel.rst +++ /dev/null @@ -1,37 +0,0 @@ - -.. _`pip wheel`: - -pip wheel ---------- - -.. contents:: - -Usage -***** - -.. pip-command-usage:: wheel - - -Description -*********** - -.. pip-command-description:: wheel - - -Options -******* - -.. pip-command-options:: wheel - -.. pip-index-options:: - - -Examples -******** - -1. Build wheels for a requirement (and all its dependencies), and then install - - :: - - $ pip wheel --wheel-dir=/tmp/wheelhouse SomePackage - $ pip install --no-index --find-links=/tmp/wheelhouse SomePackage diff --git a/vendor/pip-1.5.6/docs/usage.rst b/vendor/pip-1.5.6/docs/usage.rst deleted file mode 100644 index 5108803..0000000 --- a/vendor/pip-1.5.6/docs/usage.rst +++ /dev/null @@ -1,8 +0,0 @@ -:orphan: - -========== -Usage -========== - -The "Usage" section is now covered in the :doc:`Reference Guide ` - diff --git a/vendor/pip-1.5.6/docs/user_guide.rst b/vendor/pip-1.5.6/docs/user_guide.rst deleted file mode 100644 index cd0146f..0000000 --- a/vendor/pip-1.5.6/docs/user_guide.rst +++ /dev/null @@ -1,509 +0,0 @@ -========== -User Guide -========== - -.. contents:: - -Installing Packages -******************* - -pip supports installing from `PyPI`_, version control, local projects, and -directly from distribution files. - - -The most common scenario is to install from `PyPI`_ using :ref:`Requirement -Specifiers` - - :: - - $ pip install SomePackage # latest version - $ pip install SomePackage==1.0.4 # specific version - $ pip install 'SomePackage>=1.0.4' # minimum version - - -For more information and examples, see the :ref:`pip install` reference. - - -.. _`Requirements Files`: - -Requirements Files -****************** - -"Requirements files" are files containing a list of items to be -installed using :ref:`pip install` like so: - - :: - - pip install -r requirements.txt - - -Details on the format of the files are here: :ref:`Requirements File Format`. - -Logically, a Requirements file is just a list of :ref:`pip install` arguments -placed in a file. - -In practice, there are 4 common uses of Requirements files: - -1. Requirements files are used to hold the result from :ref:`pip freeze` for the - purpose of achieving :ref:`repeatable installations `. In - this case, your requirement file contains a pinned version of everything that - was installed when `pip freeze` was run. - - :: - - pip freeze > requirements.txt - pip install -r requirements.txt - -2. Requirements files are used to force pip to properly resolve dependencies. - As it is now, pip `doesn't have true dependency resolution - `_, but instead simply uses the first - specification it finds for a project. E.g if `pkg1` requires `pkg3>=1.0` and - `pkg2` requires `pkg3>=1.0,<=2.0`, and if `pkg1` is resolved first, pip will - only use `pkg3>=1.0`, and could easily end up installing a version of `pkg3` - that conflicts with the needs of `pkg2`. To solve this problem, you can - place `pkg3>=1.0,<=2.0` (i.e. the correct specification) into your - requirements file directly along with the other top level requirements. Like - so: - - :: - - pkg1 - pkg2 - pkg3>=1.0,<=2.0 - - -3. Requirements files are used to force pip to install an alternate version of a - sub-dependency. For example, suppose `ProjectA` in your requirements file - requires `ProjectB`, but the latest version (v1.3) has a bug, you can force - pip to accept earlier versions like so: - - :: - - ProjectA - ProjectB<1.3 - -4. Requirements files are used to override a dependency with a local patch that - lives in version control. For example, suppose a dependency, - `SomeDependency` from PyPI has a bug, and you can't wait for an upstream fix. - You could clone/copy the src, make the fix, and place it in vcs with the tag - `sometag`. You'd reference it in your requirements file with a line like so: - - :: - - git+https://myvcs.com/some_dependency@sometag#egg=SomeDependency - - If `SomeDependency` was previously a top-level requirement in your - requirements file, then **replace** that line with the new line. If - `SomeDependency` is a sub-dependency, then **add** the new line. - - -It's important to be clear that pip determines package dependencies using -`install_requires metadata -`_, -not by discovering `requirements.txt` files embedded in projects. - -See also: - -* :ref:`Requirements File Format` -* :ref:`pip freeze` -* `"setup.py vs requirements.txt" (an article by Donald Stufft) - `_ - - - -.. _`Installing from Wheels`: - -Installing from Wheels -********************** - -"Wheel" is a built, archive format that can greatly speed installation compared -to building and installing from source archives. For more information, see the -`Wheel docs `_ , -`PEP427 `_, and -`PEP425 `_ - -Pip prefers Wheels where they are available. To disable this, use the -:ref:`--no-use-wheel ` flag for :ref:`pip install`. - -If no satisfactory wheels are found, pip will default to finding source archives. - - -To install directly from a wheel archive: - -:: - - pip install SomePackage-1.0-py2.py3-none-any.whl - - -For the cases where wheels are not available, pip offers :ref:`pip wheel` as a -convenience, to build wheels for all your requirements and dependencies. - -:ref:`pip wheel` requires the `wheel package -`_ to be installed, which provides the -"bdist_wheel" setuptools extension that it uses. - -To build wheels for your requirements and all their dependencies to a local directory: - -:: - - pip install wheel - pip wheel --wheel-dir=/local/wheels -r requirements.txt - - -And *then* to install those requirements just using your local directory of wheels (and not from PyPI): - -:: - - pip install --no-index --find-links=/local/wheels -r requirements.txt - - -Uninstalling Packages -********************* - -pip is able to uninstall most packages like so: - -:: - - $ pip uninstall SomePackage - -pip also performs an automatic uninstall of an old version of a package -before upgrading to a newer version. - -For more information and examples, see the :ref:`pip uninstall` reference. - - -Listing Packages -**************** - -To list installed packages: - -:: - - $ pip list - Pygments (1.5) - docutils (0.9.1) - Sphinx (1.1.2) - Jinja2 (2.6) - -To list outdated packages, and show the latest version available: - -:: - - $ pip list --outdated - docutils (Current: 0.9.1 Latest: 0.10) - Sphinx (Current: 1.1.2 Latest: 1.1.3) - - -To show details about an installed package: - -:: - - $ pip show sphinx - --- - Name: Sphinx - Version: 1.1.3 - Location: /my/env/lib/pythonx.x/site-packages - Requires: Pygments, Jinja2, docutils - - -For more information and examples, see the :ref:`pip list` and :ref:`pip show` -reference pages. - - -Searching for Packages -********************** - -pip can search `PyPI`_ for packages using the ``pip search`` -command:: - - $ pip search "query" - -The query will be used to search the names and summaries of all -packages. - -For more information and examples, see the :ref:`pip search` reference. - -.. _`Configuration`: - -Configuration -************* - -.. _config-file: - -Config file ------------- - -pip allows you to set all command line option defaults in a standard ini -style config file. - -The names and locations of the configuration files vary slightly across -platforms. - -* On Unix and Mac OS X the configuration file is: :file:`$HOME/.pip/pip.conf` -* On Windows, the configuration file is: :file:`%HOME%\\pip\\pip.ini` - -You can set a custom path location for the config file using the environment variable ``PIP_CONFIG_FILE``. - -The names of the settings are derived from the long command line option, e.g. -if you want to use a different package index (``--index-url``) and set the -HTTP timeout (``--default-timeout``) to 60 seconds your config file would -look like this: - -.. code-block:: ini - - [global] - timeout = 60 - index-url = http://download.zope.org/ppix - -Each subcommand can be configured optionally in its own section so that every -global setting with the same name will be overridden; e.g. decreasing the -``timeout`` to ``10`` seconds when running the `freeze` -(`Freezing Requirements <./#freezing-requirements>`_) command and using -``60`` seconds for all other commands is possible with: - -.. code-block:: ini - - [global] - timeout = 60 - - [freeze] - timeout = 10 - - -Boolean options like ``--ignore-installed`` or ``--no-dependencies`` can be -set like this: - -.. code-block:: ini - - [install] - ignore-installed = true - no-dependencies = yes - -Appending options like ``--find-links`` can be written on multiple lines: - -.. code-block:: ini - - [global] - find-links = - http://download.example.com - - [install] - find-links = - http://mirror1.example.com - http://mirror2.example.com - - -Environment Variables ---------------------- - -pip's command line options can be set with environment variables using the -format ``PIP_`` . Dashes (``-``) have to be replaced with -underscores (``_``). - -For example, to set the default timeout:: - - export PIP_DEFAULT_TIMEOUT=60 - -This is the same as passing the option to pip directly:: - - pip --default-timeout=60 [...] - -To set options that can be set multiple times on the command line, just add -spaces in between values. For example:: - - export PIP_FIND_LINKS="http://mirror1.example.com http://mirror2.example.com" - -is the same as calling:: - - pip install --find-links=http://mirror1.example.com --find-links=http://mirror2.example.com - - -Config Precedence ------------------ - -Command line options have precedence over environment variables, which have precedence over the config file. - -Within the config file, command specific sections have precedence over the global section. - -Examples: - -- ``--host=foo`` overrides ``PIP_HOST=foo`` -- ``PIP_HOST=foo`` overrides a config file with ``[global] host = foo`` -- A command specific section in the config file ``[] host = bar`` - overrides the option with same name in the ``[global]`` config file section - - -Command Completion ------------------- - -pip comes with support for command line completion in bash and zsh. - -To setup for bash:: - - $ pip completion --bash >> ~/.profile - -To setup for zsh:: - - $ pip completion --zsh >> ~/.zprofile - -Alternatively, you can use the result of the ``completion`` command -directly with the eval function of you shell, e.g. by adding the following to your startup file:: - - eval "`pip completion --bash`" - - - -.. _`Fast & Local Installs`: - -Fast & Local Installs -********************* - -Often, you will want a fast install from local archives, without probing PyPI. - -First, download the archives that fulfill your requirements:: - -$ pip install --download -r requirements.txt - -Then, install using :ref:`--find-links <--find-links>` and :ref:`--no-index <--no-index>`:: - -$ pip install --no-index --find-links=[file://] -r requirements.txt - - -Non-recursive upgrades -************************ - -``pip install --upgrade`` is currently written to perform a recursive upgrade. - -E.g. supposing: - -* `SomePackage-1.0` requires `AnotherPackage>=1.0` -* `SomePackage-2.0` requires `AnotherPackage>=1.0` and `OneMorePoject==1.0` -* `SomePackage-1.0` and `AnotherPackage-1.0` are currently installed -* `SomePackage-2.0` and `AnotherPackage-2.0` are the latest versions available on PyPI. - -Running ``pip install --upgrade SomePackage`` would upgrade `SomePackage` *and* `AnotherPackage` -despite `AnotherPackage` already being satisifed. - -If you would like to perform a non-recursive upgrade perform these 2 steps:: - - pip install --upgrade --no-deps SomePackage - pip install SomePackage - -The first line will upgrade `SomePackage`, but not dependencies like `AnotherPackage`. The 2nd line will fill in new dependencies like `OneMorePackage`. - - -User Installs -************* - -With Python 2.6 came the `"user scheme" for installation -`_, -which means that all Python distributions support an alternative install -location that is specific to a user. The default location for each OS is -explained in the python documentation for the `site.USER_BASE -`_ variable. This mode -of installation can be turned on by specifying the :ref:`--user -` option to ``pip install``. - -Moreover, the "user scheme" can be customized by setting the -``PYTHONUSERBASE`` environment variable, which updates the value of ``site.USER_BASE``. - -To install "SomePackage" into an environment with site.USER_BASE customized to '/myappenv', do the following:: - - export PYTHONUSERBASE=/myappenv - pip install --user SomePackage - - -``pip install --user`` follows four rules: - -#. When globally installed packages are on the python path, and they *conflict* - with the installation requirements, they are ignored, and *not* - uninstalled. -#. When globally installed packages are on the python path, and they *satisfy* - the installation requirements, pip does nothing, and reports that - requirement is satisfied (similar to how global packages can satisfy - requirements when installing packages in a ``--system-site-packages`` - virtualenv). -#. pip will not perform a ``--user`` install in a ``--no-site-packages`` - virtualenv (i.e. the default kind of virtualenv), due to the user site not - being on the python path. The installation would be pointless. -#. In a ``--system-site-packages`` virtualenv, pip will not install a package - that conflicts with a package in the virtualenv site-packages. The --user - installation would lack sys.path precedence and be pointless. - - -To make the rules clearer, here are some examples: - - -From within a ``--no-site-packages`` virtualenv (i.e. the default kind):: - - $ pip install --user SomePackage - Can not perform a '--user' install. User site-packages are not visible in this virtualenv. - - -From within a ``--system-site-packages`` virtualenv where ``SomePackage==0.3`` is already installed in the virtualenv:: - - $ pip install --user SomePackage==0.4 - Will not install to the user site because it will lack sys.path precedence - - -From within a real python, where ``SomePackage`` is *not* installed globally:: - - $ pip install --user SomePackage - [...] - Successfully installed SomePackage - - -From within a real python, where ``SomePackage`` *is* installed globally, but is *not* the latest version:: - - $ pip install --user SomePackage - [...] - Requirement already satisfied (use --upgrade to upgrade) - - $ pip install --user --upgrade SomePackage - [...] - Successfully installed SomePackage - - -From within a real python, where ``SomePackage`` *is* installed globally, and is the latest version:: - - $ pip install --user SomePackage - [...] - Requirement already satisfied (use --upgrade to upgrade) - - $ pip install --user --upgrade SomePackage - [...] - Requirement already up-to-date: SomePackage - - # force the install - $ pip install --user --ignore-installed SomePackage - [...] - Successfully installed SomePackage - - -.. _`Repeatability`: - -Ensuring Repeatability -********************** - -Three things are required to fully guarantee a repeatable installation using requirements files. - -1. The requirements file was generated by ``pip freeze`` or you're sure it only - contains requirements that specify a specific version. - -2. The installation is performed using :ref:`--no-deps `. - This guarantees that only what is explicitly listed in the requirements file is - installed. - -3. The installation is performed against an index or find-links location that is - guaranteed to *not* allow archives to be changed and updated without a - version increase. Unfortunately, this is *not* true on PyPI. It is possible - for the same pypi distribution to have a different hash over time. Project - authors are allowed to delete a distribution, and then upload a new one with - the same name and version, but a different hash. See `Issue #1175 - `_ for plans to add hash - confirmation to pip, or a new "lock file" notion, but for now, know that the `peep - project `_ offers this feature on top of pip - using requirements file comments. - - -.. _PyPI: http://pypi.python.org/pypi/ diff --git a/vendor/pip-1.5.6/pip/__init__.py b/vendor/pip-1.5.6/pip/__init__.py deleted file mode 100755 index bb4a588..0000000 --- a/vendor/pip-1.5.6/pip/__init__.py +++ /dev/null @@ -1,277 +0,0 @@ -#!/usr/bin/env python -import os -import optparse - -import sys -import re - -from pip.exceptions import InstallationError, CommandError, PipError -from pip.log import logger -from pip.util import get_installed_distributions, get_prog -from pip.vcs import git, mercurial, subversion, bazaar # noqa -from pip.baseparser import ConfigOptionParser, UpdatingDefaultsHelpFormatter -from pip.commands import commands, get_summaries, get_similar_commands - -# This fixes a peculiarity when importing via __import__ - as we are -# initialising the pip module, "from pip import cmdoptions" is recursive -# and appears not to work properly in that situation. -import pip.cmdoptions -cmdoptions = pip.cmdoptions - -# The version as used in the setup.py and the docs conf.py -__version__ = "1.5.6" - - -def autocomplete(): - """Command and option completion for the main option parser (and options) - and its subcommands (and options). - - Enable by sourcing one of the completion shell scripts (bash or zsh). - """ - # Don't complete if user hasn't sourced bash_completion file. - if 'PIP_AUTO_COMPLETE' not in os.environ: - return - cwords = os.environ['COMP_WORDS'].split()[1:] - cword = int(os.environ['COMP_CWORD']) - try: - current = cwords[cword - 1] - 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() - # subcommand options - if subcommand_name: - # special case: 'help' subcommand has no options - if subcommand_name == 'help': - sys.exit(1) - # special case: list locally installed dists for uninstall command - if subcommand_name == 'uninstall' and not current.startswith('-'): - installed = [] - lc = current.lower() - for dist in get_installed_distributions(local_only=True): - if dist.key.startswith(lc) and dist.key not in cwords[1:]: - installed.append(dist.key) - # if there are no dists installed, fall back to option completion - if installed: - for dist in installed: - print(dist) - sys.exit(1) - - subcommand = commands[subcommand_name]() - options += [(opt.get_opt_string(), opt.nargs) - for opt in subcommand.parser.option_list_all - if opt.help != optparse.SUPPRESS_HELP] - - # filter out previously specified options from available options - prev_opts = [x.split('=')[0] for x in cwords[1:cword - 1]] - options = [(x, v) for (x, v) in options if x not in prev_opts] - # filter options by current input - options = [(k, v) for k, v in options if k.startswith(current)] - for option in options: - opt_label = option[0] - # append '=' to options which require args - if option[1]: - opt_label += '=' - print(opt_label) - else: - # show main parser options only when necessary - if current.startswith('-') or current.startswith('--'): - 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) - - subcommands += [i.get_opt_string() for i in opts - if i.help != optparse.SUPPRESS_HELP] - - print(' '.join([x for x in subcommands if x.startswith(current)])) - sys.exit(1) - - -def create_main_parser(): - parser_kw = { - 'usage': '\n%prog [options]', - 'add_help_option': False, - 'formatter': UpdatingDefaultsHelpFormatter(), - 'name': 'global', - 'prog': get_prog(), - } - - parser = ConfigOptionParser(**parser_kw) - parser.disable_interspersed_args() - - pip_pkg_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) - parser.version = 'pip %s from %s (python %s)' % ( - __version__, pip_pkg_dir, sys.version[:3]) - - # add the general options - gen_opts = cmdoptions.make_option_group(cmdoptions.general_group, parser) - parser.add_option_group(gen_opts) - - parser.main = True # so the help formatter knows - - # create command listing for description - command_summaries = get_summaries() - description = [''] + ['%-27s %s' % (i, j) for i, j in command_summaries] - parser.description = '\n'.join(description) - - return parser - - -def parseopts(args): - parser = create_main_parser() - - # Note: parser calls disable_interspersed_args(), so the result of this call - # is to split the initial args into the general options before the - # subcommand and everything else. - # For example: - # args: ['--timeout=5', 'install', '--user', 'INITools'] - # general_options: ['--timeout==5'] - # args_else: ['install', '--user', 'INITools'] - general_options, args_else = parser.parse_args(args) - - # --version - if general_options.version: - sys.stdout.write(parser.version) - sys.stdout.write(os.linesep) - sys.exit() - - # pip || pip help -> print_help() - if not args_else or (args_else[0] == 'help' and len(args_else) == 1): - parser.print_help() - sys.exit() - - # the subcommand name - cmd_name = args_else[0].lower() - - #all the args without the subcommand - cmd_args = args[:] - cmd_args.remove(args_else[0].lower()) - - if cmd_name not in commands: - guess = get_similar_commands(cmd_name) - - msg = ['unknown command "%s"' % cmd_name] - if guess: - msg.append('maybe you meant "%s"' % guess) - - raise CommandError(' - '.join(msg)) - - return cmd_name, cmd_args - - -def main(initial_args=None): - if initial_args is None: - initial_args = sys.argv[1:] - - autocomplete() - - try: - cmd_name, cmd_args = parseopts(initial_args) - except PipError: - e = sys.exc_info()[1] - sys.stderr.write("ERROR: %s" % e) - sys.stderr.write(os.linesep) - sys.exit(1) - - command = commands[cmd_name]() - return command.main(cmd_args) - - -def bootstrap(): - """ - Bootstrapping function to be called from install-pip.py script. - """ - pkgs = ['pip'] - try: - import setuptools - except ImportError: - pkgs.append('setuptools') - return main(['install', '--upgrade'] + pkgs + sys.argv[1:]) - -############################################################ -## Writing freeze files - - -class FrozenRequirement(object): - - def __init__(self, name, req, editable, comments=()): - self.name = name - self.req = req - self.editable = editable - self.comments = comments - - _rev_re = re.compile(r'-r(\d+)$') - _date_re = re.compile(r'-(20\d\d\d\d\d\d)$') - - @classmethod - def from_dist(cls, dist, dependency_links, find_tags=False): - location = os.path.normcase(os.path.abspath(dist.location)) - comments = [] - from pip.vcs import vcs, get_src_requirement - if vcs.get_backend_name(location): - editable = True - try: - req = get_src_requirement(dist, location, find_tags) - except InstallationError: - ex = sys.exc_info()[1] - logger.warn("Error when trying to get requirement for VCS system %s, falling back to uneditable format" % ex) - req = None - if req is None: - logger.warn('Could not determine repository location of %s' % location) - comments.append('## !! Could not determine repository location') - req = dist.as_requirement() - editable = False - else: - editable = False - req = dist.as_requirement() - specs = req.specs - assert len(specs) == 1 and specs[0][0] == '==' - version = specs[0][1] - ver_match = cls._rev_re.search(version) - date_match = cls._date_re.search(version) - if ver_match or date_match: - svn_backend = vcs.get_backend('svn') - if svn_backend: - svn_location = svn_backend( - ).get_location(dist, dependency_links) - if not svn_location: - logger.warn( - 'Warning: cannot find svn location for %s' % req) - comments.append('## FIXME: could not find svn URL in dependency_links for this package:') - else: - comments.append('# Installing as editable to satisfy requirement %s:' % req) - if ver_match: - rev = ver_match.group(1) - else: - rev = '{%s}' % date_match.group(1) - editable = True - req = '%s@%s#egg=%s' % (svn_location, rev, cls.egg_name(dist)) - return cls(dist.project_name, req, editable, comments) - - @staticmethod - def egg_name(dist): - name = dist.egg_name() - match = re.search(r'-py\d\.\d$', name) - if match: - name = name[:match.start()] - return name - - def __str__(self): - req = self.req - if self.editable: - req = '-e %s' % req - return '\n'.join(list(self.comments) + [str(req)]) + '\n' - - -if __name__ == '__main__': - exit = main() - if exit: - sys.exit(exit) diff --git a/vendor/pip-1.5.6/pip/__main__.py b/vendor/pip-1.5.6/pip/__main__.py deleted file mode 100644 index 5ca3746..0000000 --- a/vendor/pip-1.5.6/pip/__main__.py +++ /dev/null @@ -1,7 +0,0 @@ -import sys -from .runner import run - -if __name__ == '__main__': - exit = run() - if exit: - sys.exit(exit) diff --git a/vendor/pip-1.5.6/pip/_vendor/__init__.py b/vendor/pip-1.5.6/pip/_vendor/__init__.py deleted file mode 100644 index f233ca0..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/__init__.py +++ /dev/null @@ -1,8 +0,0 @@ -""" -pip._vendor is for vendoring dependencies of pip to prevent needing pip to -depend on something external. - -Files inside of pip._vendor should be considered immutable and should only be -updated to versions from upstream. -""" -from __future__ import absolute_import diff --git a/vendor/pip-1.5.6/pip/_vendor/_markerlib/__init__.py b/vendor/pip-1.5.6/pip/_vendor/_markerlib/__init__.py deleted file mode 100644 index 197781a..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/_markerlib/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -try: - import ast - from pip._vendor._markerlib.markers import default_environment, compile, interpret -except ImportError: - if 'ast' in globals(): - raise - def default_environment(): - return {} - def compile(marker): - def marker_fn(environment=None, override=None): - # 'empty markers are True' heuristic won't install extra deps. - return not marker.strip() - marker_fn.__doc__ = marker - return marker_fn - def interpret(marker, environment=None, override=None): - return compile(marker)() diff --git a/vendor/pip-1.5.6/pip/_vendor/_markerlib/markers.py b/vendor/pip-1.5.6/pip/_vendor/_markerlib/markers.py deleted file mode 100644 index fa83706..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/_markerlib/markers.py +++ /dev/null @@ -1,119 +0,0 @@ -# -*- coding: utf-8 -*- -"""Interpret PEP 345 environment markers. - -EXPR [in|==|!=|not in] EXPR [or|and] ... - -where EXPR belongs to any of those: - - python_version = '%s.%s' % (sys.version_info[0], sys.version_info[1]) - python_full_version = sys.version.split()[0] - os.name = os.name - sys.platform = sys.platform - platform.version = platform.version() - platform.machine = platform.machine() - platform.python_implementation = platform.python_implementation() - a free string, like '2.6', or 'win32' -""" - -__all__ = ['default_environment', 'compile', 'interpret'] - -import ast -import os -import platform -import sys -import weakref - -_builtin_compile = compile - -try: - from platform import python_implementation -except ImportError: - if os.name == "java": - # Jython 2.5 has ast module, but not platform.python_implementation() function. - def python_implementation(): - return "Jython" - else: - raise - - -# restricted set of variables -_VARS = {'sys.platform': sys.platform, - 'python_version': '%s.%s' % sys.version_info[:2], - # FIXME parsing sys.platform is not reliable, but there is no other - # way to get e.g. 2.7.2+, and the PEP is defined with sys.version - 'python_full_version': sys.version.split(' ', 1)[0], - 'os.name': os.name, - 'platform.version': platform.version(), - 'platform.machine': platform.machine(), - 'platform.python_implementation': python_implementation(), - 'extra': None # wheel extension - } - -for var in list(_VARS.keys()): - if '.' in var: - _VARS[var.replace('.', '_')] = _VARS[var] - -def default_environment(): - """Return copy of default PEP 385 globals dictionary.""" - return dict(_VARS) - -class ASTWhitelist(ast.NodeTransformer): - def __init__(self, statement): - self.statement = statement # for error messages - - ALLOWED = (ast.Compare, ast.BoolOp, ast.Attribute, ast.Name, ast.Load, ast.Str) - # Bool operations - ALLOWED += (ast.And, ast.Or) - # Comparison operations - ALLOWED += (ast.Eq, ast.Gt, ast.GtE, ast.In, ast.Is, ast.IsNot, ast.Lt, ast.LtE, ast.NotEq, ast.NotIn) - - def visit(self, node): - """Ensure statement only contains allowed nodes.""" - if not isinstance(node, self.ALLOWED): - raise SyntaxError('Not allowed in environment markers.\n%s\n%s' % - (self.statement, - (' ' * node.col_offset) + '^')) - return ast.NodeTransformer.visit(self, node) - - def visit_Attribute(self, node): - """Flatten one level of attribute access.""" - new_node = ast.Name("%s.%s" % (node.value.id, node.attr), node.ctx) - return ast.copy_location(new_node, node) - -def parse_marker(marker): - tree = ast.parse(marker, mode='eval') - new_tree = ASTWhitelist(marker).generic_visit(tree) - return new_tree - -def compile_marker(parsed_marker): - return _builtin_compile(parsed_marker, '', 'eval', - dont_inherit=True) - -_cache = weakref.WeakValueDictionary() - -def compile(marker): - """Return compiled marker as a function accepting an environment dict.""" - try: - return _cache[marker] - except KeyError: - pass - if not marker.strip(): - def marker_fn(environment=None, override=None): - """""" - return True - else: - compiled_marker = compile_marker(parse_marker(marker)) - def marker_fn(environment=None, override=None): - """override updates environment""" - if override is None: - override = {} - if environment is None: - environment = default_environment() - environment.update(override) - return eval(compiled_marker, environment) - marker_fn.__doc__ = marker - _cache[marker] = marker_fn - return _cache[marker] - -def interpret(marker, environment=None): - return compile(marker)(environment) diff --git a/vendor/pip-1.5.6/pip/_vendor/colorama/__init__.py b/vendor/pip-1.5.6/pip/_vendor/colorama/__init__.py deleted file mode 100644 index 0856986..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/colorama/__init__.py +++ /dev/null @@ -1,7 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. -from .initialise import init, deinit, reinit -from .ansi import Fore, Back, Style -from .ansitowin32 import AnsiToWin32 - -__version__ = '0.3.1' - diff --git a/vendor/pip-1.5.6/pip/_vendor/colorama/ansi.py b/vendor/pip-1.5.6/pip/_vendor/colorama/ansi.py deleted file mode 100644 index 5dfe374..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/colorama/ansi.py +++ /dev/null @@ -1,50 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. -''' -This module generates ANSI character codes to printing colors to terminals. -See: http://en.wikipedia.org/wiki/ANSI_escape_code -''' - -CSI = '\033[' - -def code_to_chars(code): - return CSI + str(code) + 'm' - -class AnsiCodes(object): - def __init__(self, codes): - for name in dir(codes): - if not name.startswith('_'): - value = getattr(codes, name) - setattr(self, name, code_to_chars(value)) - -class AnsiFore: - BLACK = 30 - RED = 31 - GREEN = 32 - YELLOW = 33 - BLUE = 34 - MAGENTA = 35 - CYAN = 36 - WHITE = 37 - RESET = 39 - -class AnsiBack: - BLACK = 40 - RED = 41 - GREEN = 42 - YELLOW = 43 - BLUE = 44 - MAGENTA = 45 - CYAN = 46 - WHITE = 47 - RESET = 49 - -class AnsiStyle: - BRIGHT = 1 - DIM = 2 - NORMAL = 22 - RESET_ALL = 0 - -Fore = AnsiCodes( AnsiFore ) -Back = AnsiCodes( AnsiBack ) -Style = AnsiCodes( AnsiStyle ) - diff --git a/vendor/pip-1.5.6/pip/_vendor/colorama/ansitowin32.py b/vendor/pip-1.5.6/pip/_vendor/colorama/ansitowin32.py deleted file mode 100644 index 0053a77..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/colorama/ansitowin32.py +++ /dev/null @@ -1,190 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. -import re -import sys - -from .ansi import AnsiFore, AnsiBack, AnsiStyle, Style -from .winterm import WinTerm, WinColor, WinStyle -from .win32 import windll - - -winterm = None -if windll is not None: - winterm = WinTerm() - - -def is_a_tty(stream): - return hasattr(stream, 'isatty') and stream.isatty() - - -class StreamWrapper(object): - ''' - Wraps a stream (such as stdout), acting as a transparent proxy for all - attribute access apart from method 'write()', which is delegated to our - Converter instance. - ''' - def __init__(self, wrapped, converter): - # double-underscore everything to prevent clashes with names of - # attributes on the wrapped stream object. - self.__wrapped = wrapped - self.__convertor = converter - - def __getattr__(self, name): - return getattr(self.__wrapped, name) - - def write(self, text): - self.__convertor.write(text) - - -class AnsiToWin32(object): - ''' - Implements a 'write()' method which, on Windows, will strip ANSI character - sequences from the text, and if outputting to a tty, will convert them into - win32 function calls. - ''' - ANSI_RE = re.compile('\033\[((?:\d|;)*)([a-zA-Z])') - - def __init__(self, wrapped, convert=None, strip=None, autoreset=False): - # The wrapped stream (normally sys.stdout or sys.stderr) - self.wrapped = wrapped - - # should we reset colors to defaults after every .write() - self.autoreset = autoreset - - # create the proxy wrapping our output stream - self.stream = StreamWrapper(wrapped, self) - - on_windows = sys.platform.startswith('win') - - # should we strip ANSI sequences from our output? - if strip is None: - strip = on_windows - self.strip = strip - - # should we should convert ANSI sequences into win32 calls? - if convert is None: - convert = on_windows and is_a_tty(wrapped) - self.convert = convert - - # dict of ansi codes to win32 functions and parameters - self.win32_calls = self.get_win32_calls() - - # are we wrapping stderr? - self.on_stderr = self.wrapped is sys.stderr - - - def should_wrap(self): - ''' - True if this class is actually needed. If false, then the output - stream will not be affected, nor will win32 calls be issued, so - wrapping stdout is not actually required. This will generally be - False on non-Windows platforms, unless optional functionality like - autoreset has been requested using kwargs to init() - ''' - return self.convert or self.strip or self.autoreset - - - def get_win32_calls(self): - if self.convert and winterm: - return { - AnsiStyle.RESET_ALL: (winterm.reset_all, ), - AnsiStyle.BRIGHT: (winterm.style, WinStyle.BRIGHT), - AnsiStyle.DIM: (winterm.style, WinStyle.NORMAL), - AnsiStyle.NORMAL: (winterm.style, WinStyle.NORMAL), - AnsiFore.BLACK: (winterm.fore, WinColor.BLACK), - AnsiFore.RED: (winterm.fore, WinColor.RED), - AnsiFore.GREEN: (winterm.fore, WinColor.GREEN), - AnsiFore.YELLOW: (winterm.fore, WinColor.YELLOW), - AnsiFore.BLUE: (winterm.fore, WinColor.BLUE), - AnsiFore.MAGENTA: (winterm.fore, WinColor.MAGENTA), - AnsiFore.CYAN: (winterm.fore, WinColor.CYAN), - AnsiFore.WHITE: (winterm.fore, WinColor.GREY), - AnsiFore.RESET: (winterm.fore, ), - AnsiBack.BLACK: (winterm.back, WinColor.BLACK), - AnsiBack.RED: (winterm.back, WinColor.RED), - AnsiBack.GREEN: (winterm.back, WinColor.GREEN), - AnsiBack.YELLOW: (winterm.back, WinColor.YELLOW), - AnsiBack.BLUE: (winterm.back, WinColor.BLUE), - AnsiBack.MAGENTA: (winterm.back, WinColor.MAGENTA), - AnsiBack.CYAN: (winterm.back, WinColor.CYAN), - AnsiBack.WHITE: (winterm.back, WinColor.GREY), - AnsiBack.RESET: (winterm.back, ), - } - - - def write(self, text): - if self.strip or self.convert: - self.write_and_convert(text) - else: - self.wrapped.write(text) - self.wrapped.flush() - if self.autoreset: - self.reset_all() - - - def reset_all(self): - if self.convert: - self.call_win32('m', (0,)) - elif not self.wrapped.closed and is_a_tty(self.wrapped): - self.wrapped.write(Style.RESET_ALL) - - - def write_and_convert(self, text): - ''' - Write the given text to our wrapped stream, stripping any ANSI - sequences from the text, and optionally converting them into win32 - calls. - ''' - cursor = 0 - for match in self.ANSI_RE.finditer(text): - start, end = match.span() - self.write_plain_text(text, cursor, start) - self.convert_ansi(*match.groups()) - cursor = end - self.write_plain_text(text, cursor, len(text)) - - - def write_plain_text(self, text, start, end): - if start < end: - self.wrapped.write(text[start:end]) - self.wrapped.flush() - - - def convert_ansi(self, paramstring, command): - if self.convert: - params = self.extract_params(paramstring) - self.call_win32(command, params) - - - def extract_params(self, paramstring): - def split(paramstring): - for p in paramstring.split(';'): - if p != '': - yield int(p) - return tuple(split(paramstring)) - - - def call_win32(self, command, params): - if params == []: - params = [0] - if command == 'm': - for param in params: - if param in self.win32_calls: - func_args = self.win32_calls[param] - func = func_args[0] - args = func_args[1:] - kwargs = dict(on_stderr=self.on_stderr) - func(*args, **kwargs) - elif command in ('H', 'f'): # set cursor position - func = winterm.set_cursor_position - func(params, on_stderr=self.on_stderr) - elif command in ('J'): - func = winterm.erase_data - func(params, on_stderr=self.on_stderr) - elif command == 'A': - if params == () or params == None: - num_rows = 1 - else: - num_rows = params[0] - func = winterm.cursor_up - func(num_rows, on_stderr=self.on_stderr) - diff --git a/vendor/pip-1.5.6/pip/_vendor/colorama/initialise.py b/vendor/pip-1.5.6/pip/_vendor/colorama/initialise.py deleted file mode 100644 index cba3676..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/colorama/initialise.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. -import atexit -import sys - -from .ansitowin32 import AnsiToWin32 - - -orig_stdout = sys.stdout -orig_stderr = sys.stderr - -wrapped_stdout = sys.stdout -wrapped_stderr = sys.stderr - -atexit_done = False - - -def reset_all(): - AnsiToWin32(orig_stdout).reset_all() - - -def init(autoreset=False, convert=None, strip=None, wrap=True): - - if not wrap and any([autoreset, convert, strip]): - raise ValueError('wrap=False conflicts with any other arg=True') - - global wrapped_stdout, wrapped_stderr - sys.stdout = wrapped_stdout = \ - wrap_stream(orig_stdout, convert, strip, autoreset, wrap) - sys.stderr = wrapped_stderr = \ - wrap_stream(orig_stderr, convert, strip, autoreset, wrap) - - global atexit_done - if not atexit_done: - atexit.register(reset_all) - atexit_done = True - - -def deinit(): - sys.stdout = orig_stdout - sys.stderr = orig_stderr - - -def reinit(): - sys.stdout = wrapped_stdout - sys.stderr = wrapped_stdout - - -def wrap_stream(stream, convert, strip, autoreset, wrap): - if wrap: - wrapper = AnsiToWin32(stream, - convert=convert, strip=strip, autoreset=autoreset) - if wrapper.should_wrap(): - stream = wrapper.stream - return stream - - diff --git a/vendor/pip-1.5.6/pip/_vendor/colorama/win32.py b/vendor/pip-1.5.6/pip/_vendor/colorama/win32.py deleted file mode 100644 index 5203e79..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/colorama/win32.py +++ /dev/null @@ -1,137 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. - -# from winbase.h -STDOUT = -11 -STDERR = -12 - -import ctypes -from ctypes import LibraryLoader - -try: - windll = LibraryLoader(ctypes.WinDLL) - from ctypes import wintypes -except (AttributeError, ImportError): - windll = None - SetConsoleTextAttribute = lambda *_: None -else: - from ctypes import ( - byref, Structure, c_char, c_short, c_uint32, c_ushort, POINTER - ) - - class CONSOLE_SCREEN_BUFFER_INFO(Structure): - """struct in wincon.h.""" - _fields_ = [ - ("dwSize", wintypes._COORD), - ("dwCursorPosition", wintypes._COORD), - ("wAttributes", wintypes.WORD), - ("srWindow", wintypes.SMALL_RECT), - ("dwMaximumWindowSize", wintypes._COORD), - ] - def __str__(self): - return '(%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d)' % ( - self.dwSize.Y, self.dwSize.X - , self.dwCursorPosition.Y, self.dwCursorPosition.X - , self.wAttributes - , self.srWindow.Top, self.srWindow.Left, self.srWindow.Bottom, self.srWindow.Right - , self.dwMaximumWindowSize.Y, self.dwMaximumWindowSize.X - ) - - _GetStdHandle = windll.kernel32.GetStdHandle - _GetStdHandle.argtypes = [ - wintypes.DWORD, - ] - _GetStdHandle.restype = wintypes.HANDLE - - _GetConsoleScreenBufferInfo = windll.kernel32.GetConsoleScreenBufferInfo - _GetConsoleScreenBufferInfo.argtypes = [ - wintypes.HANDLE, - POINTER(CONSOLE_SCREEN_BUFFER_INFO), - ] - _GetConsoleScreenBufferInfo.restype = wintypes.BOOL - - _SetConsoleTextAttribute = windll.kernel32.SetConsoleTextAttribute - _SetConsoleTextAttribute.argtypes = [ - wintypes.HANDLE, - wintypes.WORD, - ] - _SetConsoleTextAttribute.restype = wintypes.BOOL - - _SetConsoleCursorPosition = windll.kernel32.SetConsoleCursorPosition - _SetConsoleCursorPosition.argtypes = [ - wintypes.HANDLE, - wintypes._COORD, - ] - _SetConsoleCursorPosition.restype = wintypes.BOOL - - _FillConsoleOutputCharacterA = windll.kernel32.FillConsoleOutputCharacterA - _FillConsoleOutputCharacterA.argtypes = [ - wintypes.HANDLE, - c_char, - wintypes.DWORD, - wintypes._COORD, - POINTER(wintypes.DWORD), - ] - _FillConsoleOutputCharacterA.restype = wintypes.BOOL - - _FillConsoleOutputAttribute = windll.kernel32.FillConsoleOutputAttribute - _FillConsoleOutputAttribute.argtypes = [ - wintypes.HANDLE, - wintypes.WORD, - wintypes.DWORD, - wintypes._COORD, - POINTER(wintypes.DWORD), - ] - _FillConsoleOutputAttribute.restype = wintypes.BOOL - - handles = { - STDOUT: _GetStdHandle(STDOUT), - STDERR: _GetStdHandle(STDERR), - } - - def GetConsoleScreenBufferInfo(stream_id=STDOUT): - handle = handles[stream_id] - csbi = CONSOLE_SCREEN_BUFFER_INFO() - success = _GetConsoleScreenBufferInfo( - handle, byref(csbi)) - return csbi - - def SetConsoleTextAttribute(stream_id, attrs): - handle = handles[stream_id] - return _SetConsoleTextAttribute(handle, attrs) - - def SetConsoleCursorPosition(stream_id, position): - position = wintypes._COORD(*position) - # If the position is out of range, do nothing. - if position.Y <= 0 or position.X <= 0: - return - # Adjust for Windows' SetConsoleCursorPosition: - # 1. being 0-based, while ANSI is 1-based. - # 2. expecting (x,y), while ANSI uses (y,x). - adjusted_position = wintypes._COORD(position.Y - 1, position.X - 1) - # Adjust for viewport's scroll position - sr = GetConsoleScreenBufferInfo(STDOUT).srWindow - adjusted_position.Y += sr.Top - adjusted_position.X += sr.Left - # Resume normal processing - handle = handles[stream_id] - return _SetConsoleCursorPosition(handle, adjusted_position) - - def FillConsoleOutputCharacter(stream_id, char, length, start): - handle = handles[stream_id] - char = c_char(char) - length = wintypes.DWORD(length) - num_written = wintypes.DWORD(0) - # Note that this is hard-coded for ANSI (vs wide) bytes. - success = _FillConsoleOutputCharacterA( - handle, char, length, start, byref(num_written)) - return num_written.value - - def FillConsoleOutputAttribute(stream_id, attr, length, start): - ''' FillConsoleOutputAttribute( hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten )''' - handle = handles[stream_id] - attribute = wintypes.WORD(attr) - length = wintypes.DWORD(length) - num_written = wintypes.DWORD(0) - # Note that this is hard-coded for ANSI (vs wide) bytes. - return _FillConsoleOutputAttribute( - handle, attribute, length, start, byref(num_written)) diff --git a/vendor/pip-1.5.6/pip/_vendor/colorama/winterm.py b/vendor/pip-1.5.6/pip/_vendor/colorama/winterm.py deleted file mode 100644 index 2708811..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/colorama/winterm.py +++ /dev/null @@ -1,120 +0,0 @@ -# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. -from . import win32 - - -# from wincon.h -class WinColor(object): - BLACK = 0 - BLUE = 1 - GREEN = 2 - CYAN = 3 - RED = 4 - MAGENTA = 5 - YELLOW = 6 - GREY = 7 - -# from wincon.h -class WinStyle(object): - NORMAL = 0x00 # dim text, dim background - BRIGHT = 0x08 # bright text, dim background - - -class WinTerm(object): - - def __init__(self): - self._default = win32.GetConsoleScreenBufferInfo(win32.STDOUT).wAttributes - self.set_attrs(self._default) - self._default_fore = self._fore - self._default_back = self._back - self._default_style = self._style - - def get_attrs(self): - return self._fore + self._back * 16 + self._style - - def set_attrs(self, value): - self._fore = value & 7 - self._back = (value >> 4) & 7 - self._style = value & WinStyle.BRIGHT - - def reset_all(self, on_stderr=None): - self.set_attrs(self._default) - self.set_console(attrs=self._default) - - def fore(self, fore=None, on_stderr=False): - if fore is None: - fore = self._default_fore - self._fore = fore - self.set_console(on_stderr=on_stderr) - - def back(self, back=None, on_stderr=False): - if back is None: - back = self._default_back - self._back = back - self.set_console(on_stderr=on_stderr) - - def style(self, style=None, on_stderr=False): - if style is None: - style = self._default_style - self._style = style - self.set_console(on_stderr=on_stderr) - - def set_console(self, attrs=None, on_stderr=False): - if attrs is None: - attrs = self.get_attrs() - handle = win32.STDOUT - if on_stderr: - handle = win32.STDERR - win32.SetConsoleTextAttribute(handle, attrs) - - def get_position(self, handle): - position = win32.GetConsoleScreenBufferInfo(handle).dwCursorPosition - # Because Windows coordinates are 0-based, - # and win32.SetConsoleCursorPosition expects 1-based. - position.X += 1 - position.Y += 1 - return position - - def set_cursor_position(self, position=None, on_stderr=False): - if position is None: - #I'm not currently tracking the position, so there is no default. - #position = self.get_position() - return - handle = win32.STDOUT - if on_stderr: - handle = win32.STDERR - win32.SetConsoleCursorPosition(handle, position) - - def cursor_up(self, num_rows=0, on_stderr=False): - if num_rows == 0: - return - handle = win32.STDOUT - if on_stderr: - handle = win32.STDERR - position = self.get_position(handle) - adjusted_position = (position.Y - num_rows, position.X) - self.set_cursor_position(adjusted_position, on_stderr) - - def erase_data(self, mode=0, on_stderr=False): - # 0 (or None) should clear from the cursor to the end of the screen. - # 1 should clear from the cursor to the beginning of the screen. - # 2 should clear the entire screen. (And maybe move cursor to (1,1)?) - # - # At the moment, I only support mode 2. From looking at the API, it - # should be possible to calculate a different number of bytes to clear, - # and to do so relative to the cursor position. - if mode[0] not in (2,): - return - handle = win32.STDOUT - if on_stderr: - handle = win32.STDERR - # here's where we'll home the cursor - coord_screen = win32.COORD(0,0) - csbi = win32.GetConsoleScreenBufferInfo(handle) - # get the number of character cells in the current buffer - dw_con_size = csbi.dwSize.X * csbi.dwSize.Y - # fill the entire screen with blanks - win32.FillConsoleOutputCharacter(handle, ' ', dw_con_size, coord_screen) - # now set the buffer's attributes accordingly - win32.FillConsoleOutputAttribute(handle, self.get_attrs(), dw_con_size, coord_screen ); - # put the cursor at (0, 0) - win32.SetConsoleCursorPosition(handle, (coord_screen.X, coord_screen.Y)) diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/__init__.py b/vendor/pip-1.5.6/pip/_vendor/distlib/__init__.py deleted file mode 100644 index f9081bb..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/distlib/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012-2014 Vinay Sajip. -# Licensed to the Python Software Foundation under a contributor agreement. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -import logging - -__version__ = '0.1.8' - -class DistlibException(Exception): - pass - -try: - from logging import NullHandler -except ImportError: # pragma: no cover - class NullHandler(logging.Handler): - def handle(self, record): pass - def emit(self, record): pass - def createLock(self): self.lock = None - -logger = logging.getLogger(__name__) -logger.addHandler(NullHandler()) diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/_backport/__init__.py b/vendor/pip-1.5.6/pip/_vendor/distlib/_backport/__init__.py deleted file mode 100644 index f7dbf4c..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/distlib/_backport/__init__.py +++ /dev/null @@ -1,6 +0,0 @@ -"""Modules copied from Python 3 standard libraries, for internal use only. - -Individual classes and functions are found in d2._backport.misc. Intended -usage is to always import things missing from 3.1 from that module: the -built-in/stdlib objects will be used if found. -""" diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/_backport/misc.py b/vendor/pip-1.5.6/pip/_vendor/distlib/_backport/misc.py deleted file mode 100644 index cfb318d..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/distlib/_backport/misc.py +++ /dev/null @@ -1,41 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012 The Python Software Foundation. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -"""Backports for individual classes and functions.""" - -import os -import sys - -__all__ = ['cache_from_source', 'callable', 'fsencode'] - - -try: - from imp import cache_from_source -except ImportError: - def cache_from_source(py_file, debug=__debug__): - ext = debug and 'c' or 'o' - return py_file + ext - - -try: - callable = callable -except NameError: - from collections import Callable - - def callable(obj): - return isinstance(obj, Callable) - - -try: - fsencode = os.fsencode -except AttributeError: - def fsencode(filename): - if isinstance(filename, bytes): - return filename - elif isinstance(filename, str): - return filename.encode(sys.getfilesystemencoding()) - else: - raise TypeError("expect bytes or str, not %s" % - type(filename).__name__) diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/_backport/shutil.py b/vendor/pip-1.5.6/pip/_vendor/distlib/_backport/shutil.py deleted file mode 100644 index 9e2e234..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/distlib/_backport/shutil.py +++ /dev/null @@ -1,761 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012 The Python Software Foundation. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -"""Utility functions for copying and archiving files and directory trees. - -XXX The functions here don't copy the resource fork or other metadata on Mac. - -""" - -import os -import sys -import stat -from os.path import abspath -import fnmatch -import collections -import errno -from . import tarfile - -try: - import bz2 - _BZ2_SUPPORTED = True -except ImportError: - _BZ2_SUPPORTED = False - -try: - from pwd import getpwnam -except ImportError: - getpwnam = None - -try: - from grp import getgrnam -except ImportError: - getgrnam = None - -__all__ = ["copyfileobj", "copyfile", "copymode", "copystat", "copy", "copy2", - "copytree", "move", "rmtree", "Error", "SpecialFileError", - "ExecError", "make_archive", "get_archive_formats", - "register_archive_format", "unregister_archive_format", - "get_unpack_formats", "register_unpack_format", - "unregister_unpack_format", "unpack_archive", "ignore_patterns"] - -class Error(EnvironmentError): - pass - -class SpecialFileError(EnvironmentError): - """Raised when trying to do a kind of operation (e.g. copying) which is - not supported on a special file (e.g. a named pipe)""" - -class ExecError(EnvironmentError): - """Raised when a command could not be executed""" - -class ReadError(EnvironmentError): - """Raised when an archive cannot be read""" - -class RegistryError(Exception): - """Raised when a registery operation with the archiving - and unpacking registeries fails""" - - -try: - WindowsError -except NameError: - WindowsError = None - -def copyfileobj(fsrc, fdst, length=16*1024): - """copy data from file-like object fsrc to file-like object fdst""" - while 1: - buf = fsrc.read(length) - if not buf: - break - fdst.write(buf) - -def _samefile(src, dst): - # Macintosh, Unix. - if hasattr(os.path, 'samefile'): - try: - return os.path.samefile(src, dst) - except OSError: - return False - - # All other platforms: check for same pathname. - return (os.path.normcase(os.path.abspath(src)) == - os.path.normcase(os.path.abspath(dst))) - -def copyfile(src, dst): - """Copy data from src to dst""" - if _samefile(src, dst): - raise Error("`%s` and `%s` are the same file" % (src, dst)) - - for fn in [src, dst]: - try: - st = os.stat(fn) - except OSError: - # File most likely does not exist - pass - else: - # XXX What about other special files? (sockets, devices...) - if stat.S_ISFIFO(st.st_mode): - raise SpecialFileError("`%s` is a named pipe" % fn) - - with open(src, 'rb') as fsrc: - with open(dst, 'wb') as fdst: - copyfileobj(fsrc, fdst) - -def copymode(src, dst): - """Copy mode bits from src to dst""" - if hasattr(os, 'chmod'): - st = os.stat(src) - mode = stat.S_IMODE(st.st_mode) - os.chmod(dst, mode) - -def copystat(src, dst): - """Copy all stat info (mode bits, atime, mtime, flags) from src to dst""" - st = os.stat(src) - mode = stat.S_IMODE(st.st_mode) - if hasattr(os, 'utime'): - os.utime(dst, (st.st_atime, st.st_mtime)) - if hasattr(os, 'chmod'): - os.chmod(dst, mode) - if hasattr(os, 'chflags') and hasattr(st, 'st_flags'): - try: - os.chflags(dst, st.st_flags) - except OSError as why: - if (not hasattr(errno, 'EOPNOTSUPP') or - why.errno != errno.EOPNOTSUPP): - raise - -def copy(src, dst): - """Copy data and mode bits ("cp src dst"). - - The destination may be a directory. - - """ - if os.path.isdir(dst): - dst = os.path.join(dst, os.path.basename(src)) - copyfile(src, dst) - copymode(src, dst) - -def copy2(src, dst): - """Copy data and all stat info ("cp -p src dst"). - - The destination may be a directory. - - """ - if os.path.isdir(dst): - dst = os.path.join(dst, os.path.basename(src)) - copyfile(src, dst) - copystat(src, dst) - -def ignore_patterns(*patterns): - """Function that can be used as copytree() ignore parameter. - - Patterns is a sequence of glob-style patterns - that are used to exclude files""" - def _ignore_patterns(path, names): - ignored_names = [] - for pattern in patterns: - ignored_names.extend(fnmatch.filter(names, pattern)) - return set(ignored_names) - return _ignore_patterns - -def copytree(src, dst, symlinks=False, ignore=None, copy_function=copy2, - ignore_dangling_symlinks=False): - """Recursively copy a directory tree. - - The destination directory must not already exist. - If exception(s) occur, an Error is raised with a list of reasons. - - If the optional symlinks flag is true, symbolic links in the - source tree result in symbolic links in the destination tree; if - it is false, the contents of the files pointed to by symbolic - links are copied. If the file pointed by the symlink doesn't - exist, an exception will be added in the list of errors raised in - an Error exception at the end of the copy process. - - You can set the optional ignore_dangling_symlinks flag to true if you - want to silence this exception. Notice that this has no effect on - platforms that don't support os.symlink. - - The optional ignore argument is a callable. If given, it - is called with the `src` parameter, which is the directory - being visited by copytree(), and `names` which is the list of - `src` contents, as returned by os.listdir(): - - callable(src, names) -> ignored_names - - Since copytree() is called recursively, the callable will be - called once for each directory that is copied. It returns a - list of names relative to the `src` directory that should - not be copied. - - The optional copy_function argument is a callable that will be used - to copy each file. It will be called with the source path and the - destination path as arguments. By default, copy2() is used, but any - function that supports the same signature (like copy()) can be used. - - """ - names = os.listdir(src) - if ignore is not None: - ignored_names = ignore(src, names) - else: - ignored_names = set() - - os.makedirs(dst) - errors = [] - for name in names: - if name in ignored_names: - continue - srcname = os.path.join(src, name) - dstname = os.path.join(dst, name) - try: - if os.path.islink(srcname): - linkto = os.readlink(srcname) - if symlinks: - os.symlink(linkto, dstname) - else: - # ignore dangling symlink if the flag is on - if not os.path.exists(linkto) and ignore_dangling_symlinks: - continue - # otherwise let the copy occurs. copy2 will raise an error - copy_function(srcname, dstname) - elif os.path.isdir(srcname): - copytree(srcname, dstname, symlinks, ignore, copy_function) - else: - # Will raise a SpecialFileError for unsupported file types - copy_function(srcname, dstname) - # catch the Error from the recursive copytree so that we can - # continue with other files - except Error as err: - errors.extend(err.args[0]) - except EnvironmentError as why: - errors.append((srcname, dstname, str(why))) - try: - copystat(src, dst) - except OSError as why: - if WindowsError is not None and isinstance(why, WindowsError): - # Copying file access times may fail on Windows - pass - else: - errors.extend((src, dst, str(why))) - if errors: - raise Error(errors) - -def rmtree(path, ignore_errors=False, onerror=None): - """Recursively delete a directory tree. - - If ignore_errors is set, errors are ignored; otherwise, if onerror - is set, it is called to handle the error with arguments (func, - path, exc_info) where func is os.listdir, os.remove, or os.rmdir; - path is the argument to that function that caused it to fail; and - exc_info is a tuple returned by sys.exc_info(). If ignore_errors - is false and onerror is None, an exception is raised. - - """ - if ignore_errors: - def onerror(*args): - pass - elif onerror is None: - def onerror(*args): - raise - try: - if os.path.islink(path): - # symlinks to directories are forbidden, see bug #1669 - raise OSError("Cannot call rmtree on a symbolic link") - except OSError: - onerror(os.path.islink, path, sys.exc_info()) - # can't continue even if onerror hook returns - return - names = [] - try: - names = os.listdir(path) - except os.error: - onerror(os.listdir, path, sys.exc_info()) - for name in names: - fullname = os.path.join(path, name) - try: - mode = os.lstat(fullname).st_mode - except os.error: - mode = 0 - if stat.S_ISDIR(mode): - rmtree(fullname, ignore_errors, onerror) - else: - try: - os.remove(fullname) - except os.error: - onerror(os.remove, fullname, sys.exc_info()) - try: - os.rmdir(path) - except os.error: - onerror(os.rmdir, path, sys.exc_info()) - - -def _basename(path): - # A basename() variant which first strips the trailing slash, if present. - # Thus we always get the last component of the path, even for directories. - return os.path.basename(path.rstrip(os.path.sep)) - -def move(src, dst): - """Recursively move a file or directory to another location. This is - similar to the Unix "mv" command. - - If the destination is a directory or a symlink to a directory, the source - is moved inside the directory. The destination path must not already - exist. - - If the destination already exists but is not a directory, it may be - overwritten depending on os.rename() semantics. - - If the destination is on our current filesystem, then rename() is used. - Otherwise, src is copied to the destination and then removed. - A lot more could be done here... A look at a mv.c shows a lot of - the issues this implementation glosses over. - - """ - real_dst = dst - if os.path.isdir(dst): - if _samefile(src, dst): - # We might be on a case insensitive filesystem, - # perform the rename anyway. - os.rename(src, dst) - return - - real_dst = os.path.join(dst, _basename(src)) - if os.path.exists(real_dst): - raise Error("Destination path '%s' already exists" % real_dst) - try: - os.rename(src, real_dst) - except OSError: - if os.path.isdir(src): - if _destinsrc(src, dst): - raise Error("Cannot move a directory '%s' into itself '%s'." % (src, dst)) - copytree(src, real_dst, symlinks=True) - rmtree(src) - else: - copy2(src, real_dst) - os.unlink(src) - -def _destinsrc(src, dst): - src = abspath(src) - dst = abspath(dst) - if not src.endswith(os.path.sep): - src += os.path.sep - if not dst.endswith(os.path.sep): - dst += os.path.sep - return dst.startswith(src) - -def _get_gid(name): - """Returns a gid, given a group name.""" - if getgrnam is None or name is None: - return None - try: - result = getgrnam(name) - except KeyError: - result = None - if result is not None: - return result[2] - return None - -def _get_uid(name): - """Returns an uid, given a user name.""" - if getpwnam is None or name is None: - return None - try: - result = getpwnam(name) - except KeyError: - result = None - if result is not None: - return result[2] - return None - -def _make_tarball(base_name, base_dir, compress="gzip", verbose=0, dry_run=0, - owner=None, group=None, logger=None): - """Create a (possibly compressed) tar file from all the files under - 'base_dir'. - - 'compress' must be "gzip" (the default), "bzip2", or None. - - 'owner' and 'group' can be used to define an owner and a group for the - archive that is being built. If not provided, the current owner and group - will be used. - - The output tar file will be named 'base_name' + ".tar", possibly plus - the appropriate compression extension (".gz", or ".bz2"). - - Returns the output filename. - """ - tar_compression = {'gzip': 'gz', None: ''} - compress_ext = {'gzip': '.gz'} - - if _BZ2_SUPPORTED: - tar_compression['bzip2'] = 'bz2' - compress_ext['bzip2'] = '.bz2' - - # flags for compression program, each element of list will be an argument - if compress is not None and compress not in compress_ext: - raise ValueError("bad value for 'compress', or compression format not " - "supported : {0}".format(compress)) - - archive_name = base_name + '.tar' + compress_ext.get(compress, '') - archive_dir = os.path.dirname(archive_name) - - if not os.path.exists(archive_dir): - if logger is not None: - logger.info("creating %s", archive_dir) - if not dry_run: - os.makedirs(archive_dir) - - # creating the tarball - if logger is not None: - logger.info('Creating tar archive') - - uid = _get_uid(owner) - gid = _get_gid(group) - - def _set_uid_gid(tarinfo): - if gid is not None: - tarinfo.gid = gid - tarinfo.gname = group - if uid is not None: - tarinfo.uid = uid - tarinfo.uname = owner - return tarinfo - - if not dry_run: - tar = tarfile.open(archive_name, 'w|%s' % tar_compression[compress]) - try: - tar.add(base_dir, filter=_set_uid_gid) - finally: - tar.close() - - return archive_name - -def _call_external_zip(base_dir, zip_filename, verbose=False, dry_run=False): - # XXX see if we want to keep an external call here - if verbose: - zipoptions = "-r" - else: - zipoptions = "-rq" - from distutils.errors import DistutilsExecError - from distutils.spawn import spawn - try: - spawn(["zip", zipoptions, zip_filename, base_dir], dry_run=dry_run) - except DistutilsExecError: - # XXX really should distinguish between "couldn't find - # external 'zip' command" and "zip failed". - raise ExecError("unable to create zip file '%s': " - "could neither import the 'zipfile' module nor " - "find a standalone zip utility") % zip_filename - -def _make_zipfile(base_name, base_dir, verbose=0, dry_run=0, logger=None): - """Create a zip file from all the files under 'base_dir'. - - The output zip file will be named 'base_name' + ".zip". Uses either the - "zipfile" Python module (if available) or the InfoZIP "zip" utility - (if installed and found on the default search path). If neither tool is - available, raises ExecError. Returns the name of the output zip - file. - """ - zip_filename = base_name + ".zip" - archive_dir = os.path.dirname(base_name) - - if not os.path.exists(archive_dir): - if logger is not None: - logger.info("creating %s", archive_dir) - if not dry_run: - os.makedirs(archive_dir) - - # If zipfile module is not available, try spawning an external 'zip' - # command. - try: - import zipfile - except ImportError: - zipfile = None - - if zipfile is None: - _call_external_zip(base_dir, zip_filename, verbose, dry_run) - else: - if logger is not None: - logger.info("creating '%s' and adding '%s' to it", - zip_filename, base_dir) - - if not dry_run: - zip = zipfile.ZipFile(zip_filename, "w", - compression=zipfile.ZIP_DEFLATED) - - for dirpath, dirnames, filenames in os.walk(base_dir): - for name in filenames: - path = os.path.normpath(os.path.join(dirpath, name)) - if os.path.isfile(path): - zip.write(path, path) - if logger is not None: - logger.info("adding '%s'", path) - zip.close() - - return zip_filename - -_ARCHIVE_FORMATS = { - 'gztar': (_make_tarball, [('compress', 'gzip')], "gzip'ed tar-file"), - 'bztar': (_make_tarball, [('compress', 'bzip2')], "bzip2'ed tar-file"), - 'tar': (_make_tarball, [('compress', None)], "uncompressed tar file"), - 'zip': (_make_zipfile, [], "ZIP file"), - } - -if _BZ2_SUPPORTED: - _ARCHIVE_FORMATS['bztar'] = (_make_tarball, [('compress', 'bzip2')], - "bzip2'ed tar-file") - -def get_archive_formats(): - """Returns a list of supported formats for archiving and unarchiving. - - Each element of the returned sequence is a tuple (name, description) - """ - formats = [(name, registry[2]) for name, registry in - _ARCHIVE_FORMATS.items()] - formats.sort() - return formats - -def register_archive_format(name, function, extra_args=None, description=''): - """Registers an archive format. - - name is the name of the format. function is the callable that will be - used to create archives. If provided, extra_args is a sequence of - (name, value) tuples that will be passed as arguments to the callable. - description can be provided to describe the format, and will be returned - by the get_archive_formats() function. - """ - if extra_args is None: - extra_args = [] - if not isinstance(function, collections.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') - for element in extra_args: - if not isinstance(element, (tuple, list)) or len(element) !=2: - raise TypeError('extra_args elements are : (arg_name, value)') - - _ARCHIVE_FORMATS[name] = (function, extra_args, description) - -def unregister_archive_format(name): - del _ARCHIVE_FORMATS[name] - -def make_archive(base_name, format, root_dir=None, base_dir=None, verbose=0, - dry_run=0, owner=None, group=None, logger=None): - """Create an archive file (eg. zip or tar). - - 'base_name' is the name of the file to create, minus any format-specific - extension; 'format' is the archive format: one of "zip", "tar", "bztar" - or "gztar". - - 'root_dir' is a directory that will be the root directory of the - archive; ie. we typically chdir into 'root_dir' before creating the - archive. 'base_dir' is the directory where we start archiving from; - ie. 'base_dir' will be the common prefix of all files and - directories in the archive. 'root_dir' and 'base_dir' both default - to the current directory. Returns the name of the archive file. - - 'owner' and 'group' are used when creating a tar archive. By default, - uses the current owner and group. - """ - save_cwd = os.getcwd() - if root_dir is not None: - if logger is not None: - logger.debug("changing into '%s'", root_dir) - base_name = os.path.abspath(base_name) - if not dry_run: - os.chdir(root_dir) - - if base_dir is None: - base_dir = os.curdir - - kwargs = {'dry_run': dry_run, 'logger': logger} - - try: - format_info = _ARCHIVE_FORMATS[format] - except KeyError: - raise ValueError("unknown archive format '%s'" % format) - - func = format_info[0] - for arg, val in format_info[1]: - kwargs[arg] = val - - if format != 'zip': - kwargs['owner'] = owner - kwargs['group'] = group - - try: - filename = func(base_name, base_dir, **kwargs) - finally: - if root_dir is not None: - if logger is not None: - logger.debug("changing back to '%s'", save_cwd) - os.chdir(save_cwd) - - return filename - - -def get_unpack_formats(): - """Returns a list of supported formats for unpacking. - - Each element of the returned sequence is a tuple - (name, extensions, description) - """ - formats = [(name, info[0], info[3]) for name, info in - _UNPACK_FORMATS.items()] - formats.sort() - return formats - -def _check_unpack_options(extensions, function, extra_args): - """Checks what gets registered as an unpacker.""" - # first make sure no other unpacker is registered for this extension - existing_extensions = {} - for name, info in _UNPACK_FORMATS.items(): - for ext in info[0]: - existing_extensions[ext] = name - - for extension in extensions: - if extension in existing_extensions: - msg = '%s is already registered for "%s"' - raise RegistryError(msg % (extension, - existing_extensions[extension])) - - if not isinstance(function, collections.Callable): - raise TypeError('The registered function must be a callable') - - -def register_unpack_format(name, extensions, function, extra_args=None, - description=''): - """Registers an unpack format. - - `name` is the name of the format. `extensions` is a list of extensions - corresponding to the format. - - `function` is the callable that will be - used to unpack archives. The callable will receive archives to unpack. - If it's unable to handle an archive, it needs to raise a ReadError - exception. - - If provided, `extra_args` is a sequence of - (name, value) tuples that will be passed as arguments to the callable. - description can be provided to describe the format, and will be returned - by the get_unpack_formats() function. - """ - if extra_args is None: - extra_args = [] - _check_unpack_options(extensions, function, extra_args) - _UNPACK_FORMATS[name] = extensions, function, extra_args, description - -def unregister_unpack_format(name): - """Removes the pack format from the registery.""" - del _UNPACK_FORMATS[name] - -def _ensure_directory(path): - """Ensure that the parent directory of `path` exists""" - dirname = os.path.dirname(path) - if not os.path.isdir(dirname): - os.makedirs(dirname) - -def _unpack_zipfile(filename, extract_dir): - """Unpack zip `filename` to `extract_dir` - """ - try: - import zipfile - except ImportError: - raise ReadError('zlib not supported, cannot unpack this archive.') - - if not zipfile.is_zipfile(filename): - raise ReadError("%s is not a zip file" % filename) - - zip = zipfile.ZipFile(filename) - try: - for info in zip.infolist(): - name = info.filename - - # don't extract absolute paths or ones with .. in them - if name.startswith('/') or '..' in name: - continue - - target = os.path.join(extract_dir, *name.split('/')) - if not target: - continue - - _ensure_directory(target) - if not name.endswith('/'): - # file - data = zip.read(info.filename) - f = open(target, 'wb') - try: - f.write(data) - finally: - f.close() - del data - finally: - zip.close() - -def _unpack_tarfile(filename, extract_dir): - """Unpack tar/tar.gz/tar.bz2 `filename` to `extract_dir` - """ - try: - tarobj = tarfile.open(filename) - except tarfile.TarError: - raise ReadError( - "%s is not a compressed or uncompressed tar file" % filename) - try: - tarobj.extractall(extract_dir) - finally: - tarobj.close() - -_UNPACK_FORMATS = { - 'gztar': (['.tar.gz', '.tgz'], _unpack_tarfile, [], "gzip'ed tar-file"), - 'tar': (['.tar'], _unpack_tarfile, [], "uncompressed tar file"), - 'zip': (['.zip'], _unpack_zipfile, [], "ZIP file") - } - -if _BZ2_SUPPORTED: - _UNPACK_FORMATS['bztar'] = (['.bz2'], _unpack_tarfile, [], - "bzip2'ed tar-file") - -def _find_unpack_format(filename): - for name, info in _UNPACK_FORMATS.items(): - for extension in info[0]: - if filename.endswith(extension): - return name - return None - -def unpack_archive(filename, extract_dir=None, format=None): - """Unpack an archive. - - `filename` is the name of the archive. - - `extract_dir` is the name of the target directory, where the archive - is unpacked. If not provided, the current working directory is used. - - `format` is the archive format: one of "zip", "tar", or "gztar". Or any - other registered format. If not provided, unpack_archive will use the - filename extension and see if an unpacker was registered for that - extension. - - In case none is found, a ValueError is raised. - """ - if extract_dir is None: - extract_dir = os.getcwd() - - if format is not None: - try: - format_info = _UNPACK_FORMATS[format] - except KeyError: - raise ValueError("Unknown unpack format '{0}'".format(format)) - - func = format_info[1] - func(filename, extract_dir, **dict(format_info[2])) - else: - # we need to look at the registered unpackers supported extensions - format = _find_unpack_format(filename) - if format is None: - raise ReadError("Unknown archive format '{0}'".format(filename)) - - func = _UNPACK_FORMATS[format][1] - kwargs = dict(_UNPACK_FORMATS[format][2]) - func(filename, extract_dir, **kwargs) diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/_backport/sysconfig.cfg b/vendor/pip-1.5.6/pip/_vendor/distlib/_backport/sysconfig.cfg deleted file mode 100644 index 1746bd0..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/distlib/_backport/sysconfig.cfg +++ /dev/null @@ -1,84 +0,0 @@ -[posix_prefix] -# Configuration directories. Some of these come straight out of the -# configure script. They are for implementing the other variables, not to -# be used directly in [resource_locations]. -confdir = /etc -datadir = /usr/share -libdir = /usr/lib -statedir = /var -# User resource directory -local = ~/.local/{distribution.name} - -stdlib = {base}/lib/python{py_version_short} -platstdlib = {platbase}/lib/python{py_version_short} -purelib = {base}/lib/python{py_version_short}/site-packages -platlib = {platbase}/lib/python{py_version_short}/site-packages -include = {base}/include/python{py_version_short}{abiflags} -platinclude = {platbase}/include/python{py_version_short}{abiflags} -data = {base} - -[posix_home] -stdlib = {base}/lib/python -platstdlib = {base}/lib/python -purelib = {base}/lib/python -platlib = {base}/lib/python -include = {base}/include/python -platinclude = {base}/include/python -scripts = {base}/bin -data = {base} - -[nt] -stdlib = {base}/Lib -platstdlib = {base}/Lib -purelib = {base}/Lib/site-packages -platlib = {base}/Lib/site-packages -include = {base}/Include -platinclude = {base}/Include -scripts = {base}/Scripts -data = {base} - -[os2] -stdlib = {base}/Lib -platstdlib = {base}/Lib -purelib = {base}/Lib/site-packages -platlib = {base}/Lib/site-packages -include = {base}/Include -platinclude = {base}/Include -scripts = {base}/Scripts -data = {base} - -[os2_home] -stdlib = {userbase}/lib/python{py_version_short} -platstdlib = {userbase}/lib/python{py_version_short} -purelib = {userbase}/lib/python{py_version_short}/site-packages -platlib = {userbase}/lib/python{py_version_short}/site-packages -include = {userbase}/include/python{py_version_short} -scripts = {userbase}/bin -data = {userbase} - -[nt_user] -stdlib = {userbase}/Python{py_version_nodot} -platstdlib = {userbase}/Python{py_version_nodot} -purelib = {userbase}/Python{py_version_nodot}/site-packages -platlib = {userbase}/Python{py_version_nodot}/site-packages -include = {userbase}/Python{py_version_nodot}/Include -scripts = {userbase}/Scripts -data = {userbase} - -[posix_user] -stdlib = {userbase}/lib/python{py_version_short} -platstdlib = {userbase}/lib/python{py_version_short} -purelib = {userbase}/lib/python{py_version_short}/site-packages -platlib = {userbase}/lib/python{py_version_short}/site-packages -include = {userbase}/include/python{py_version_short} -scripts = {userbase}/bin -data = {userbase} - -[osx_framework_user] -stdlib = {userbase}/lib/python -platstdlib = {userbase}/lib/python -purelib = {userbase}/lib/python/site-packages -platlib = {userbase}/lib/python/site-packages -include = {userbase}/include -scripts = {userbase}/bin -data = {userbase} diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/_backport/sysconfig.py b/vendor/pip-1.5.6/pip/_vendor/distlib/_backport/sysconfig.py deleted file mode 100644 index 1d31326..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/distlib/_backport/sysconfig.py +++ /dev/null @@ -1,788 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012 The Python Software Foundation. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -"""Access to Python's configuration information.""" - -import codecs -import os -import re -import sys -from os.path import pardir, realpath -try: - import configparser -except ImportError: - import ConfigParser as configparser - - -__all__ = [ - 'get_config_h_filename', - 'get_config_var', - 'get_config_vars', - 'get_makefile_filename', - 'get_path', - 'get_path_names', - 'get_paths', - 'get_platform', - 'get_python_version', - 'get_scheme_names', - 'parse_config_h', -] - - -def _safe_realpath(path): - try: - return realpath(path) - except OSError: - return path - - -if sys.executable: - _PROJECT_BASE = os.path.dirname(_safe_realpath(sys.executable)) -else: - # sys.executable can be empty if argv[0] has been changed and Python is - # unable to retrieve the real program name - _PROJECT_BASE = _safe_realpath(os.getcwd()) - -if os.name == "nt" and "pcbuild" in _PROJECT_BASE[-8:].lower(): - _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir)) -# PC/VS7.1 -if os.name == "nt" and "\\pc\\v" in _PROJECT_BASE[-10:].lower(): - _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir)) -# PC/AMD64 -if os.name == "nt" and "\\pcbuild\\amd64" in _PROJECT_BASE[-14:].lower(): - _PROJECT_BASE = _safe_realpath(os.path.join(_PROJECT_BASE, pardir, pardir)) - - -def is_python_build(): - for fn in ("Setup.dist", "Setup.local"): - if os.path.isfile(os.path.join(_PROJECT_BASE, "Modules", fn)): - return True - return False - -_PYTHON_BUILD = is_python_build() - -_cfg_read = False - -def _ensure_cfg_read(): - global _cfg_read - if not _cfg_read: - from ..resources import finder - backport_package = __name__.rsplit('.', 1)[0] - _finder = finder(backport_package) - _cfgfile = _finder.find('sysconfig.cfg') - assert _cfgfile, 'sysconfig.cfg exists' - with _cfgfile.as_stream() as s: - _SCHEMES.readfp(s) - if _PYTHON_BUILD: - for scheme in ('posix_prefix', 'posix_home'): - _SCHEMES.set(scheme, 'include', '{srcdir}/Include') - _SCHEMES.set(scheme, 'platinclude', '{projectbase}/.') - - _cfg_read = True - - -_SCHEMES = configparser.RawConfigParser() -_VAR_REPL = re.compile(r'\{([^{]*?)\}') - -def _expand_globals(config): - _ensure_cfg_read() - if config.has_section('globals'): - globals = config.items('globals') - else: - globals = tuple() - - sections = config.sections() - for section in sections: - if section == 'globals': - continue - for option, value in globals: - if config.has_option(section, option): - continue - config.set(section, option, value) - config.remove_section('globals') - - # now expanding local variables defined in the cfg file - # - for section in config.sections(): - variables = dict(config.items(section)) - - def _replacer(matchobj): - name = matchobj.group(1) - if name in variables: - return variables[name] - return matchobj.group(0) - - for option, value in config.items(section): - config.set(section, option, _VAR_REPL.sub(_replacer, value)) - -#_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] -_PREFIX = os.path.normpath(sys.prefix) -_EXEC_PREFIX = os.path.normpath(sys.exec_prefix) -_CONFIG_VARS = None -_USER_BASE = None - - -def _subst_vars(path, local_vars): - """In the string `path`, replace tokens like {some.thing} with the - corresponding value from the map `local_vars`. - - If there is no corresponding value, leave the token unchanged. - """ - def _replacer(matchobj): - name = matchobj.group(1) - if name in local_vars: - return local_vars[name] - elif name in os.environ: - return os.environ[name] - return matchobj.group(0) - return _VAR_REPL.sub(_replacer, path) - - -def _extend_dict(target_dict, other_dict): - target_keys = target_dict.keys() - for key, value in other_dict.items(): - if key in target_keys: - continue - target_dict[key] = value - - -def _expand_vars(scheme, vars): - res = {} - if vars is None: - vars = {} - _extend_dict(vars, get_config_vars()) - - for key, value in _SCHEMES.items(scheme): - if os.name in ('posix', 'nt'): - value = os.path.expanduser(value) - res[key] = os.path.normpath(_subst_vars(value, vars)) - return res - - -def format_value(value, vars): - def _replacer(matchobj): - name = matchobj.group(1) - if name in vars: - return vars[name] - return matchobj.group(0) - return _VAR_REPL.sub(_replacer, value) - - -def _get_default_scheme(): - if os.name == 'posix': - # the default scheme for posix is posix_prefix - return 'posix_prefix' - return os.name - - -def _getuserbase(): - env_base = os.environ.get("PYTHONUSERBASE", None) - - def joinuser(*args): - return os.path.expanduser(os.path.join(*args)) - - # what about 'os2emx', 'riscos' ? - if os.name == "nt": - base = os.environ.get("APPDATA") or "~" - if env_base: - return env_base - else: - return joinuser(base, "Python") - - if sys.platform == "darwin": - framework = get_config_var("PYTHONFRAMEWORK") - if framework: - if env_base: - return env_base - else: - return joinuser("~", "Library", framework, "%d.%d" % - sys.version_info[:2]) - - if env_base: - return env_base - else: - return joinuser("~", ".local") - - -def _parse_makefile(filename, vars=None): - """Parse a Makefile-style file. - - A dictionary containing name/value pairs is returned. If an - optional dictionary is passed in as the second argument, it is - used instead of a new dictionary. - """ - # Regexes needed for parsing Makefile (and similar syntaxes, - # like old-style Setup files). - _variable_rx = re.compile("([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)") - _findvar1_rx = re.compile(r"\$\(([A-Za-z][A-Za-z0-9_]*)\)") - _findvar2_rx = re.compile(r"\${([A-Za-z][A-Za-z0-9_]*)}") - - if vars is None: - vars = {} - done = {} - notdone = {} - - with codecs.open(filename, encoding='utf-8', errors="surrogateescape") as f: - lines = f.readlines() - - for line in lines: - if line.startswith('#') or line.strip() == '': - continue - m = _variable_rx.match(line) - if m: - n, v = m.group(1, 2) - v = v.strip() - # `$$' is a literal `$' in make - tmpv = v.replace('$$', '') - - if "$" in tmpv: - notdone[n] = v - else: - try: - v = int(v) - except ValueError: - # insert literal `$' - done[n] = v.replace('$$', '$') - else: - done[n] = v - - # do variable interpolation here - variables = list(notdone.keys()) - - # Variables with a 'PY_' prefix in the makefile. These need to - # be made available without that prefix through sysconfig. - # Special care is needed to ensure that variable expansion works, even - # if the expansion uses the name without a prefix. - renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS') - - while len(variables) > 0: - for name in tuple(variables): - value = notdone[name] - m = _findvar1_rx.search(value) or _findvar2_rx.search(value) - if m is not None: - n = m.group(1) - found = True - if n in done: - item = str(done[n]) - elif n in notdone: - # get it on a subsequent round - found = False - elif n in os.environ: - # do it like make: fall back to environment - item = os.environ[n] - - elif n in renamed_variables: - if (name.startswith('PY_') and - name[3:] in renamed_variables): - item = "" - - elif 'PY_' + n in notdone: - found = False - - else: - item = str(done['PY_' + n]) - - else: - done[n] = item = "" - - if found: - after = value[m.end():] - value = value[:m.start()] + item + after - if "$" in after: - notdone[name] = value - else: - try: - value = int(value) - except ValueError: - done[name] = value.strip() - else: - done[name] = value - variables.remove(name) - - if (name.startswith('PY_') and - name[3:] in renamed_variables): - - name = name[3:] - if name not in done: - done[name] = value - - else: - # bogus variable reference (e.g. "prefix=$/opt/python"); - # just drop it since we can't deal - done[name] = value - variables.remove(name) - - # strip spurious spaces - for k, v in done.items(): - if isinstance(v, str): - done[k] = v.strip() - - # save the results in the global dictionary - vars.update(done) - return vars - - -def get_makefile_filename(): - """Return the path of the Makefile.""" - if _PYTHON_BUILD: - return os.path.join(_PROJECT_BASE, "Makefile") - if hasattr(sys, 'abiflags'): - config_dir_name = 'config-%s%s' % (_PY_VERSION_SHORT, sys.abiflags) - else: - config_dir_name = 'config' - return os.path.join(get_path('stdlib'), config_dir_name, 'Makefile') - - -def _init_posix(vars): - """Initialize the module as appropriate for POSIX systems.""" - # load the installed Makefile: - makefile = get_makefile_filename() - try: - _parse_makefile(makefile, vars) - except IOError as e: - msg = "invalid Python installation: unable to open %s" % makefile - if hasattr(e, "strerror"): - msg = msg + " (%s)" % e.strerror - raise IOError(msg) - # load the installed pyconfig.h: - config_h = get_config_h_filename() - try: - with open(config_h) as f: - parse_config_h(f, vars) - except IOError as e: - msg = "invalid Python installation: unable to open %s" % config_h - if hasattr(e, "strerror"): - msg = msg + " (%s)" % e.strerror - raise IOError(msg) - # On AIX, there are wrong paths to the linker scripts in the Makefile - # -- these paths are relative to the Python source, but when installed - # the scripts are in another directory. - if _PYTHON_BUILD: - vars['LDSHARED'] = vars['BLDSHARED'] - - -def _init_non_posix(vars): - """Initialize the module as appropriate for NT""" - # set basic install directories - vars['LIBDEST'] = get_path('stdlib') - vars['BINLIBDEST'] = get_path('platstdlib') - vars['INCLUDEPY'] = get_path('include') - vars['SO'] = '.pyd' - vars['EXE'] = '.exe' - vars['VERSION'] = _PY_VERSION_SHORT_NO_DOT - vars['BINDIR'] = os.path.dirname(_safe_realpath(sys.executable)) - -# -# public APIs -# - - -def parse_config_h(fp, vars=None): - """Parse a config.h-style file. - - A dictionary containing name/value pairs is returned. If an - optional dictionary is passed in as the second argument, it is - used instead of a new dictionary. - """ - if vars is None: - vars = {} - define_rx = re.compile("#define ([A-Z][A-Za-z0-9_]+) (.*)\n") - undef_rx = re.compile("/[*] #undef ([A-Z][A-Za-z0-9_]+) [*]/\n") - - while True: - line = fp.readline() - if not line: - break - m = define_rx.match(line) - if m: - n, v = m.group(1, 2) - try: - v = int(v) - except ValueError: - pass - vars[n] = v - else: - m = undef_rx.match(line) - if m: - vars[m.group(1)] = 0 - return vars - - -def get_config_h_filename(): - """Return the path of pyconfig.h.""" - if _PYTHON_BUILD: - if os.name == "nt": - inc_dir = os.path.join(_PROJECT_BASE, "PC") - else: - inc_dir = _PROJECT_BASE - else: - inc_dir = get_path('platinclude') - return os.path.join(inc_dir, 'pyconfig.h') - - -def get_scheme_names(): - """Return a tuple containing the schemes names.""" - return tuple(sorted(_SCHEMES.sections())) - - -def get_path_names(): - """Return a tuple containing the paths names.""" - # xxx see if we want a static list - return _SCHEMES.options('posix_prefix') - - -def get_paths(scheme=_get_default_scheme(), vars=None, expand=True): - """Return a mapping containing an install scheme. - - ``scheme`` is the install scheme name. If not provided, it will - return the default scheme for the current platform. - """ - _ensure_cfg_read() - if expand: - return _expand_vars(scheme, vars) - else: - return dict(_SCHEMES.items(scheme)) - - -def get_path(name, scheme=_get_default_scheme(), vars=None, expand=True): - """Return a path corresponding to the scheme. - - ``scheme`` is the install scheme name. - """ - return get_paths(scheme, vars, expand)[name] - - -def get_config_vars(*args): - """With no arguments, return a dictionary of all configuration - variables relevant for the current platform. - - On Unix, this means every variable defined in Python's installed Makefile; - On Windows and Mac OS it's a much smaller set. - - With arguments, return a list of values that result from looking up - each argument in the configuration variable dictionary. - """ - global _CONFIG_VARS - if _CONFIG_VARS is None: - _CONFIG_VARS = {} - # Normalized versions of prefix and exec_prefix are handy to have; - # in fact, these are the standard versions used most places in the - # distutils2 module. - _CONFIG_VARS['prefix'] = _PREFIX - _CONFIG_VARS['exec_prefix'] = _EXEC_PREFIX - _CONFIG_VARS['py_version'] = _PY_VERSION - _CONFIG_VARS['py_version_short'] = _PY_VERSION_SHORT - _CONFIG_VARS['py_version_nodot'] = _PY_VERSION[0] + _PY_VERSION[2] - _CONFIG_VARS['base'] = _PREFIX - _CONFIG_VARS['platbase'] = _EXEC_PREFIX - _CONFIG_VARS['projectbase'] = _PROJECT_BASE - try: - _CONFIG_VARS['abiflags'] = sys.abiflags - except AttributeError: - # sys.abiflags may not be defined on all platforms. - _CONFIG_VARS['abiflags'] = '' - - if os.name in ('nt', 'os2'): - _init_non_posix(_CONFIG_VARS) - if os.name == 'posix': - _init_posix(_CONFIG_VARS) - # Setting 'userbase' is done below the call to the - # init function to enable using 'get_config_var' in - # the init-function. - if sys.version >= '2.6': - _CONFIG_VARS['userbase'] = _getuserbase() - - if 'srcdir' not in _CONFIG_VARS: - _CONFIG_VARS['srcdir'] = _PROJECT_BASE - else: - _CONFIG_VARS['srcdir'] = _safe_realpath(_CONFIG_VARS['srcdir']) - - # Convert srcdir into an absolute path if it appears necessary. - # Normally it is relative to the build directory. However, during - # testing, for example, we might be running a non-installed python - # from a different directory. - if _PYTHON_BUILD and os.name == "posix": - base = _PROJECT_BASE - try: - cwd = os.getcwd() - except OSError: - cwd = None - if (not os.path.isabs(_CONFIG_VARS['srcdir']) and - base != cwd): - # srcdir is relative and we are not in the same directory - # as the executable. Assume executable is in the build - # directory and make srcdir absolute. - srcdir = os.path.join(base, _CONFIG_VARS['srcdir']) - _CONFIG_VARS['srcdir'] = os.path.normpath(srcdir) - - if sys.platform == 'darwin': - kernel_version = os.uname()[2] # Kernel version (8.4.3) - major_version = int(kernel_version.split('.')[0]) - - if major_version < 8: - # On Mac OS X before 10.4, check if -arch and -isysroot - # are in CFLAGS or LDFLAGS and remove them if they are. - # This is needed when building extensions on a 10.3 system - # using a universal build of python. - for key in ('LDFLAGS', 'BASECFLAGS', - # a number of derived variables. These need to be - # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - flags = _CONFIG_VARS[key] - flags = re.sub('-arch\s+\w+\s', ' ', flags) - flags = re.sub('-isysroot [^ \t]*', ' ', flags) - _CONFIG_VARS[key] = flags - else: - # Allow the user to override the architecture flags using - # an environment variable. - # NOTE: This name was introduced by Apple in OSX 10.5 and - # is used by several scripting languages distributed with - # that OS release. - if 'ARCHFLAGS' in os.environ: - arch = os.environ['ARCHFLAGS'] - for key in ('LDFLAGS', 'BASECFLAGS', - # a number of derived variables. These need to be - # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - - flags = _CONFIG_VARS[key] - flags = re.sub('-arch\s+\w+\s', ' ', flags) - flags = flags + ' ' + arch - _CONFIG_VARS[key] = flags - - # If we're on OSX 10.5 or later and the user tries to - # compiles an extension using an SDK that is not present - # on the current machine it is better to not use an SDK - # than to fail. - # - # The major usecase for this is users using a Python.org - # binary installer on OSX 10.6: that installer uses - # the 10.4u SDK, but that SDK is not installed by default - # when you install Xcode. - # - CFLAGS = _CONFIG_VARS.get('CFLAGS', '') - m = re.search('-isysroot\s+(\S+)', CFLAGS) - if m is not None: - sdk = m.group(1) - if not os.path.exists(sdk): - for key in ('LDFLAGS', 'BASECFLAGS', - # a number of derived variables. These need to be - # patched up as well. - 'CFLAGS', 'PY_CFLAGS', 'BLDSHARED'): - - flags = _CONFIG_VARS[key] - flags = re.sub('-isysroot\s+\S+(\s|$)', ' ', flags) - _CONFIG_VARS[key] = flags - - if args: - vals = [] - for name in args: - vals.append(_CONFIG_VARS.get(name)) - return vals - else: - return _CONFIG_VARS - - -def get_config_var(name): - """Return the value of a single variable using the dictionary returned by - 'get_config_vars()'. - - Equivalent to get_config_vars().get(name) - """ - return get_config_vars().get(name) - - -def get_platform(): - """Return a string that identifies the current platform. - - This is used mainly to distinguish platform-specific build directories and - platform-specific built distributions. Typically includes the OS name - and version and the architecture (as supplied by 'os.uname()'), - although the exact information included depends on the OS; eg. for IRIX - the architecture isn't particularly important (IRIX only runs on SGI - hardware), but for Linux the kernel version isn't particularly - important. - - Examples of returned values: - linux-i586 - linux-alpha (?) - solaris-2.6-sun4u - irix-5.3 - irix64-6.2 - - Windows will return one of: - win-amd64 (64bit Windows on AMD64 (aka x86_64, Intel64, EM64T, etc) - win-ia64 (64bit Windows on Itanium) - win32 (all others - specifically, sys.platform is returned) - - For other non-POSIX platforms, currently just returns 'sys.platform'. - """ - if os.name == 'nt': - # sniff sys.version for architecture. - prefix = " bit (" - i = sys.version.find(prefix) - if i == -1: - return sys.platform - j = sys.version.find(")", i) - look = sys.version[i+len(prefix):j].lower() - if look == 'amd64': - return 'win-amd64' - if look == 'itanium': - return 'win-ia64' - return sys.platform - - if os.name != "posix" or not hasattr(os, 'uname'): - # XXX what about the architecture? NT is Intel or Alpha, - # Mac OS is M68k or PPC, etc. - return sys.platform - - # Try to distinguish various flavours of Unix - osname, host, release, version, machine = os.uname() - - # Convert the OS name to lowercase, remove '/' characters - # (to accommodate BSD/OS), and translate spaces (for "Power Macintosh") - osname = osname.lower().replace('/', '') - machine = machine.replace(' ', '_') - machine = machine.replace('/', '-') - - if osname[:5] == "linux": - # At least on Linux/Intel, 'machine' is the processor -- - # i386, etc. - # XXX what about Alpha, SPARC, etc? - return "%s-%s" % (osname, machine) - elif osname[:5] == "sunos": - if release[0] >= "5": # SunOS 5 == Solaris 2 - osname = "solaris" - release = "%d.%s" % (int(release[0]) - 3, release[2:]) - # fall through to standard osname-release-machine representation - elif osname[:4] == "irix": # could be "irix64"! - return "%s-%s" % (osname, release) - elif osname[:3] == "aix": - return "%s-%s.%s" % (osname, version, release) - elif osname[:6] == "cygwin": - osname = "cygwin" - rel_re = re.compile(r'[\d.]+') - m = rel_re.match(release) - if m: - release = m.group() - elif osname[:6] == "darwin": - # - # For our purposes, we'll assume that the system version from - # distutils' perspective is what MACOSX_DEPLOYMENT_TARGET is set - # to. This makes the compatibility story a bit more sane because the - # machine is going to compile and link as if it were - # MACOSX_DEPLOYMENT_TARGET. - cfgvars = get_config_vars() - macver = cfgvars.get('MACOSX_DEPLOYMENT_TARGET') - - if True: - # Always calculate the release of the running machine, - # needed to determine if we can build fat binaries or not. - - macrelease = macver - # Get the system version. Reading this plist is a documented - # way to get the system version (see the documentation for - # the Gestalt Manager) - try: - f = open('/System/Library/CoreServices/SystemVersion.plist') - except IOError: - # We're on a plain darwin box, fall back to the default - # behaviour. - pass - else: - try: - m = re.search(r'ProductUserVisibleVersion\s*' - r'(.*?)', f.read()) - finally: - f.close() - if m is not None: - macrelease = '.'.join(m.group(1).split('.')[:2]) - # else: fall back to the default behaviour - - if not macver: - macver = macrelease - - if macver: - release = macver - osname = "macosx" - - if ((macrelease + '.') >= '10.4.' and - '-arch' in get_config_vars().get('CFLAGS', '').strip()): - # The universal build will build fat binaries, but not on - # systems before 10.4 - # - # Try to detect 4-way universal builds, those have machine-type - # 'universal' instead of 'fat'. - - machine = 'fat' - cflags = get_config_vars().get('CFLAGS') - - archs = re.findall('-arch\s+(\S+)', cflags) - archs = tuple(sorted(set(archs))) - - if len(archs) == 1: - machine = archs[0] - elif archs == ('i386', 'ppc'): - machine = 'fat' - elif archs == ('i386', 'x86_64'): - machine = 'intel' - elif archs == ('i386', 'ppc', 'x86_64'): - machine = 'fat3' - elif archs == ('ppc64', 'x86_64'): - machine = 'fat64' - elif archs == ('i386', 'ppc', 'ppc64', 'x86_64'): - machine = 'universal' - else: - raise ValueError( - "Don't know machine value for archs=%r" % (archs,)) - - elif machine == 'i386': - # On OSX the machine type returned by uname is always the - # 32-bit variant, even if the executable architecture is - # the 64-bit variant - if sys.maxsize >= 2**32: - machine = 'x86_64' - - elif machine in ('PowerPC', 'Power_Macintosh'): - # Pick a sane name for the PPC architecture. - # See 'i386' case - if sys.maxsize >= 2**32: - machine = 'ppc64' - else: - machine = 'ppc' - - return "%s-%s-%s" % (osname, release, machine) - - -def get_python_version(): - return _PY_VERSION_SHORT - - -def _print_dict(title, data): - for index, (key, value) in enumerate(sorted(data.items())): - if index == 0: - print('%s: ' % (title)) - print('\t%s = "%s"' % (key, value)) - - -def _main(): - """Display all information sysconfig detains.""" - print('Platform: "%s"' % get_platform()) - print('Python version: "%s"' % get_python_version()) - print('Current installation scheme: "%s"' % _get_default_scheme()) - print() - _print_dict('Paths', get_paths()) - print() - _print_dict('Variables', get_config_vars()) - - -if __name__ == '__main__': - _main() diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/_backport/tarfile.py b/vendor/pip-1.5.6/pip/_vendor/distlib/_backport/tarfile.py deleted file mode 100644 index 0580fb7..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/distlib/_backport/tarfile.py +++ /dev/null @@ -1,2607 +0,0 @@ -#------------------------------------------------------------------- -# tarfile.py -#------------------------------------------------------------------- -# Copyright (C) 2002 Lars Gustaebel -# All rights reserved. -# -# 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. -# -from __future__ import print_function - -"""Read from and write to tar format archives. -""" - -__version__ = "$Revision$" - -version = "0.9.0" -__author__ = "Lars Gust\u00e4bel (lars@gustaebel.de)" -__date__ = "$Date: 2011-02-25 17:42:01 +0200 (Fri, 25 Feb 2011) $" -__cvsid__ = "$Id: tarfile.py 88586 2011-02-25 15:42:01Z marc-andre.lemburg $" -__credits__ = "Gustavo Niemeyer, Niels Gust\u00e4bel, Richard Townsend." - -#--------- -# Imports -#--------- -import sys -import os -import stat -import errno -import time -import struct -import copy -import re - -try: - import grp, pwd -except ImportError: - grp = pwd = None - -# os.symlink on Windows prior to 6.0 raises NotImplementedError -symlink_exception = (AttributeError, NotImplementedError) -try: - # WindowsError (1314) will be raised if the caller does not hold the - # SeCreateSymbolicLinkPrivilege privilege - symlink_exception += (WindowsError,) -except NameError: - pass - -# from tarfile import * -__all__ = ["TarFile", "TarInfo", "is_tarfile", "TarError"] - -if sys.version_info[0] < 3: - import __builtin__ as builtins -else: - import builtins - -_open = builtins.open # Since 'open' is TarFile.open - -#--------------------------------------------------------- -# tar constants -#--------------------------------------------------------- -NUL = b"\0" # the null character -BLOCKSIZE = 512 # length of processing blocks -RECORDSIZE = BLOCKSIZE * 20 # length of records -GNU_MAGIC = b"ustar \0" # magic gnu tar string -POSIX_MAGIC = b"ustar\x0000" # magic posix tar string - -LENGTH_NAME = 100 # maximum length of a filename -LENGTH_LINK = 100 # maximum length of a linkname -LENGTH_PREFIX = 155 # maximum length of the prefix field - -REGTYPE = b"0" # regular file -AREGTYPE = b"\0" # regular file -LNKTYPE = b"1" # link (inside tarfile) -SYMTYPE = b"2" # symbolic link -CHRTYPE = b"3" # character special device -BLKTYPE = b"4" # block special device -DIRTYPE = b"5" # directory -FIFOTYPE = b"6" # fifo special device -CONTTYPE = b"7" # contiguous file - -GNUTYPE_LONGNAME = b"L" # GNU tar longname -GNUTYPE_LONGLINK = b"K" # GNU tar longlink -GNUTYPE_SPARSE = b"S" # GNU tar sparse file - -XHDTYPE = b"x" # POSIX.1-2001 extended header -XGLTYPE = b"g" # POSIX.1-2001 global header -SOLARIS_XHDTYPE = b"X" # Solaris extended header - -USTAR_FORMAT = 0 # POSIX.1-1988 (ustar) format -GNU_FORMAT = 1 # GNU tar format -PAX_FORMAT = 2 # POSIX.1-2001 (pax) format -DEFAULT_FORMAT = GNU_FORMAT - -#--------------------------------------------------------- -# tarfile constants -#--------------------------------------------------------- -# File types that tarfile supports: -SUPPORTED_TYPES = (REGTYPE, AREGTYPE, LNKTYPE, - SYMTYPE, DIRTYPE, FIFOTYPE, - CONTTYPE, CHRTYPE, BLKTYPE, - GNUTYPE_LONGNAME, GNUTYPE_LONGLINK, - GNUTYPE_SPARSE) - -# File types that will be treated as a regular file. -REGULAR_TYPES = (REGTYPE, AREGTYPE, - CONTTYPE, GNUTYPE_SPARSE) - -# File types that are part of the GNU tar format. -GNU_TYPES = (GNUTYPE_LONGNAME, GNUTYPE_LONGLINK, - GNUTYPE_SPARSE) - -# Fields from a pax header that override a TarInfo attribute. -PAX_FIELDS = ("path", "linkpath", "size", "mtime", - "uid", "gid", "uname", "gname") - -# Fields from a pax header that are affected by hdrcharset. -PAX_NAME_FIELDS = set(("path", "linkpath", "uname", "gname")) - -# Fields in a pax header that are numbers, all other fields -# are treated as strings. -PAX_NUMBER_FIELDS = { - "atime": float, - "ctime": float, - "mtime": float, - "uid": int, - "gid": int, - "size": int -} - -#--------------------------------------------------------- -# Bits used in the mode field, values in octal. -#--------------------------------------------------------- -S_IFLNK = 0o120000 # symbolic link -S_IFREG = 0o100000 # regular file -S_IFBLK = 0o060000 # block device -S_IFDIR = 0o040000 # directory -S_IFCHR = 0o020000 # character device -S_IFIFO = 0o010000 # fifo - -TSUID = 0o4000 # set UID on execution -TSGID = 0o2000 # set GID on execution -TSVTX = 0o1000 # reserved - -TUREAD = 0o400 # read by owner -TUWRITE = 0o200 # write by owner -TUEXEC = 0o100 # execute/search by owner -TGREAD = 0o040 # read by group -TGWRITE = 0o020 # write by group -TGEXEC = 0o010 # execute/search by group -TOREAD = 0o004 # read by other -TOWRITE = 0o002 # write by other -TOEXEC = 0o001 # execute/search by other - -#--------------------------------------------------------- -# initialization -#--------------------------------------------------------- -if os.name in ("nt", "ce"): - ENCODING = "utf-8" -else: - ENCODING = sys.getfilesystemencoding() - -#--------------------------------------------------------- -# Some useful functions -#--------------------------------------------------------- - -def stn(s, length, encoding, errors): - """Convert a string to a null-terminated bytes object. - """ - s = s.encode(encoding, errors) - return s[:length] + (length - len(s)) * NUL - -def nts(s, encoding, errors): - """Convert a null-terminated bytes object to a string. - """ - p = s.find(b"\0") - if p != -1: - s = s[:p] - return s.decode(encoding, errors) - -def nti(s): - """Convert a number field to a python number. - """ - # There are two possible encodings for a number field, see - # itn() below. - if s[0] != chr(0o200): - try: - n = int(nts(s, "ascii", "strict") or "0", 8) - except ValueError: - raise InvalidHeaderError("invalid header") - else: - n = 0 - for i in range(len(s) - 1): - n <<= 8 - n += ord(s[i + 1]) - return n - -def itn(n, digits=8, format=DEFAULT_FORMAT): - """Convert a python number to a number field. - """ - # POSIX 1003.1-1988 requires numbers to be encoded as a string of - # octal digits followed by a null-byte, this allows values up to - # (8**(digits-1))-1. GNU tar allows storing numbers greater than - # that if necessary. A leading 0o200 byte indicates this particular - # encoding, the following digits-1 bytes are a big-endian - # representation. This allows values up to (256**(digits-1))-1. - if 0 <= n < 8 ** (digits - 1): - s = ("%0*o" % (digits - 1, n)).encode("ascii") + NUL - else: - if format != GNU_FORMAT or n >= 256 ** (digits - 1): - raise ValueError("overflow in number field") - - if n < 0: - # XXX We mimic GNU tar's behaviour with negative numbers, - # this could raise OverflowError. - n = struct.unpack("L", struct.pack("l", n))[0] - - s = bytearray() - for i in range(digits - 1): - s.insert(0, n & 0o377) - n >>= 8 - s.insert(0, 0o200) - return s - -def calc_chksums(buf): - """Calculate the checksum for a member's header by summing up all - characters except for the chksum field which is treated as if - it was filled with spaces. According to the GNU tar sources, - some tars (Sun and NeXT) calculate chksum with signed char, - which will be different if there are chars in the buffer with - the high bit set. So we calculate two checksums, unsigned and - signed. - """ - unsigned_chksum = 256 + sum(struct.unpack("148B", buf[:148]) + struct.unpack("356B", buf[156:512])) - signed_chksum = 256 + sum(struct.unpack("148b", buf[:148]) + struct.unpack("356b", buf[156:512])) - return unsigned_chksum, signed_chksum - -def copyfileobj(src, dst, length=None): - """Copy length bytes from fileobj src to fileobj dst. - If length is None, copy the entire content. - """ - if length == 0: - return - if length is None: - while True: - buf = src.read(16*1024) - if not buf: - break - dst.write(buf) - return - - BUFSIZE = 16 * 1024 - blocks, remainder = divmod(length, BUFSIZE) - for b in range(blocks): - buf = src.read(BUFSIZE) - if len(buf) < BUFSIZE: - raise IOError("end of file reached") - dst.write(buf) - - if remainder != 0: - buf = src.read(remainder) - if len(buf) < remainder: - raise IOError("end of file reached") - dst.write(buf) - return - -filemode_table = ( - ((S_IFLNK, "l"), - (S_IFREG, "-"), - (S_IFBLK, "b"), - (S_IFDIR, "d"), - (S_IFCHR, "c"), - (S_IFIFO, "p")), - - ((TUREAD, "r"),), - ((TUWRITE, "w"),), - ((TUEXEC|TSUID, "s"), - (TSUID, "S"), - (TUEXEC, "x")), - - ((TGREAD, "r"),), - ((TGWRITE, "w"),), - ((TGEXEC|TSGID, "s"), - (TSGID, "S"), - (TGEXEC, "x")), - - ((TOREAD, "r"),), - ((TOWRITE, "w"),), - ((TOEXEC|TSVTX, "t"), - (TSVTX, "T"), - (TOEXEC, "x")) -) - -def filemode(mode): - """Convert a file's mode to a string of the form - -rwxrwxrwx. - Used by TarFile.list() - """ - perm = [] - for table in filemode_table: - for bit, char in table: - if mode & bit == bit: - perm.append(char) - break - else: - perm.append("-") - return "".join(perm) - -class TarError(Exception): - """Base exception.""" - pass -class ExtractError(TarError): - """General exception for extract errors.""" - pass -class ReadError(TarError): - """Exception for unreadble tar archives.""" - pass -class CompressionError(TarError): - """Exception for unavailable compression methods.""" - pass -class StreamError(TarError): - """Exception for unsupported operations on stream-like TarFiles.""" - pass -class HeaderError(TarError): - """Base exception for header errors.""" - pass -class EmptyHeaderError(HeaderError): - """Exception for empty headers.""" - pass -class TruncatedHeaderError(HeaderError): - """Exception for truncated headers.""" - pass -class EOFHeaderError(HeaderError): - """Exception for end of file headers.""" - pass -class InvalidHeaderError(HeaderError): - """Exception for invalid headers.""" - pass -class SubsequentHeaderError(HeaderError): - """Exception for missing and invalid extended headers.""" - pass - -#--------------------------- -# internal stream interface -#--------------------------- -class _LowLevelFile(object): - """Low-level file object. Supports reading and writing. - It is used instead of a regular file object for streaming - access. - """ - - def __init__(self, name, mode): - mode = { - "r": os.O_RDONLY, - "w": os.O_WRONLY | os.O_CREAT | os.O_TRUNC, - }[mode] - if hasattr(os, "O_BINARY"): - mode |= os.O_BINARY - self.fd = os.open(name, mode, 0o666) - - def close(self): - os.close(self.fd) - - def read(self, size): - return os.read(self.fd, size) - - def write(self, s): - os.write(self.fd, s) - -class _Stream(object): - """Class that serves as an adapter between TarFile and - a stream-like object. The stream-like object only - needs to have a read() or write() method and is accessed - blockwise. Use of gzip or bzip2 compression is possible. - A stream-like object could be for example: sys.stdin, - sys.stdout, a socket, a tape device etc. - - _Stream is intended to be used only internally. - """ - - def __init__(self, name, mode, comptype, fileobj, bufsize): - """Construct a _Stream object. - """ - self._extfileobj = True - if fileobj is None: - fileobj = _LowLevelFile(name, mode) - self._extfileobj = False - - if comptype == '*': - # Enable transparent compression detection for the - # stream interface - fileobj = _StreamProxy(fileobj) - comptype = fileobj.getcomptype() - - self.name = name or "" - self.mode = mode - self.comptype = comptype - self.fileobj = fileobj - self.bufsize = bufsize - self.buf = b"" - self.pos = 0 - self.closed = False - - try: - if comptype == "gz": - try: - import zlib - except ImportError: - raise CompressionError("zlib module is not available") - self.zlib = zlib - self.crc = zlib.crc32(b"") - if mode == "r": - self._init_read_gz() - else: - self._init_write_gz() - - if comptype == "bz2": - try: - import bz2 - except ImportError: - raise CompressionError("bz2 module is not available") - if mode == "r": - self.dbuf = b"" - self.cmp = bz2.BZ2Decompressor() - else: - self.cmp = bz2.BZ2Compressor() - except: - if not self._extfileobj: - self.fileobj.close() - self.closed = True - raise - - def __del__(self): - if hasattr(self, "closed") and not self.closed: - self.close() - - def _init_write_gz(self): - """Initialize for writing with gzip compression. - """ - self.cmp = self.zlib.compressobj(9, self.zlib.DEFLATED, - -self.zlib.MAX_WBITS, - self.zlib.DEF_MEM_LEVEL, - 0) - timestamp = struct.pack(" self.bufsize: - self.fileobj.write(self.buf[:self.bufsize]) - self.buf = self.buf[self.bufsize:] - - def close(self): - """Close the _Stream object. No operation should be - done on it afterwards. - """ - if self.closed: - return - - if self.mode == "w" and self.comptype != "tar": - self.buf += self.cmp.flush() - - if self.mode == "w" and self.buf: - self.fileobj.write(self.buf) - self.buf = b"" - if self.comptype == "gz": - # The native zlib crc is an unsigned 32-bit integer, but - # the Python wrapper implicitly casts that to a signed C - # long. So, on a 32-bit box self.crc may "look negative", - # while the same crc on a 64-bit box may "look positive". - # To avoid irksome warnings from the `struct` module, force - # it to look positive on all boxes. - self.fileobj.write(struct.pack("= 0: - blocks, remainder = divmod(pos - self.pos, self.bufsize) - for i in range(blocks): - self.read(self.bufsize) - self.read(remainder) - else: - raise StreamError("seeking backwards is not allowed") - return self.pos - - def read(self, size=None): - """Return the next size number of bytes from the stream. - If size is not defined, return all bytes of the stream - up to EOF. - """ - if size is None: - t = [] - while True: - buf = self._read(self.bufsize) - if not buf: - break - t.append(buf) - buf = "".join(t) - else: - buf = self._read(size) - self.pos += len(buf) - return buf - - def _read(self, size): - """Return size bytes from the stream. - """ - if self.comptype == "tar": - return self.__read(size) - - c = len(self.dbuf) - while c < size: - buf = self.__read(self.bufsize) - if not buf: - break - try: - buf = self.cmp.decompress(buf) - except IOError: - raise ReadError("invalid compressed data") - self.dbuf += buf - c += len(buf) - buf = self.dbuf[:size] - self.dbuf = self.dbuf[size:] - return buf - - def __read(self, size): - """Return size bytes from stream. If internal buffer is empty, - read another block from the stream. - """ - c = len(self.buf) - while c < size: - buf = self.fileobj.read(self.bufsize) - if not buf: - break - self.buf += buf - c += len(buf) - buf = self.buf[:size] - self.buf = self.buf[size:] - return buf -# class _Stream - -class _StreamProxy(object): - """Small proxy class that enables transparent compression - detection for the Stream interface (mode 'r|*'). - """ - - def __init__(self, fileobj): - self.fileobj = fileobj - self.buf = self.fileobj.read(BLOCKSIZE) - - def read(self, size): - self.read = self.fileobj.read - return self.buf - - def getcomptype(self): - if self.buf.startswith(b"\037\213\010"): - return "gz" - if self.buf.startswith(b"BZh91"): - return "bz2" - return "tar" - - def close(self): - self.fileobj.close() -# class StreamProxy - -class _BZ2Proxy(object): - """Small proxy class that enables external file object - support for "r:bz2" and "w:bz2" modes. This is actually - a workaround for a limitation in bz2 module's BZ2File - class which (unlike gzip.GzipFile) has no support for - a file object argument. - """ - - blocksize = 16 * 1024 - - def __init__(self, fileobj, mode): - self.fileobj = fileobj - self.mode = mode - self.name = getattr(self.fileobj, "name", None) - self.init() - - def init(self): - import bz2 - self.pos = 0 - if self.mode == "r": - self.bz2obj = bz2.BZ2Decompressor() - self.fileobj.seek(0) - self.buf = b"" - else: - self.bz2obj = bz2.BZ2Compressor() - - def read(self, size): - x = len(self.buf) - while x < size: - raw = self.fileobj.read(self.blocksize) - if not raw: - break - data = self.bz2obj.decompress(raw) - self.buf += data - x += len(data) - - buf = self.buf[:size] - self.buf = self.buf[size:] - self.pos += len(buf) - return buf - - def seek(self, pos): - if pos < self.pos: - self.init() - self.read(pos - self.pos) - - def tell(self): - return self.pos - - def write(self, data): - self.pos += len(data) - raw = self.bz2obj.compress(data) - self.fileobj.write(raw) - - def close(self): - if self.mode == "w": - raw = self.bz2obj.flush() - self.fileobj.write(raw) -# class _BZ2Proxy - -#------------------------ -# Extraction file object -#------------------------ -class _FileInFile(object): - """A thin wrapper around an existing file object that - provides a part of its data as an individual file - object. - """ - - def __init__(self, fileobj, offset, size, blockinfo=None): - self.fileobj = fileobj - self.offset = offset - self.size = size - self.position = 0 - - if blockinfo is None: - blockinfo = [(0, size)] - - # Construct a map with data and zero blocks. - self.map_index = 0 - self.map = [] - lastpos = 0 - realpos = self.offset - for offset, size in blockinfo: - if offset > lastpos: - self.map.append((False, lastpos, offset, None)) - self.map.append((True, offset, offset + size, realpos)) - realpos += size - lastpos = offset + size - if lastpos < self.size: - self.map.append((False, lastpos, self.size, None)) - - def seekable(self): - if not hasattr(self.fileobj, "seekable"): - # XXX gzip.GzipFile and bz2.BZ2File - return True - return self.fileobj.seekable() - - def tell(self): - """Return the current file position. - """ - return self.position - - def seek(self, position): - """Seek to a position in the file. - """ - self.position = position - - def read(self, size=None): - """Read data from the file. - """ - if size is None: - size = self.size - self.position - else: - size = min(size, self.size - self.position) - - buf = b"" - while size > 0: - while True: - data, start, stop, offset = self.map[self.map_index] - if start <= self.position < stop: - break - else: - self.map_index += 1 - if self.map_index == len(self.map): - self.map_index = 0 - length = min(size, stop - self.position) - if data: - self.fileobj.seek(offset + (self.position - start)) - buf += self.fileobj.read(length) - else: - buf += NUL * length - size -= length - self.position += length - return buf -#class _FileInFile - - -class ExFileObject(object): - """File-like object for reading an archive member. - Is returned by TarFile.extractfile(). - """ - blocksize = 1024 - - def __init__(self, tarfile, tarinfo): - self.fileobj = _FileInFile(tarfile.fileobj, - tarinfo.offset_data, - tarinfo.size, - tarinfo.sparse) - self.name = tarinfo.name - self.mode = "r" - self.closed = False - self.size = tarinfo.size - - self.position = 0 - self.buffer = b"" - - def readable(self): - return True - - def writable(self): - return False - - def seekable(self): - return self.fileobj.seekable() - - def read(self, size=None): - """Read at most size bytes from the file. If size is not - present or None, read all data until EOF is reached. - """ - if self.closed: - raise ValueError("I/O operation on closed file") - - buf = b"" - if self.buffer: - if size is None: - buf = self.buffer - self.buffer = b"" - else: - buf = self.buffer[:size] - self.buffer = self.buffer[size:] - - if size is None: - buf += self.fileobj.read() - else: - buf += self.fileobj.read(size - len(buf)) - - self.position += len(buf) - return buf - - # XXX TextIOWrapper uses the read1() method. - read1 = read - - def readline(self, size=-1): - """Read one entire line from the file. If size is present - and non-negative, return a string with at most that - size, which may be an incomplete line. - """ - if self.closed: - raise ValueError("I/O operation on closed file") - - pos = self.buffer.find(b"\n") + 1 - if pos == 0: - # no newline found. - while True: - buf = self.fileobj.read(self.blocksize) - self.buffer += buf - if not buf or b"\n" in buf: - pos = self.buffer.find(b"\n") + 1 - if pos == 0: - # no newline found. - pos = len(self.buffer) - break - - if size != -1: - pos = min(size, pos) - - buf = self.buffer[:pos] - self.buffer = self.buffer[pos:] - self.position += len(buf) - return buf - - def readlines(self): - """Return a list with all remaining lines. - """ - result = [] - while True: - line = self.readline() - if not line: break - result.append(line) - return result - - def tell(self): - """Return the current file position. - """ - if self.closed: - raise ValueError("I/O operation on closed file") - - return self.position - - def seek(self, pos, whence=os.SEEK_SET): - """Seek to a position in the file. - """ - if self.closed: - raise ValueError("I/O operation on closed file") - - if whence == os.SEEK_SET: - self.position = min(max(pos, 0), self.size) - elif whence == os.SEEK_CUR: - if pos < 0: - self.position = max(self.position + pos, 0) - else: - self.position = min(self.position + pos, self.size) - elif whence == os.SEEK_END: - self.position = max(min(self.size + pos, self.size), 0) - else: - raise ValueError("Invalid argument") - - self.buffer = b"" - self.fileobj.seek(self.position) - - def close(self): - """Close the file object. - """ - self.closed = True - - def __iter__(self): - """Get an iterator over the file's lines. - """ - while True: - line = self.readline() - if not line: - break - yield line -#class ExFileObject - -#------------------ -# Exported Classes -#------------------ -class TarInfo(object): - """Informational class which holds the details about an - archive member given by a tar header block. - TarInfo objects are returned by TarFile.getmember(), - TarFile.getmembers() and TarFile.gettarinfo() and are - usually created internally. - """ - - __slots__ = ("name", "mode", "uid", "gid", "size", "mtime", - "chksum", "type", "linkname", "uname", "gname", - "devmajor", "devminor", - "offset", "offset_data", "pax_headers", "sparse", - "tarfile", "_sparse_structs", "_link_target") - - def __init__(self, name=""): - """Construct a TarInfo object. name is the optional name - of the member. - """ - self.name = name # member name - self.mode = 0o644 # file permissions - self.uid = 0 # user id - self.gid = 0 # group id - self.size = 0 # file size - self.mtime = 0 # modification time - self.chksum = 0 # header checksum - self.type = REGTYPE # member type - self.linkname = "" # link name - self.uname = "" # user name - self.gname = "" # group name - self.devmajor = 0 # device major number - self.devminor = 0 # device minor number - - self.offset = 0 # the tar header starts here - self.offset_data = 0 # the file's data starts here - - self.sparse = None # sparse member information - self.pax_headers = {} # pax header information - - # In pax headers the "name" and "linkname" field are called - # "path" and "linkpath". - def _getpath(self): - return self.name - def _setpath(self, name): - self.name = name - path = property(_getpath, _setpath) - - def _getlinkpath(self): - return self.linkname - def _setlinkpath(self, linkname): - self.linkname = linkname - linkpath = property(_getlinkpath, _setlinkpath) - - def __repr__(self): - return "<%s %r at %#x>" % (self.__class__.__name__,self.name,id(self)) - - def get_info(self): - """Return the TarInfo's attributes as a dictionary. - """ - info = { - "name": self.name, - "mode": self.mode & 0o7777, - "uid": self.uid, - "gid": self.gid, - "size": self.size, - "mtime": self.mtime, - "chksum": self.chksum, - "type": self.type, - "linkname": self.linkname, - "uname": self.uname, - "gname": self.gname, - "devmajor": self.devmajor, - "devminor": self.devminor - } - - if info["type"] == DIRTYPE and not info["name"].endswith("/"): - info["name"] += "/" - - return info - - def tobuf(self, format=DEFAULT_FORMAT, encoding=ENCODING, errors="surrogateescape"): - """Return a tar header as a string of 512 byte blocks. - """ - info = self.get_info() - - if format == USTAR_FORMAT: - return self.create_ustar_header(info, encoding, errors) - elif format == GNU_FORMAT: - return self.create_gnu_header(info, encoding, errors) - elif format == PAX_FORMAT: - return self.create_pax_header(info, encoding) - else: - raise ValueError("invalid format") - - def create_ustar_header(self, info, encoding, errors): - """Return the object as a ustar header block. - """ - info["magic"] = POSIX_MAGIC - - if len(info["linkname"]) > LENGTH_LINK: - raise ValueError("linkname is too long") - - if len(info["name"]) > LENGTH_NAME: - info["prefix"], info["name"] = self._posix_split_name(info["name"]) - - return self._create_header(info, USTAR_FORMAT, encoding, errors) - - def create_gnu_header(self, info, encoding, errors): - """Return the object as a GNU header block sequence. - """ - info["magic"] = GNU_MAGIC - - buf = b"" - if len(info["linkname"]) > LENGTH_LINK: - buf += self._create_gnu_long_header(info["linkname"], GNUTYPE_LONGLINK, encoding, errors) - - if len(info["name"]) > LENGTH_NAME: - buf += self._create_gnu_long_header(info["name"], GNUTYPE_LONGNAME, encoding, errors) - - return buf + self._create_header(info, GNU_FORMAT, encoding, errors) - - def create_pax_header(self, info, encoding): - """Return the object as a ustar header block. If it cannot be - represented this way, prepend a pax extended header sequence - with supplement information. - """ - info["magic"] = POSIX_MAGIC - pax_headers = self.pax_headers.copy() - - # Test string fields for values that exceed the field length or cannot - # be represented in ASCII encoding. - for name, hname, length in ( - ("name", "path", LENGTH_NAME), ("linkname", "linkpath", LENGTH_LINK), - ("uname", "uname", 32), ("gname", "gname", 32)): - - if hname in pax_headers: - # The pax header has priority. - continue - - # Try to encode the string as ASCII. - try: - info[name].encode("ascii", "strict") - except UnicodeEncodeError: - pax_headers[hname] = info[name] - continue - - if len(info[name]) > length: - pax_headers[hname] = info[name] - - # Test number fields for values that exceed the field limit or values - # that like to be stored as float. - for name, digits in (("uid", 8), ("gid", 8), ("size", 12), ("mtime", 12)): - if name in pax_headers: - # The pax header has priority. Avoid overflow. - info[name] = 0 - continue - - val = info[name] - if not 0 <= val < 8 ** (digits - 1) or isinstance(val, float): - pax_headers[name] = str(val) - info[name] = 0 - - # Create a pax extended header if necessary. - if pax_headers: - buf = self._create_pax_generic_header(pax_headers, XHDTYPE, encoding) - else: - buf = b"" - - return buf + self._create_header(info, USTAR_FORMAT, "ascii", "replace") - - @classmethod - def create_pax_global_header(cls, pax_headers): - """Return the object as a pax global header block sequence. - """ - return cls._create_pax_generic_header(pax_headers, XGLTYPE, "utf8") - - def _posix_split_name(self, name): - """Split a name longer than 100 chars into a prefix - and a name part. - """ - prefix = name[:LENGTH_PREFIX + 1] - while prefix and prefix[-1] != "/": - prefix = prefix[:-1] - - name = name[len(prefix):] - prefix = prefix[:-1] - - if not prefix or len(name) > LENGTH_NAME: - raise ValueError("name is too long") - return prefix, name - - @staticmethod - def _create_header(info, format, encoding, errors): - """Return a header block. info is a dictionary with file - information, format must be one of the *_FORMAT constants. - """ - parts = [ - stn(info.get("name", ""), 100, encoding, errors), - itn(info.get("mode", 0) & 0o7777, 8, format), - itn(info.get("uid", 0), 8, format), - itn(info.get("gid", 0), 8, format), - itn(info.get("size", 0), 12, format), - itn(info.get("mtime", 0), 12, format), - b" ", # checksum field - info.get("type", REGTYPE), - stn(info.get("linkname", ""), 100, encoding, errors), - info.get("magic", POSIX_MAGIC), - stn(info.get("uname", ""), 32, encoding, errors), - stn(info.get("gname", ""), 32, encoding, errors), - itn(info.get("devmajor", 0), 8, format), - itn(info.get("devminor", 0), 8, format), - stn(info.get("prefix", ""), 155, encoding, errors) - ] - - buf = struct.pack("%ds" % BLOCKSIZE, b"".join(parts)) - chksum = calc_chksums(buf[-BLOCKSIZE:])[0] - buf = buf[:-364] + ("%06o\0" % chksum).encode("ascii") + buf[-357:] - return buf - - @staticmethod - def _create_payload(payload): - """Return the string payload filled with zero bytes - up to the next 512 byte border. - """ - blocks, remainder = divmod(len(payload), BLOCKSIZE) - if remainder > 0: - payload += (BLOCKSIZE - remainder) * NUL - return payload - - @classmethod - def _create_gnu_long_header(cls, name, type, encoding, errors): - """Return a GNUTYPE_LONGNAME or GNUTYPE_LONGLINK sequence - for name. - """ - name = name.encode(encoding, errors) + NUL - - info = {} - info["name"] = "././@LongLink" - info["type"] = type - info["size"] = len(name) - info["magic"] = GNU_MAGIC - - # create extended header + name blocks. - return cls._create_header(info, USTAR_FORMAT, encoding, errors) + \ - cls._create_payload(name) - - @classmethod - def _create_pax_generic_header(cls, pax_headers, type, encoding): - """Return a POSIX.1-2008 extended or global header sequence - that contains a list of keyword, value pairs. The values - must be strings. - """ - # Check if one of the fields contains surrogate characters and thereby - # forces hdrcharset=BINARY, see _proc_pax() for more information. - binary = False - for keyword, value in pax_headers.items(): - try: - value.encode("utf8", "strict") - except UnicodeEncodeError: - binary = True - break - - records = b"" - if binary: - # Put the hdrcharset field at the beginning of the header. - records += b"21 hdrcharset=BINARY\n" - - for keyword, value in pax_headers.items(): - keyword = keyword.encode("utf8") - if binary: - # Try to restore the original byte representation of `value'. - # Needless to say, that the encoding must match the string. - value = value.encode(encoding, "surrogateescape") - else: - value = value.encode("utf8") - - l = len(keyword) + len(value) + 3 # ' ' + '=' + '\n' - n = p = 0 - while True: - n = l + len(str(p)) - if n == p: - break - p = n - records += bytes(str(p), "ascii") + b" " + keyword + b"=" + value + b"\n" - - # We use a hardcoded "././@PaxHeader" name like star does - # instead of the one that POSIX recommends. - info = {} - info["name"] = "././@PaxHeader" - info["type"] = type - info["size"] = len(records) - info["magic"] = POSIX_MAGIC - - # Create pax header + record blocks. - return cls._create_header(info, USTAR_FORMAT, "ascii", "replace") + \ - cls._create_payload(records) - - @classmethod - def frombuf(cls, buf, encoding, errors): - """Construct a TarInfo object from a 512 byte bytes object. - """ - if len(buf) == 0: - raise EmptyHeaderError("empty header") - if len(buf) != BLOCKSIZE: - raise TruncatedHeaderError("truncated header") - if buf.count(NUL) == BLOCKSIZE: - raise EOFHeaderError("end of file header") - - chksum = nti(buf[148:156]) - if chksum not in calc_chksums(buf): - raise InvalidHeaderError("bad checksum") - - obj = cls() - obj.name = nts(buf[0:100], encoding, errors) - obj.mode = nti(buf[100:108]) - obj.uid = nti(buf[108:116]) - obj.gid = nti(buf[116:124]) - obj.size = nti(buf[124:136]) - obj.mtime = nti(buf[136:148]) - obj.chksum = chksum - obj.type = buf[156:157] - obj.linkname = nts(buf[157:257], encoding, errors) - obj.uname = nts(buf[265:297], encoding, errors) - obj.gname = nts(buf[297:329], encoding, errors) - obj.devmajor = nti(buf[329:337]) - obj.devminor = nti(buf[337:345]) - prefix = nts(buf[345:500], encoding, errors) - - # Old V7 tar format represents a directory as a regular - # file with a trailing slash. - if obj.type == AREGTYPE and obj.name.endswith("/"): - obj.type = DIRTYPE - - # The old GNU sparse format occupies some of the unused - # space in the buffer for up to 4 sparse structures. - # Save the them for later processing in _proc_sparse(). - if obj.type == GNUTYPE_SPARSE: - pos = 386 - structs = [] - for i in range(4): - try: - offset = nti(buf[pos:pos + 12]) - numbytes = nti(buf[pos + 12:pos + 24]) - except ValueError: - break - structs.append((offset, numbytes)) - pos += 24 - isextended = bool(buf[482]) - origsize = nti(buf[483:495]) - obj._sparse_structs = (structs, isextended, origsize) - - # Remove redundant slashes from directories. - if obj.isdir(): - obj.name = obj.name.rstrip("/") - - # Reconstruct a ustar longname. - if prefix and obj.type not in GNU_TYPES: - obj.name = prefix + "/" + obj.name - return obj - - @classmethod - def fromtarfile(cls, tarfile): - """Return the next TarInfo object from TarFile object - tarfile. - """ - buf = tarfile.fileobj.read(BLOCKSIZE) - obj = cls.frombuf(buf, tarfile.encoding, tarfile.errors) - obj.offset = tarfile.fileobj.tell() - BLOCKSIZE - return obj._proc_member(tarfile) - - #-------------------------------------------------------------------------- - # The following are methods that are called depending on the type of a - # member. The entry point is _proc_member() which can be overridden in a - # subclass to add custom _proc_*() methods. A _proc_*() method MUST - # implement the following - # operations: - # 1. Set self.offset_data to the position where the data blocks begin, - # if there is data that follows. - # 2. Set tarfile.offset to the position where the next member's header will - # begin. - # 3. Return self or another valid TarInfo object. - def _proc_member(self, tarfile): - """Choose the right processing method depending on - the type and call it. - """ - if self.type in (GNUTYPE_LONGNAME, GNUTYPE_LONGLINK): - return self._proc_gnulong(tarfile) - elif self.type == GNUTYPE_SPARSE: - return self._proc_sparse(tarfile) - elif self.type in (XHDTYPE, XGLTYPE, SOLARIS_XHDTYPE): - return self._proc_pax(tarfile) - else: - return self._proc_builtin(tarfile) - - def _proc_builtin(self, tarfile): - """Process a builtin type or an unknown type which - will be treated as a regular file. - """ - self.offset_data = tarfile.fileobj.tell() - offset = self.offset_data - if self.isreg() or self.type not in SUPPORTED_TYPES: - # Skip the following data blocks. - offset += self._block(self.size) - tarfile.offset = offset - - # Patch the TarInfo object with saved global - # header information. - self._apply_pax_info(tarfile.pax_headers, tarfile.encoding, tarfile.errors) - - return self - - def _proc_gnulong(self, tarfile): - """Process the blocks that hold a GNU longname - or longlink member. - """ - buf = tarfile.fileobj.read(self._block(self.size)) - - # Fetch the next header and process it. - try: - next = self.fromtarfile(tarfile) - except HeaderError: - raise SubsequentHeaderError("missing or bad subsequent header") - - # Patch the TarInfo object from the next header with - # the longname information. - next.offset = self.offset - if self.type == GNUTYPE_LONGNAME: - next.name = nts(buf, tarfile.encoding, tarfile.errors) - elif self.type == GNUTYPE_LONGLINK: - next.linkname = nts(buf, tarfile.encoding, tarfile.errors) - - return next - - def _proc_sparse(self, tarfile): - """Process a GNU sparse header plus extra headers. - """ - # We already collected some sparse structures in frombuf(). - structs, isextended, origsize = self._sparse_structs - del self._sparse_structs - - # Collect sparse structures from extended header blocks. - while isextended: - buf = tarfile.fileobj.read(BLOCKSIZE) - pos = 0 - for i in range(21): - try: - offset = nti(buf[pos:pos + 12]) - numbytes = nti(buf[pos + 12:pos + 24]) - except ValueError: - break - if offset and numbytes: - structs.append((offset, numbytes)) - pos += 24 - isextended = bool(buf[504]) - self.sparse = structs - - self.offset_data = tarfile.fileobj.tell() - tarfile.offset = self.offset_data + self._block(self.size) - self.size = origsize - return self - - def _proc_pax(self, tarfile): - """Process an extended or global header as described in - POSIX.1-2008. - """ - # Read the header information. - buf = tarfile.fileobj.read(self._block(self.size)) - - # A pax header stores supplemental information for either - # the following file (extended) or all following files - # (global). - if self.type == XGLTYPE: - pax_headers = tarfile.pax_headers - else: - pax_headers = tarfile.pax_headers.copy() - - # Check if the pax header contains a hdrcharset field. This tells us - # the encoding of the path, linkpath, uname and gname fields. Normally, - # these fields are UTF-8 encoded but since POSIX.1-2008 tar - # implementations are allowed to store them as raw binary strings if - # the translation to UTF-8 fails. - match = re.search(br"\d+ hdrcharset=([^\n]+)\n", buf) - if match is not None: - pax_headers["hdrcharset"] = match.group(1).decode("utf8") - - # For the time being, we don't care about anything other than "BINARY". - # The only other value that is currently allowed by the standard is - # "ISO-IR 10646 2000 UTF-8" in other words UTF-8. - hdrcharset = pax_headers.get("hdrcharset") - if hdrcharset == "BINARY": - encoding = tarfile.encoding - else: - encoding = "utf8" - - # Parse pax header information. A record looks like that: - # "%d %s=%s\n" % (length, keyword, value). length is the size - # of the complete record including the length field itself and - # the newline. keyword and value are both UTF-8 encoded strings. - regex = re.compile(br"(\d+) ([^=]+)=") - pos = 0 - while True: - match = regex.match(buf, pos) - if not match: - break - - length, keyword = match.groups() - length = int(length) - value = buf[match.end(2) + 1:match.start(1) + length - 1] - - # Normally, we could just use "utf8" as the encoding and "strict" - # as the error handler, but we better not take the risk. For - # example, GNU tar <= 1.23 is known to store filenames it cannot - # translate to UTF-8 as raw strings (unfortunately without a - # hdrcharset=BINARY header). - # We first try the strict standard encoding, and if that fails we - # fall back on the user's encoding and error handler. - keyword = self._decode_pax_field(keyword, "utf8", "utf8", - tarfile.errors) - if keyword in PAX_NAME_FIELDS: - value = self._decode_pax_field(value, encoding, tarfile.encoding, - tarfile.errors) - else: - value = self._decode_pax_field(value, "utf8", "utf8", - tarfile.errors) - - pax_headers[keyword] = value - pos += length - - # Fetch the next header. - try: - next = self.fromtarfile(tarfile) - except HeaderError: - raise SubsequentHeaderError("missing or bad subsequent header") - - # Process GNU sparse information. - if "GNU.sparse.map" in pax_headers: - # GNU extended sparse format version 0.1. - self._proc_gnusparse_01(next, pax_headers) - - elif "GNU.sparse.size" in pax_headers: - # GNU extended sparse format version 0.0. - self._proc_gnusparse_00(next, pax_headers, buf) - - elif pax_headers.get("GNU.sparse.major") == "1" and pax_headers.get("GNU.sparse.minor") == "0": - # GNU extended sparse format version 1.0. - self._proc_gnusparse_10(next, pax_headers, tarfile) - - if self.type in (XHDTYPE, SOLARIS_XHDTYPE): - # Patch the TarInfo object with the extended header info. - next._apply_pax_info(pax_headers, tarfile.encoding, tarfile.errors) - next.offset = self.offset - - if "size" in pax_headers: - # If the extended header replaces the size field, - # we need to recalculate the offset where the next - # header starts. - offset = next.offset_data - if next.isreg() or next.type not in SUPPORTED_TYPES: - offset += next._block(next.size) - tarfile.offset = offset - - return next - - def _proc_gnusparse_00(self, next, pax_headers, buf): - """Process a GNU tar extended sparse header, version 0.0. - """ - offsets = [] - for match in re.finditer(br"\d+ GNU.sparse.offset=(\d+)\n", buf): - offsets.append(int(match.group(1))) - numbytes = [] - for match in re.finditer(br"\d+ GNU.sparse.numbytes=(\d+)\n", buf): - numbytes.append(int(match.group(1))) - next.sparse = list(zip(offsets, numbytes)) - - def _proc_gnusparse_01(self, next, pax_headers): - """Process a GNU tar extended sparse header, version 0.1. - """ - sparse = [int(x) for x in pax_headers["GNU.sparse.map"].split(",")] - next.sparse = list(zip(sparse[::2], sparse[1::2])) - - def _proc_gnusparse_10(self, next, pax_headers, tarfile): - """Process a GNU tar extended sparse header, version 1.0. - """ - fields = None - sparse = [] - buf = tarfile.fileobj.read(BLOCKSIZE) - fields, buf = buf.split(b"\n", 1) - fields = int(fields) - while len(sparse) < fields * 2: - if b"\n" not in buf: - buf += tarfile.fileobj.read(BLOCKSIZE) - number, buf = buf.split(b"\n", 1) - sparse.append(int(number)) - next.offset_data = tarfile.fileobj.tell() - next.sparse = list(zip(sparse[::2], sparse[1::2])) - - def _apply_pax_info(self, pax_headers, encoding, errors): - """Replace fields with supplemental information from a previous - pax extended or global header. - """ - for keyword, value in pax_headers.items(): - if keyword == "GNU.sparse.name": - setattr(self, "path", value) - elif keyword == "GNU.sparse.size": - setattr(self, "size", int(value)) - elif keyword == "GNU.sparse.realsize": - setattr(self, "size", int(value)) - elif keyword in PAX_FIELDS: - if keyword in PAX_NUMBER_FIELDS: - try: - value = PAX_NUMBER_FIELDS[keyword](value) - except ValueError: - value = 0 - if keyword == "path": - value = value.rstrip("/") - setattr(self, keyword, value) - - self.pax_headers = pax_headers.copy() - - def _decode_pax_field(self, value, encoding, fallback_encoding, fallback_errors): - """Decode a single field from a pax record. - """ - try: - return value.decode(encoding, "strict") - except UnicodeDecodeError: - return value.decode(fallback_encoding, fallback_errors) - - def _block(self, count): - """Round up a byte count by BLOCKSIZE and return it, - e.g. _block(834) => 1024. - """ - blocks, remainder = divmod(count, BLOCKSIZE) - if remainder: - blocks += 1 - return blocks * BLOCKSIZE - - def isreg(self): - return self.type in REGULAR_TYPES - def isfile(self): - return self.isreg() - def isdir(self): - return self.type == DIRTYPE - def issym(self): - return self.type == SYMTYPE - def islnk(self): - return self.type == LNKTYPE - def ischr(self): - return self.type == CHRTYPE - def isblk(self): - return self.type == BLKTYPE - def isfifo(self): - return self.type == FIFOTYPE - def issparse(self): - return self.sparse is not None - def isdev(self): - return self.type in (CHRTYPE, BLKTYPE, FIFOTYPE) -# class TarInfo - -class TarFile(object): - """The TarFile Class provides an interface to tar archives. - """ - - debug = 0 # May be set from 0 (no msgs) to 3 (all msgs) - - dereference = False # If true, add content of linked file to the - # tar file, else the link. - - ignore_zeros = False # If true, skips empty or invalid blocks and - # continues processing. - - errorlevel = 1 # If 0, fatal errors only appear in debug - # messages (if debug >= 0). If > 0, errors - # are passed to the caller as exceptions. - - format = DEFAULT_FORMAT # The format to use when creating an archive. - - encoding = ENCODING # Encoding for 8-bit character strings. - - errors = None # Error handler for unicode conversion. - - tarinfo = TarInfo # The default TarInfo class to use. - - fileobject = ExFileObject # The default ExFileObject class to use. - - def __init__(self, name=None, mode="r", fileobj=None, format=None, - tarinfo=None, dereference=None, ignore_zeros=None, encoding=None, - errors="surrogateescape", pax_headers=None, debug=None, errorlevel=None): - """Open an (uncompressed) tar archive `name'. `mode' is either 'r' to - read from an existing archive, 'a' to append data to an existing - file or 'w' to create a new file overwriting an existing one. `mode' - defaults to 'r'. - If `fileobj' is given, it is used for reading or writing data. If it - can be determined, `mode' is overridden by `fileobj's mode. - `fileobj' is not closed, when TarFile is closed. - """ - if len(mode) > 1 or mode not in "raw": - raise ValueError("mode must be 'r', 'a' or 'w'") - self.mode = mode - self._mode = {"r": "rb", "a": "r+b", "w": "wb"}[mode] - - if not fileobj: - if self.mode == "a" and not os.path.exists(name): - # Create nonexistent files in append mode. - self.mode = "w" - self._mode = "wb" - fileobj = bltn_open(name, self._mode) - self._extfileobj = False - else: - if name is None and hasattr(fileobj, "name"): - name = fileobj.name - if hasattr(fileobj, "mode"): - self._mode = fileobj.mode - self._extfileobj = True - self.name = os.path.abspath(name) if name else None - self.fileobj = fileobj - - # Init attributes. - if format is not None: - self.format = format - if tarinfo is not None: - self.tarinfo = tarinfo - if dereference is not None: - self.dereference = dereference - if ignore_zeros is not None: - self.ignore_zeros = ignore_zeros - if encoding is not None: - self.encoding = encoding - self.errors = errors - - if pax_headers is not None and self.format == PAX_FORMAT: - self.pax_headers = pax_headers - else: - self.pax_headers = {} - - if debug is not None: - self.debug = debug - if errorlevel is not None: - self.errorlevel = errorlevel - - # Init datastructures. - self.closed = False - self.members = [] # list of members as TarInfo objects - self._loaded = False # flag if all members have been read - self.offset = self.fileobj.tell() - # current position in the archive file - self.inodes = {} # dictionary caching the inodes of - # archive members already added - - try: - if self.mode == "r": - self.firstmember = None - self.firstmember = self.next() - - if self.mode == "a": - # Move to the end of the archive, - # before the first empty block. - while True: - self.fileobj.seek(self.offset) - try: - tarinfo = self.tarinfo.fromtarfile(self) - self.members.append(tarinfo) - except EOFHeaderError: - self.fileobj.seek(self.offset) - break - except HeaderError as e: - raise ReadError(str(e)) - - if self.mode in "aw": - self._loaded = True - - if self.pax_headers: - buf = self.tarinfo.create_pax_global_header(self.pax_headers.copy()) - self.fileobj.write(buf) - self.offset += len(buf) - except: - if not self._extfileobj: - self.fileobj.close() - self.closed = True - raise - - #-------------------------------------------------------------------------- - # Below are the classmethods which act as alternate constructors to the - # TarFile class. The open() method is the only one that is needed for - # public use; it is the "super"-constructor and is able to select an - # adequate "sub"-constructor for a particular compression using the mapping - # from OPEN_METH. - # - # This concept allows one to subclass TarFile without losing the comfort of - # the super-constructor. A sub-constructor is registered and made available - # by adding it to the mapping in OPEN_METH. - - @classmethod - def open(cls, name=None, mode="r", fileobj=None, bufsize=RECORDSIZE, **kwargs): - """Open a tar archive for reading, writing or appending. Return - an appropriate TarFile class. - - mode: - 'r' or 'r:*' open for reading with transparent compression - 'r:' open for reading exclusively uncompressed - 'r:gz' open for reading with gzip compression - 'r:bz2' open for reading with bzip2 compression - 'a' or 'a:' open for appending, creating the file if necessary - 'w' or 'w:' open for writing without compression - 'w:gz' open for writing with gzip compression - 'w:bz2' open for writing with bzip2 compression - - 'r|*' open a stream of tar blocks with transparent compression - 'r|' open an uncompressed stream of tar blocks for reading - 'r|gz' open a gzip compressed stream of tar blocks - 'r|bz2' open a bzip2 compressed stream of tar blocks - 'w|' open an uncompressed stream for writing - 'w|gz' open a gzip compressed stream for writing - 'w|bz2' open a bzip2 compressed stream for writing - """ - - if not name and not fileobj: - raise ValueError("nothing to open") - - if mode in ("r", "r:*"): - # Find out which *open() is appropriate for opening the file. - for comptype in cls.OPEN_METH: - func = getattr(cls, cls.OPEN_METH[comptype]) - if fileobj is not None: - saved_pos = fileobj.tell() - try: - return func(name, "r", fileobj, **kwargs) - except (ReadError, CompressionError) as e: - if fileobj is not None: - fileobj.seek(saved_pos) - continue - raise ReadError("file could not be opened successfully") - - elif ":" in mode: - filemode, comptype = mode.split(":", 1) - filemode = filemode or "r" - comptype = comptype or "tar" - - # Select the *open() function according to - # given compression. - if comptype in cls.OPEN_METH: - func = getattr(cls, cls.OPEN_METH[comptype]) - else: - raise CompressionError("unknown compression type %r" % comptype) - return func(name, filemode, fileobj, **kwargs) - - elif "|" in mode: - filemode, comptype = mode.split("|", 1) - filemode = filemode or "r" - comptype = comptype or "tar" - - if filemode not in "rw": - raise ValueError("mode must be 'r' or 'w'") - - stream = _Stream(name, filemode, comptype, fileobj, bufsize) - try: - t = cls(name, filemode, stream, **kwargs) - except: - stream.close() - raise - t._extfileobj = False - return t - - elif mode in "aw": - return cls.taropen(name, mode, fileobj, **kwargs) - - raise ValueError("undiscernible mode") - - @classmethod - def taropen(cls, name, mode="r", fileobj=None, **kwargs): - """Open uncompressed tar archive name for reading or writing. - """ - if len(mode) > 1 or mode not in "raw": - raise ValueError("mode must be 'r', 'a' or 'w'") - return cls(name, mode, fileobj, **kwargs) - - @classmethod - def gzopen(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs): - """Open gzip compressed tar archive name for reading or writing. - Appending is not allowed. - """ - if len(mode) > 1 or mode not in "rw": - raise ValueError("mode must be 'r' or 'w'") - - try: - import gzip - gzip.GzipFile - except (ImportError, AttributeError): - raise CompressionError("gzip module is not available") - - extfileobj = fileobj is not None - try: - fileobj = gzip.GzipFile(name, mode + "b", compresslevel, fileobj) - t = cls.taropen(name, mode, fileobj, **kwargs) - except IOError: - if not extfileobj and fileobj is not None: - fileobj.close() - if fileobj is None: - raise - raise ReadError("not a gzip file") - except: - if not extfileobj and fileobj is not None: - fileobj.close() - raise - t._extfileobj = extfileobj - return t - - @classmethod - def bz2open(cls, name, mode="r", fileobj=None, compresslevel=9, **kwargs): - """Open bzip2 compressed tar archive name for reading or writing. - Appending is not allowed. - """ - if len(mode) > 1 or mode not in "rw": - raise ValueError("mode must be 'r' or 'w'.") - - try: - import bz2 - except ImportError: - raise CompressionError("bz2 module is not available") - - if fileobj is not None: - fileobj = _BZ2Proxy(fileobj, mode) - else: - fileobj = bz2.BZ2File(name, mode, compresslevel=compresslevel) - - try: - t = cls.taropen(name, mode, fileobj, **kwargs) - except (IOError, EOFError): - fileobj.close() - raise ReadError("not a bzip2 file") - t._extfileobj = False - return t - - # All *open() methods are registered here. - OPEN_METH = { - "tar": "taropen", # uncompressed tar - "gz": "gzopen", # gzip compressed tar - "bz2": "bz2open" # bzip2 compressed tar - } - - #-------------------------------------------------------------------------- - # The public methods which TarFile provides: - - def close(self): - """Close the TarFile. In write-mode, two finishing zero blocks are - appended to the archive. - """ - if self.closed: - return - - if self.mode in "aw": - self.fileobj.write(NUL * (BLOCKSIZE * 2)) - self.offset += (BLOCKSIZE * 2) - # fill up the end with zero-blocks - # (like option -b20 for tar does) - blocks, remainder = divmod(self.offset, RECORDSIZE) - if remainder > 0: - self.fileobj.write(NUL * (RECORDSIZE - remainder)) - - if not self._extfileobj: - self.fileobj.close() - self.closed = True - - def getmember(self, name): - """Return a TarInfo object for member `name'. If `name' can not be - found in the archive, KeyError is raised. If a member occurs more - than once in the archive, its last occurrence is assumed to be the - most up-to-date version. - """ - tarinfo = self._getmember(name) - if tarinfo is None: - raise KeyError("filename %r not found" % name) - return tarinfo - - def getmembers(self): - """Return the members of the archive as a list of TarInfo objects. The - list has the same order as the members in the archive. - """ - self._check() - if not self._loaded: # if we want to obtain a list of - self._load() # all members, we first have to - # scan the whole archive. - return self.members - - def getnames(self): - """Return the members of the archive as a list of their names. It has - the same order as the list returned by getmembers(). - """ - return [tarinfo.name for tarinfo in self.getmembers()] - - def gettarinfo(self, name=None, arcname=None, fileobj=None): - """Create a TarInfo object for either the file `name' or the file - object `fileobj' (using os.fstat on its file descriptor). You can - modify some of the TarInfo's attributes before you add it using - addfile(). If given, `arcname' specifies an alternative name for the - file in the archive. - """ - self._check("aw") - - # When fileobj is given, replace name by - # fileobj's real name. - if fileobj is not None: - name = fileobj.name - - # Building the name of the member in the archive. - # Backward slashes are converted to forward slashes, - # Absolute paths are turned to relative paths. - if arcname is None: - arcname = name - drv, arcname = os.path.splitdrive(arcname) - arcname = arcname.replace(os.sep, "/") - arcname = arcname.lstrip("/") - - # Now, fill the TarInfo object with - # information specific for the file. - tarinfo = self.tarinfo() - tarinfo.tarfile = self - - # Use os.stat or os.lstat, depending on platform - # and if symlinks shall be resolved. - if fileobj is None: - if hasattr(os, "lstat") and not self.dereference: - statres = os.lstat(name) - else: - statres = os.stat(name) - else: - statres = os.fstat(fileobj.fileno()) - linkname = "" - - stmd = statres.st_mode - if stat.S_ISREG(stmd): - inode = (statres.st_ino, statres.st_dev) - if not self.dereference and statres.st_nlink > 1 and \ - inode in self.inodes and arcname != self.inodes[inode]: - # Is it a hardlink to an already - # archived file? - type = LNKTYPE - linkname = self.inodes[inode] - else: - # The inode is added only if its valid. - # For win32 it is always 0. - type = REGTYPE - if inode[0]: - self.inodes[inode] = arcname - elif stat.S_ISDIR(stmd): - type = DIRTYPE - elif stat.S_ISFIFO(stmd): - type = FIFOTYPE - elif stat.S_ISLNK(stmd): - type = SYMTYPE - linkname = os.readlink(name) - elif stat.S_ISCHR(stmd): - type = CHRTYPE - elif stat.S_ISBLK(stmd): - type = BLKTYPE - else: - return None - - # Fill the TarInfo object with all - # information we can get. - tarinfo.name = arcname - tarinfo.mode = stmd - tarinfo.uid = statres.st_uid - tarinfo.gid = statres.st_gid - if type == REGTYPE: - tarinfo.size = statres.st_size - else: - tarinfo.size = 0 - tarinfo.mtime = statres.st_mtime - tarinfo.type = type - tarinfo.linkname = linkname - if pwd: - try: - tarinfo.uname = pwd.getpwuid(tarinfo.uid)[0] - except KeyError: - pass - if grp: - try: - tarinfo.gname = grp.getgrgid(tarinfo.gid)[0] - except KeyError: - pass - - if type in (CHRTYPE, BLKTYPE): - if hasattr(os, "major") and hasattr(os, "minor"): - tarinfo.devmajor = os.major(statres.st_rdev) - tarinfo.devminor = os.minor(statres.st_rdev) - return tarinfo - - def list(self, verbose=True): - """Print a table of contents to sys.stdout. If `verbose' is False, only - the names of the members are printed. If it is True, an `ls -l'-like - output is produced. - """ - self._check() - - for tarinfo in self: - if verbose: - print(filemode(tarinfo.mode), end=' ') - print("%s/%s" % (tarinfo.uname or tarinfo.uid, - tarinfo.gname or tarinfo.gid), end=' ') - if tarinfo.ischr() or tarinfo.isblk(): - print("%10s" % ("%d,%d" \ - % (tarinfo.devmajor, tarinfo.devminor)), end=' ') - else: - print("%10d" % tarinfo.size, end=' ') - print("%d-%02d-%02d %02d:%02d:%02d" \ - % time.localtime(tarinfo.mtime)[:6], end=' ') - - print(tarinfo.name + ("/" if tarinfo.isdir() else ""), end=' ') - - if verbose: - if tarinfo.issym(): - print("->", tarinfo.linkname, end=' ') - if tarinfo.islnk(): - print("link to", tarinfo.linkname, end=' ') - print() - - def add(self, name, arcname=None, recursive=True, exclude=None, filter=None): - """Add the file `name' to the archive. `name' may be any type of file - (directory, fifo, symbolic link, etc.). If given, `arcname' - specifies an alternative name for the file in the archive. - Directories are added recursively by default. This can be avoided by - setting `recursive' to False. `exclude' is a function that should - return True for each filename to be excluded. `filter' is a function - that expects a TarInfo object argument and returns the changed - TarInfo object, if it returns None the TarInfo object will be - excluded from the archive. - """ - self._check("aw") - - if arcname is None: - arcname = name - - # Exclude pathnames. - if exclude is not None: - import warnings - warnings.warn("use the filter argument instead", - DeprecationWarning, 2) - if exclude(name): - self._dbg(2, "tarfile: Excluded %r" % name) - return - - # Skip if somebody tries to archive the archive... - if self.name is not None and os.path.abspath(name) == self.name: - self._dbg(2, "tarfile: Skipped %r" % name) - return - - self._dbg(1, name) - - # Create a TarInfo object from the file. - tarinfo = self.gettarinfo(name, arcname) - - if tarinfo is None: - self._dbg(1, "tarfile: Unsupported type %r" % name) - return - - # Change or exclude the TarInfo object. - if filter is not None: - tarinfo = filter(tarinfo) - if tarinfo is None: - self._dbg(2, "tarfile: Excluded %r" % name) - return - - # Append the tar header and data to the archive. - if tarinfo.isreg(): - f = bltn_open(name, "rb") - self.addfile(tarinfo, f) - f.close() - - elif tarinfo.isdir(): - self.addfile(tarinfo) - if recursive: - for f in os.listdir(name): - self.add(os.path.join(name, f), os.path.join(arcname, f), - recursive, exclude, filter=filter) - - else: - self.addfile(tarinfo) - - def addfile(self, tarinfo, fileobj=None): - """Add the TarInfo object `tarinfo' to the archive. If `fileobj' is - given, tarinfo.size bytes are read from it and added to the archive. - You can create TarInfo objects using gettarinfo(). - On Windows platforms, `fileobj' should always be opened with mode - 'rb' to avoid irritation about the file size. - """ - self._check("aw") - - tarinfo = copy.copy(tarinfo) - - buf = tarinfo.tobuf(self.format, self.encoding, self.errors) - self.fileobj.write(buf) - self.offset += len(buf) - - # If there's data to follow, append it. - if fileobj is not None: - copyfileobj(fileobj, self.fileobj, tarinfo.size) - blocks, remainder = divmod(tarinfo.size, BLOCKSIZE) - if remainder > 0: - self.fileobj.write(NUL * (BLOCKSIZE - remainder)) - blocks += 1 - self.offset += blocks * BLOCKSIZE - - self.members.append(tarinfo) - - def extractall(self, path=".", members=None): - """Extract all members from the archive to the current working - directory and set owner, modification time and permissions on - directories afterwards. `path' specifies a different directory - to extract to. `members' is optional and must be a subset of the - list returned by getmembers(). - """ - directories = [] - - if members is None: - members = self - - for tarinfo in members: - if tarinfo.isdir(): - # Extract directories with a safe mode. - directories.append(tarinfo) - tarinfo = copy.copy(tarinfo) - tarinfo.mode = 0o700 - # Do not set_attrs directories, as we will do that further down - self.extract(tarinfo, path, set_attrs=not tarinfo.isdir()) - - # Reverse sort directories. - directories.sort(key=lambda a: a.name) - directories.reverse() - - # Set correct owner, mtime and filemode on directories. - for tarinfo in directories: - dirpath = os.path.join(path, tarinfo.name) - try: - self.chown(tarinfo, dirpath) - self.utime(tarinfo, dirpath) - self.chmod(tarinfo, dirpath) - except ExtractError as e: - if self.errorlevel > 1: - raise - else: - self._dbg(1, "tarfile: %s" % e) - - def extract(self, member, path="", set_attrs=True): - """Extract a member from the archive to the current working directory, - using its full name. Its file information is extracted as accurately - as possible. `member' may be a filename or a TarInfo object. You can - specify a different directory using `path'. File attributes (owner, - mtime, mode) are set unless `set_attrs' is False. - """ - self._check("r") - - if isinstance(member, str): - tarinfo = self.getmember(member) - else: - tarinfo = member - - # Prepare the link target for makelink(). - if tarinfo.islnk(): - tarinfo._link_target = os.path.join(path, tarinfo.linkname) - - try: - self._extract_member(tarinfo, os.path.join(path, tarinfo.name), - set_attrs=set_attrs) - except EnvironmentError as e: - if self.errorlevel > 0: - raise - else: - if e.filename is None: - self._dbg(1, "tarfile: %s" % e.strerror) - else: - self._dbg(1, "tarfile: %s %r" % (e.strerror, e.filename)) - except ExtractError as e: - if self.errorlevel > 1: - raise - else: - self._dbg(1, "tarfile: %s" % e) - - def extractfile(self, member): - """Extract a member from the archive as a file object. `member' may be - a filename or a TarInfo object. If `member' is a regular file, a - file-like object is returned. If `member' is a link, a file-like - object is constructed from the link's target. If `member' is none of - the above, None is returned. - The file-like object is read-only and provides the following - methods: read(), readline(), readlines(), seek() and tell() - """ - self._check("r") - - if isinstance(member, str): - tarinfo = self.getmember(member) - else: - tarinfo = member - - if tarinfo.isreg(): - return self.fileobject(self, tarinfo) - - elif tarinfo.type not in SUPPORTED_TYPES: - # If a member's type is unknown, it is treated as a - # regular file. - return self.fileobject(self, tarinfo) - - elif tarinfo.islnk() or tarinfo.issym(): - if isinstance(self.fileobj, _Stream): - # A small but ugly workaround for the case that someone tries - # to extract a (sym)link as a file-object from a non-seekable - # stream of tar blocks. - raise StreamError("cannot extract (sym)link as file object") - else: - # A (sym)link's file object is its target's file object. - return self.extractfile(self._find_link_target(tarinfo)) - else: - # If there's no data associated with the member (directory, chrdev, - # blkdev, etc.), return None instead of a file object. - return None - - def _extract_member(self, tarinfo, targetpath, set_attrs=True): - """Extract the TarInfo object tarinfo to a physical - file called targetpath. - """ - # Fetch the TarInfo object for the given name - # and build the destination pathname, replacing - # forward slashes to platform specific separators. - targetpath = targetpath.rstrip("/") - targetpath = targetpath.replace("/", os.sep) - - # Create all upper directories. - upperdirs = os.path.dirname(targetpath) - if upperdirs and not os.path.exists(upperdirs): - # Create directories that are not part of the archive with - # default permissions. - os.makedirs(upperdirs) - - if tarinfo.islnk() or tarinfo.issym(): - self._dbg(1, "%s -> %s" % (tarinfo.name, tarinfo.linkname)) - else: - self._dbg(1, tarinfo.name) - - if tarinfo.isreg(): - self.makefile(tarinfo, targetpath) - elif tarinfo.isdir(): - self.makedir(tarinfo, targetpath) - elif tarinfo.isfifo(): - self.makefifo(tarinfo, targetpath) - elif tarinfo.ischr() or tarinfo.isblk(): - self.makedev(tarinfo, targetpath) - elif tarinfo.islnk() or tarinfo.issym(): - self.makelink(tarinfo, targetpath) - elif tarinfo.type not in SUPPORTED_TYPES: - self.makeunknown(tarinfo, targetpath) - else: - self.makefile(tarinfo, targetpath) - - if set_attrs: - self.chown(tarinfo, targetpath) - if not tarinfo.issym(): - self.chmod(tarinfo, targetpath) - self.utime(tarinfo, targetpath) - - #-------------------------------------------------------------------------- - # Below are the different file methods. They are called via - # _extract_member() when extract() is called. They can be replaced in a - # subclass to implement other functionality. - - def makedir(self, tarinfo, targetpath): - """Make a directory called targetpath. - """ - try: - # Use a safe mode for the directory, the real mode is set - # later in _extract_member(). - os.mkdir(targetpath, 0o700) - except EnvironmentError as e: - if e.errno != errno.EEXIST: - raise - - def makefile(self, tarinfo, targetpath): - """Make a file called targetpath. - """ - source = self.fileobj - source.seek(tarinfo.offset_data) - target = bltn_open(targetpath, "wb") - if tarinfo.sparse is not None: - for offset, size in tarinfo.sparse: - target.seek(offset) - copyfileobj(source, target, size) - else: - copyfileobj(source, target, tarinfo.size) - target.seek(tarinfo.size) - target.truncate() - target.close() - - def makeunknown(self, tarinfo, targetpath): - """Make a file from a TarInfo object with an unknown type - at targetpath. - """ - self.makefile(tarinfo, targetpath) - self._dbg(1, "tarfile: Unknown file type %r, " \ - "extracted as regular file." % tarinfo.type) - - def makefifo(self, tarinfo, targetpath): - """Make a fifo called targetpath. - """ - if hasattr(os, "mkfifo"): - os.mkfifo(targetpath) - else: - raise ExtractError("fifo not supported by system") - - def makedev(self, tarinfo, targetpath): - """Make a character or block device called targetpath. - """ - if not hasattr(os, "mknod") or not hasattr(os, "makedev"): - raise ExtractError("special devices not supported by system") - - mode = tarinfo.mode - if tarinfo.isblk(): - mode |= stat.S_IFBLK - else: - mode |= stat.S_IFCHR - - os.mknod(targetpath, mode, - os.makedev(tarinfo.devmajor, tarinfo.devminor)) - - def makelink(self, tarinfo, targetpath): - """Make a (symbolic) link called targetpath. If it cannot be created - (platform limitation), we try to make a copy of the referenced file - instead of a link. - """ - try: - # For systems that support symbolic and hard links. - if tarinfo.issym(): - os.symlink(tarinfo.linkname, targetpath) - else: - # See extract(). - if os.path.exists(tarinfo._link_target): - os.link(tarinfo._link_target, targetpath) - else: - self._extract_member(self._find_link_target(tarinfo), - targetpath) - except symlink_exception: - if tarinfo.issym(): - linkpath = os.path.join(os.path.dirname(tarinfo.name), - tarinfo.linkname) - else: - linkpath = tarinfo.linkname - else: - try: - self._extract_member(self._find_link_target(tarinfo), - targetpath) - except KeyError: - raise ExtractError("unable to resolve link inside archive") - - def chown(self, tarinfo, targetpath): - """Set owner of targetpath according to tarinfo. - """ - if pwd and hasattr(os, "geteuid") and os.geteuid() == 0: - # We have to be root to do so. - try: - g = grp.getgrnam(tarinfo.gname)[2] - except KeyError: - g = tarinfo.gid - try: - u = pwd.getpwnam(tarinfo.uname)[2] - except KeyError: - u = tarinfo.uid - try: - if tarinfo.issym() and hasattr(os, "lchown"): - os.lchown(targetpath, u, g) - else: - if sys.platform != "os2emx": - os.chown(targetpath, u, g) - except EnvironmentError as e: - raise ExtractError("could not change owner") - - def chmod(self, tarinfo, targetpath): - """Set file permissions of targetpath according to tarinfo. - """ - if hasattr(os, 'chmod'): - try: - os.chmod(targetpath, tarinfo.mode) - except EnvironmentError as e: - raise ExtractError("could not change mode") - - def utime(self, tarinfo, targetpath): - """Set modification time of targetpath according to tarinfo. - """ - if not hasattr(os, 'utime'): - return - try: - os.utime(targetpath, (tarinfo.mtime, tarinfo.mtime)) - except EnvironmentError as e: - raise ExtractError("could not change modification time") - - #-------------------------------------------------------------------------- - def next(self): - """Return the next member of the archive as a TarInfo object, when - TarFile is opened for reading. Return None if there is no more - available. - """ - self._check("ra") - if self.firstmember is not None: - m = self.firstmember - self.firstmember = None - return m - - # Read the next block. - self.fileobj.seek(self.offset) - tarinfo = None - while True: - try: - tarinfo = self.tarinfo.fromtarfile(self) - except EOFHeaderError as e: - if self.ignore_zeros: - self._dbg(2, "0x%X: %s" % (self.offset, e)) - self.offset += BLOCKSIZE - continue - except InvalidHeaderError as e: - if self.ignore_zeros: - self._dbg(2, "0x%X: %s" % (self.offset, e)) - self.offset += BLOCKSIZE - continue - elif self.offset == 0: - raise ReadError(str(e)) - except EmptyHeaderError: - if self.offset == 0: - raise ReadError("empty file") - except TruncatedHeaderError as e: - if self.offset == 0: - raise ReadError(str(e)) - except SubsequentHeaderError as e: - raise ReadError(str(e)) - break - - if tarinfo is not None: - self.members.append(tarinfo) - else: - self._loaded = True - - return tarinfo - - #-------------------------------------------------------------------------- - # Little helper methods: - - def _getmember(self, name, tarinfo=None, normalize=False): - """Find an archive member by name from bottom to top. - If tarinfo is given, it is used as the starting point. - """ - # Ensure that all members have been loaded. - members = self.getmembers() - - # Limit the member search list up to tarinfo. - if tarinfo is not None: - members = members[:members.index(tarinfo)] - - if normalize: - name = os.path.normpath(name) - - for member in reversed(members): - if normalize: - member_name = os.path.normpath(member.name) - else: - member_name = member.name - - if name == member_name: - return member - - def _load(self): - """Read through the entire archive file and look for readable - members. - """ - while True: - tarinfo = self.next() - if tarinfo is None: - break - self._loaded = True - - def _check(self, mode=None): - """Check if TarFile is still open, and if the operation's mode - corresponds to TarFile's mode. - """ - if self.closed: - raise IOError("%s is closed" % self.__class__.__name__) - if mode is not None and self.mode not in mode: - raise IOError("bad operation for mode %r" % self.mode) - - def _find_link_target(self, tarinfo): - """Find the target member of a symlink or hardlink member in the - archive. - """ - if tarinfo.issym(): - # Always search the entire archive. - linkname = os.path.dirname(tarinfo.name) + "/" + tarinfo.linkname - limit = None - else: - # Search the archive before the link, because a hard link is - # just a reference to an already archived file. - linkname = tarinfo.linkname - limit = tarinfo - - member = self._getmember(linkname, tarinfo=limit, normalize=True) - if member is None: - raise KeyError("linkname %r not found" % linkname) - return member - - def __iter__(self): - """Provide an iterator object. - """ - if self._loaded: - return iter(self.members) - else: - return TarIter(self) - - def _dbg(self, level, msg): - """Write debugging output to sys.stderr. - """ - if level <= self.debug: - print(msg, file=sys.stderr) - - def __enter__(self): - self._check() - return self - - def __exit__(self, type, value, traceback): - if type is None: - self.close() - else: - # An exception occurred. We must not call close() because - # it would try to write end-of-archive blocks and padding. - if not self._extfileobj: - self.fileobj.close() - self.closed = True -# class TarFile - -class TarIter(object): - """Iterator Class. - - for tarinfo in TarFile(...): - suite... - """ - - def __init__(self, tarfile): - """Construct a TarIter object. - """ - self.tarfile = tarfile - self.index = 0 - def __iter__(self): - """Return iterator object. - """ - return self - - def __next__(self): - """Return the next item using TarFile's next() method. - When all members have been read, set TarFile as _loaded. - """ - # Fix for SF #1100429: Under rare circumstances it can - # happen that getmembers() is called during iteration, - # which will cause TarIter to stop prematurely. - if not self.tarfile._loaded: - tarinfo = self.tarfile.next() - if not tarinfo: - self.tarfile._loaded = True - raise StopIteration - else: - try: - tarinfo = self.tarfile.members[self.index] - except IndexError: - raise StopIteration - self.index += 1 - return tarinfo - - next = __next__ # for Python 2.x - -#-------------------- -# exported functions -#-------------------- -def is_tarfile(name): - """Return True if name points to a tar archive that we - are able to handle, else return False. - """ - try: - t = open(name) - t.close() - return True - except TarError: - return False - -bltn_open = open -open = TarFile.open diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/compat.py b/vendor/pip-1.5.6/pip/_vendor/distlib/compat.py deleted file mode 100644 index 63af374..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/distlib/compat.py +++ /dev/null @@ -1,1064 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2013 Vinay Sajip. -# Licensed to the Python Software Foundation under a contributor agreement. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -from __future__ import absolute_import - -import os -import re -import sys - -if sys.version_info[0] < 3: - from StringIO import StringIO - string_types = basestring, - text_type = unicode - from types import FileType as file_type - import __builtin__ as builtins - import ConfigParser as configparser - from ._backport import shutil - from urlparse import urlparse, urlunparse, urljoin, urlsplit, urlunsplit - from urllib import (urlretrieve, quote as _quote, unquote, url2pathname, - pathname2url, ContentTooShortError, splittype) - - def quote(s): - if isinstance(s, unicode): - s = s.encode('utf-8') - return _quote(s) - - import urllib2 - from urllib2 import (Request, urlopen, URLError, HTTPError, - HTTPBasicAuthHandler, HTTPPasswordMgr, - HTTPSHandler, HTTPHandler, HTTPRedirectHandler, - build_opener) - import httplib - import xmlrpclib - import Queue as queue - from HTMLParser import HTMLParser - import htmlentitydefs - raw_input = raw_input - from itertools import ifilter as filter - from itertools import ifilterfalse as filterfalse - - _userprog = None - def splituser(host): - """splituser('user[:passwd]@host[:port]') --> 'user[:passwd]', 'host[:port]'.""" - global _userprog - if _userprog is None: - import re - _userprog = re.compile('^(.*)@(.*)$') - - match = _userprog.match(host) - if match: return match.group(1, 2) - return None, host - -else: - from io import StringIO - string_types = str, - text_type = str - from io import TextIOWrapper as file_type - import builtins - import configparser - import shutil - from urllib.parse import (urlparse, urlunparse, urljoin, splituser, quote, - unquote, urlsplit, urlunsplit, splittype) - from urllib.request import (urlopen, urlretrieve, Request, url2pathname, - pathname2url, - HTTPBasicAuthHandler, HTTPPasswordMgr, - HTTPSHandler, HTTPHandler, HTTPRedirectHandler, - build_opener) - from urllib.error import HTTPError, URLError, ContentTooShortError - import http.client as httplib - import urllib.request as urllib2 - import xmlrpc.client as xmlrpclib - import queue - from html.parser import HTMLParser - import html.entities as htmlentitydefs - raw_input = input - from itertools import filterfalse - filter = filter - -try: - from ssl import match_hostname, CertificateError -except ImportError: - class CertificateError(ValueError): - pass - - - def _dnsname_to_pat(dn): - pats = [] - for frag in dn.split(r'.'): - if frag == '*': - # When '*' is a fragment by itself, it matches a non-empty - # dotless fragment. - pats.append('[^.]+') - else: - # Otherwise, '*' matches any dotless fragment. - frag = re.escape(frag) - pats.append(frag.replace(r'\*', '[^.]*')) - return re.compile(r'\A' + r'\.'.join(pats) + r'\Z', re.IGNORECASE) - - - def match_hostname(cert, hostname): - """Verify that *cert* (in decoded format as returned by - SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 rules - are mostly followed, but IP addresses are not accepted for *hostname*. - - CertificateError is raised on failure. On success, the function - returns nothing. - """ - if not cert: - raise ValueError("empty or no certificate") - dnsnames = [] - san = cert.get('subjectAltName', ()) - for key, value in san: - if key == 'DNS': - if _dnsname_to_pat(value).match(hostname): - 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 key, value in sub: - # XXX according to RFC 2818, the most specific Common Name - # must be used. - if key == 'commonName': - if _dnsname_to_pat(value).match(hostname): - return - dnsnames.append(value) - if len(dnsnames) > 1: - 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])) - else: - raise CertificateError("no appropriate commonName or " - "subjectAltName fields were found") - - -try: - from types import SimpleNamespace as Container -except ImportError: - class Container(object): - """ - A generic container for when multiple values need to be returned - """ - def __init__(self, **kwargs): - self.__dict__.update(kwargs) - - -try: - from shutil import which -except ImportError: - # Implementation from Python 3.3 - def which(cmd, mode=os.F_OK | os.X_OK, path=None): - """Given a command, mode, and a PATH string, return the path which - conforms to the given mode on the PATH, or None if there is no such - file. - - `mode` defaults to os.F_OK | os.X_OK. `path` defaults to the result - of os.environ.get("PATH"), or can be overridden with a custom search - path. - - """ - # Check that a given file can be accessed with the correct mode. - # Additionally check that `file` is not a directory, as on Windows - # directories pass the os.access check. - def _access_check(fn, mode): - return (os.path.exists(fn) and os.access(fn, mode) - and not os.path.isdir(fn)) - - # If we're given a path with a directory part, look it up directly rather - # than referring to PATH directories. This includes checking relative to the - # current directory, e.g. ./script - if os.path.dirname(cmd): - if _access_check(cmd, mode): - return cmd - return None - - if path is None: - path = os.environ.get("PATH", os.defpath) - if not path: - return None - path = path.split(os.pathsep) - - if sys.platform == "win32": - # The current directory takes precedence on Windows. - if not os.curdir in path: - path.insert(0, os.curdir) - - # PATHEXT is necessary to check on Windows. - pathext = os.environ.get("PATHEXT", "").split(os.pathsep) - # See if the given file matches any of the expected path extensions. - # This will allow us to short circuit when given "python.exe". - # If it does match, only test that one, otherwise we have to try - # others. - if any(cmd.lower().endswith(ext.lower()) for ext in pathext): - files = [cmd] - else: - files = [cmd + ext for ext in pathext] - else: - # On other platforms you don't have things like PATHEXT to tell you - # what file suffixes are executable, so just pass on cmd as-is. - files = [cmd] - - seen = set() - for dir in path: - normdir = os.path.normcase(dir) - if not normdir in seen: - seen.add(normdir) - for thefile in files: - name = os.path.join(dir, thefile) - if _access_check(name, mode): - return name - return None - - -# ZipFile is a context manager in 2.7, but not in 2.6 - -from zipfile import ZipFile as BaseZipFile - -if hasattr(BaseZipFile, '__enter__'): - ZipFile = BaseZipFile -else: - from zipfile import ZipExtFile as BaseZipExtFile - - class ZipExtFile(BaseZipExtFile): - def __init__(self, base): - self.__dict__.update(base.__dict__) - - def __enter__(self): - return self - - def __exit__(self, *exc_info): - self.close() - # return None, so if an exception occurred, it will propagate - - class ZipFile(BaseZipFile): - def __enter__(self): - return self - - def __exit__(self, *exc_info): - self.close() - # return None, so if an exception occurred, it will propagate - - def open(self, *args, **kwargs): - base = BaseZipFile.open(self, *args, **kwargs) - return ZipExtFile(base) - -try: - from platform import python_implementation -except ImportError: # pragma: no cover - def python_implementation(): - """Return a string identifying the Python implementation.""" - if 'PyPy' in sys.version: - return 'PyPy' - if os.name == 'java': - return 'Jython' - if sys.version.startswith('IronPython'): - return 'IronPython' - return 'CPython' - -try: - import sysconfig -except ImportError: # pragma: no cover - from ._backport import sysconfig - -try: - callable = callable -except NameError: # pragma: no cover - from collections import Callable - - def callable(obj): - return isinstance(obj, Callable) - - -try: - fsencode = os.fsencode - fsdecode = os.fsdecode -except AttributeError: # pragma: no cover - _fsencoding = sys.getfilesystemencoding() - if _fsencoding == 'mbcs': - _fserrors = 'strict' - else: - _fserrors = 'surrogateescape' - - def fsencode(filename): - if isinstance(filename, bytes): - return filename - elif isinstance(filename, text_type): - return filename.encode(_fsencoding, _fserrors) - else: - raise TypeError("expect bytes or str, not %s" % - type(filename).__name__) - - def fsdecode(filename): - if isinstance(filename, text_type): - return filename - elif isinstance(filename, bytes): - return filename.decode(_fsencoding, _fserrors) - else: - raise TypeError("expect bytes or str, not %s" % - type(filename).__name__) - -try: - from tokenize import detect_encoding -except ImportError: # pragma: no cover - from codecs import BOM_UTF8, lookup - import re - - cookie_re = re.compile("coding[:=]\s*([-\w.]+)") - - def _get_normal_name(orig_enc): - """Imitates get_normal_name in tokenizer.c.""" - # Only care about the first 12 characters. - enc = orig_enc[:12].lower().replace("_", "-") - if enc == "utf-8" or enc.startswith("utf-8-"): - return "utf-8" - if enc in ("latin-1", "iso-8859-1", "iso-latin-1") or \ - enc.startswith(("latin-1-", "iso-8859-1-", "iso-latin-1-")): - return "iso-8859-1" - return orig_enc - - def detect_encoding(readline): - """ - The detect_encoding() function is used to detect the encoding that should - be used to decode a Python source file. It requires one argment, readline, - in the same way as the tokenize() generator. - - It will call readline a maximum of twice, and return the encoding used - (as a string) and a list of any lines (left as bytes) it has read in. - - It detects the encoding from the presence of a utf-8 bom or an encoding - cookie as specified in pep-0263. If both a bom and a cookie are present, - but disagree, a SyntaxError will be raised. If the encoding cookie is an - invalid charset, raise a SyntaxError. Note that if a utf-8 bom is found, - 'utf-8-sig' is returned. - - If no encoding is specified, then the default of 'utf-8' will be returned. - """ - try: - filename = readline.__self__.name - except AttributeError: - filename = None - bom_found = False - encoding = None - default = 'utf-8' - def read_or_stop(): - try: - return readline() - except StopIteration: - return b'' - - def find_cookie(line): - try: - # Decode as UTF-8. Either the line is an encoding declaration, - # in which case it should be pure ASCII, or it must be UTF-8 - # per default encoding. - line_string = line.decode('utf-8') - except UnicodeDecodeError: - msg = "invalid or missing encoding declaration" - if filename is not None: - msg = '{} for {!r}'.format(msg, filename) - raise SyntaxError(msg) - - matches = cookie_re.findall(line_string) - if not matches: - return None - encoding = _get_normal_name(matches[0]) - try: - codec = lookup(encoding) - except LookupError: - # This behaviour mimics the Python interpreter - if filename is None: - msg = "unknown encoding: " + encoding - else: - msg = "unknown encoding for {!r}: {}".format(filename, - encoding) - raise SyntaxError(msg) - - if bom_found: - if codec.name != 'utf-8': - # This behaviour mimics the Python interpreter - if filename is None: - msg = 'encoding problem: utf-8' - else: - msg = 'encoding problem for {!r}: utf-8'.format(filename) - raise SyntaxError(msg) - encoding += '-sig' - return encoding - - first = read_or_stop() - if first.startswith(BOM_UTF8): - bom_found = True - first = first[3:] - default = 'utf-8-sig' - if not first: - return default, [] - - encoding = find_cookie(first) - if encoding: - return encoding, [first] - - second = read_or_stop() - if not second: - return default, [first] - - encoding = find_cookie(second) - if encoding: - return encoding, [first, second] - - return default, [first, second] - -# For converting & <-> & etc. -try: - from html import escape -except ImportError: - from cgi import escape -if sys.version_info[:2] < (3, 4): - unescape = HTMLParser().unescape -else: - from html import unescape - -try: - from collections import ChainMap -except ImportError: # pragma: no cover - from collections import MutableMapping - - try: - from reprlib import recursive_repr as _recursive_repr - except ImportError: - def _recursive_repr(fillvalue='...'): - ''' - Decorator to make a repr function return fillvalue for a recursive - call - ''' - - def decorating_function(user_function): - repr_running = set() - - def wrapper(self): - key = id(self), get_ident() - if key in repr_running: - return fillvalue - repr_running.add(key) - try: - result = user_function(self) - finally: - repr_running.discard(key) - return result - - # Can't use functools.wraps() here because of bootstrap issues - wrapper.__module__ = getattr(user_function, '__module__') - wrapper.__doc__ = getattr(user_function, '__doc__') - wrapper.__name__ = getattr(user_function, '__name__') - wrapper.__annotations__ = getattr(user_function, '__annotations__', {}) - return wrapper - - return decorating_function - - class ChainMap(MutableMapping): - ''' A ChainMap groups multiple dicts (or other mappings) together - to create a single, updateable view. - - The underlying mappings are stored in a list. That list is public and can - accessed or updated using the *maps* attribute. There is no other state. - - Lookups search the underlying mappings successively until a key is found. - In contrast, writes, updates, and deletions only operate on the first - mapping. - - ''' - - def __init__(self, *maps): - '''Initialize a ChainMap by setting *maps* to the given mappings. - If no mappings are provided, a single empty dictionary is used. - - ''' - self.maps = list(maps) or [{}] # always at least one map - - def __missing__(self, key): - raise KeyError(key) - - def __getitem__(self, key): - for mapping in self.maps: - try: - return mapping[key] # can't use 'key in mapping' with defaultdict - except KeyError: - pass - return self.__missing__(key) # support subclasses that define __missing__ - - def get(self, key, default=None): - return self[key] if key in self else default - - def __len__(self): - return len(set().union(*self.maps)) # reuses stored hash values if possible - - def __iter__(self): - return iter(set().union(*self.maps)) - - def __contains__(self, key): - return any(key in m for m in self.maps) - - def __bool__(self): - return any(self.maps) - - @_recursive_repr() - def __repr__(self): - return '{0.__class__.__name__}({1})'.format( - self, ', '.join(map(repr, self.maps))) - - @classmethod - def fromkeys(cls, iterable, *args): - 'Create a ChainMap with a single dict created from the iterable.' - return cls(dict.fromkeys(iterable, *args)) - - def copy(self): - 'New ChainMap or subclass with a new copy of maps[0] and refs to maps[1:]' - return self.__class__(self.maps[0].copy(), *self.maps[1:]) - - __copy__ = copy - - def new_child(self): # like Django's Context.push() - 'New ChainMap with a new dict followed by all previous maps.' - return self.__class__({}, *self.maps) - - @property - def parents(self): # like Django's Context.pop() - 'New ChainMap from maps[1:].' - return self.__class__(*self.maps[1:]) - - def __setitem__(self, key, value): - self.maps[0][key] = value - - def __delitem__(self, key): - try: - del self.maps[0][key] - except KeyError: - raise KeyError('Key not found in the first mapping: {!r}'.format(key)) - - def popitem(self): - 'Remove and return an item pair from maps[0]. Raise KeyError is maps[0] is empty.' - try: - return self.maps[0].popitem() - except KeyError: - raise KeyError('No keys found in the first mapping.') - - def pop(self, key, *args): - 'Remove *key* from maps[0] and return its value. Raise KeyError if *key* not in maps[0].' - try: - return self.maps[0].pop(key, *args) - except KeyError: - raise KeyError('Key not found in the first mapping: {!r}'.format(key)) - - def clear(self): - 'Clear maps[0], leaving maps[1:] intact.' - self.maps[0].clear() - -try: - from imp import cache_from_source -except ImportError: # pragma: no cover - def cache_from_source(path, debug_override=None): - assert path.endswith('.py') - if debug_override is None: - debug_override = __debug__ - if debug_override: - suffix = 'c' - else: - suffix = 'o' - return path + suffix - -try: - from collections import OrderedDict -except ImportError: # pragma: no cover -## {{{ http://code.activestate.com/recipes/576693/ (r9) -# Backport of OrderedDict() class that runs on Python 2.4, 2.5, 2.6, 2.7 and pypy. -# Passes Python2.7's test suite and incorporates all the latest updates. - try: - from thread import get_ident as _get_ident - except ImportError: - from dummy_thread import get_ident as _get_ident - - try: - from _abcoll import KeysView, ValuesView, ItemsView - except ImportError: - pass - - - class OrderedDict(dict): - 'Dictionary that remembers insertion order' - # An inherited dict maps keys to values. - # The inherited dict provides __getitem__, __len__, __contains__, and get. - # The remaining methods are order-aware. - # Big-O running times for all methods are the same as for regular dictionaries. - - # The internal self.__map dictionary maps keys to links in a doubly linked list. - # The circular doubly linked list starts and ends with a sentinel element. - # The sentinel element never gets deleted (this simplifies the algorithm). - # Each link is stored as a list of length three: [PREV, NEXT, KEY]. - - def __init__(self, *args, **kwds): - '''Initialize an ordered dictionary. Signature is the same as for - regular dictionaries, but keyword arguments are not recommended - because their insertion order is arbitrary. - - ''' - if len(args) > 1: - raise TypeError('expected at most 1 arguments, got %d' % len(args)) - try: - self.__root - except AttributeError: - self.__root = root = [] # sentinel node - root[:] = [root, root, None] - self.__map = {} - self.__update(*args, **kwds) - - def __setitem__(self, key, value, dict_setitem=dict.__setitem__): - 'od.__setitem__(i, y) <==> od[i]=y' - # Setting a new item creates a new link which goes at the end of the linked - # list, and the inherited dictionary is updated with the new key/value pair. - if key not in self: - root = self.__root - last = root[0] - last[1] = root[0] = self.__map[key] = [last, root, key] - dict_setitem(self, key, value) - - def __delitem__(self, key, dict_delitem=dict.__delitem__): - 'od.__delitem__(y) <==> del od[y]' - # Deleting an existing item uses self.__map to find the link which is - # then removed by updating the links in the predecessor and successor nodes. - dict_delitem(self, key) - link_prev, link_next, key = self.__map.pop(key) - link_prev[1] = link_next - link_next[0] = link_prev - - def __iter__(self): - 'od.__iter__() <==> iter(od)' - root = self.__root - curr = root[1] - while curr is not root: - yield curr[2] - curr = curr[1] - - def __reversed__(self): - 'od.__reversed__() <==> reversed(od)' - root = self.__root - curr = root[0] - while curr is not root: - yield curr[2] - curr = curr[0] - - def clear(self): - 'od.clear() -> None. Remove all items from od.' - try: - for node in self.__map.itervalues(): - del node[:] - root = self.__root - root[:] = [root, root, None] - self.__map.clear() - except AttributeError: - pass - dict.clear(self) - - def popitem(self, last=True): - '''od.popitem() -> (k, v), return and remove a (key, value) pair. - Pairs are returned in LIFO order if last is true or FIFO order if false. - - ''' - if not self: - raise KeyError('dictionary is empty') - root = self.__root - if last: - link = root[0] - link_prev = link[0] - link_prev[1] = root - root[0] = link_prev - else: - link = root[1] - link_next = link[1] - root[1] = link_next - link_next[0] = root - key = link[2] - del self.__map[key] - value = dict.pop(self, key) - return key, value - - # -- the following methods do not depend on the internal structure -- - - def keys(self): - 'od.keys() -> list of keys in od' - return list(self) - - def values(self): - 'od.values() -> list of values in od' - return [self[key] for key in self] - - def items(self): - 'od.items() -> list of (key, value) pairs in od' - return [(key, self[key]) for key in self] - - def iterkeys(self): - 'od.iterkeys() -> an iterator over the keys in od' - return iter(self) - - def itervalues(self): - 'od.itervalues -> an iterator over the values in od' - for k in self: - yield self[k] - - def iteritems(self): - 'od.iteritems -> an iterator over the (key, value) items in od' - for k in self: - yield (k, self[k]) - - def update(*args, **kwds): - '''od.update(E, **F) -> None. Update od from dict/iterable E and F. - - If E is a dict instance, does: for k in E: od[k] = E[k] - If E has a .keys() method, does: for k in E.keys(): od[k] = E[k] - Or if E is an iterable of items, does: for k, v in E: od[k] = v - In either case, this is followed by: for k, v in F.items(): od[k] = v - - ''' - if len(args) > 2: - raise TypeError('update() takes at most 2 positional ' - 'arguments (%d given)' % (len(args),)) - elif not args: - raise TypeError('update() takes at least 1 argument (0 given)') - self = args[0] - # Make progressively weaker assumptions about "other" - other = () - if len(args) == 2: - other = args[1] - if isinstance(other, dict): - for key in other: - self[key] = other[key] - elif hasattr(other, 'keys'): - for key in other.keys(): - self[key] = other[key] - else: - for key, value in other: - self[key] = value - for key, value in kwds.items(): - self[key] = value - - __update = update # let subclasses override update without breaking __init__ - - __marker = object() - - def pop(self, key, default=__marker): - '''od.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. - - ''' - if key in self: - result = self[key] - del self[key] - return result - if default is self.__marker: - raise KeyError(key) - return default - - def setdefault(self, key, default=None): - 'od.setdefault(k[,d]) -> od.get(k,d), also set od[k]=d if k not in od' - if key in self: - return self[key] - self[key] = default - return default - - def __repr__(self, _repr_running=None): - 'od.__repr__() <==> repr(od)' - if not _repr_running: _repr_running = {} - call_key = id(self), _get_ident() - if call_key in _repr_running: - return '...' - _repr_running[call_key] = 1 - try: - if not self: - return '%s()' % (self.__class__.__name__,) - return '%s(%r)' % (self.__class__.__name__, self.items()) - finally: - del _repr_running[call_key] - - def __reduce__(self): - 'Return state information for pickling' - items = [[k, self[k]] for k in self] - inst_dict = vars(self).copy() - for k in vars(OrderedDict()): - inst_dict.pop(k, None) - if inst_dict: - return (self.__class__, (items,), inst_dict) - return self.__class__, (items,) - - def copy(self): - 'od.copy() -> a shallow copy of od' - return self.__class__(self) - - @classmethod - def fromkeys(cls, iterable, value=None): - '''OD.fromkeys(S[, v]) -> New ordered dictionary with keys from S - and values equal to v (which defaults to None). - - ''' - d = cls() - for key in iterable: - d[key] = value - return d - - def __eq__(self, other): - '''od.__eq__(y) <==> od==y. Comparison to another OD is order-sensitive - while comparison to a regular mapping is order-insensitive. - - ''' - if isinstance(other, OrderedDict): - return len(self)==len(other) and self.items() == other.items() - return dict.__eq__(self, other) - - def __ne__(self, other): - return not self == other - - # -- the following methods are only used in Python 2.7 -- - - def viewkeys(self): - "od.viewkeys() -> a set-like object providing a view on od's keys" - return KeysView(self) - - def viewvalues(self): - "od.viewvalues() -> an object providing a view on od's values" - return ValuesView(self) - - def viewitems(self): - "od.viewitems() -> a set-like object providing a view on od's items" - return ItemsView(self) - -try: - from logging.config import BaseConfigurator, valid_ident -except ImportError: # pragma: no cover - IDENTIFIER = re.compile('^[a-z_][a-z0-9_]*$', re.I) - - - def valid_ident(s): - m = IDENTIFIER.match(s) - if not m: - raise ValueError('Not a valid Python identifier: %r' % s) - return True - - - # The ConvertingXXX classes are wrappers around standard Python containers, - # and they serve to convert any suitable values in the container. The - # conversion converts base dicts, lists and tuples to their wrapped - # equivalents, whereas strings which match a conversion format are converted - # appropriately. - # - # Each wrapper should have a configurator attribute holding the actual - # configurator to use for conversion. - - class ConvertingDict(dict): - """A converting dictionary wrapper.""" - - def __getitem__(self, key): - value = dict.__getitem__(self, key) - result = self.configurator.convert(value) - #If the converted value is different, save for next time - if value is not result: - self[key] = result - if type(result) in (ConvertingDict, ConvertingList, - ConvertingTuple): - result.parent = self - result.key = key - return result - - def get(self, key, default=None): - value = dict.get(self, key, default) - result = self.configurator.convert(value) - #If the converted value is different, save for next time - if value is not result: - self[key] = result - if type(result) in (ConvertingDict, ConvertingList, - ConvertingTuple): - result.parent = self - result.key = key - return result - - def pop(self, key, default=None): - value = dict.pop(self, key, default) - result = self.configurator.convert(value) - if value is not result: - if type(result) in (ConvertingDict, ConvertingList, - ConvertingTuple): - result.parent = self - result.key = key - return result - - class ConvertingList(list): - """A converting list wrapper.""" - def __getitem__(self, key): - value = list.__getitem__(self, key) - result = self.configurator.convert(value) - #If the converted value is different, save for next time - if value is not result: - self[key] = result - if type(result) in (ConvertingDict, ConvertingList, - ConvertingTuple): - result.parent = self - result.key = key - return result - - def pop(self, idx=-1): - value = list.pop(self, idx) - result = self.configurator.convert(value) - if value is not result: - if type(result) in (ConvertingDict, ConvertingList, - ConvertingTuple): - result.parent = self - return result - - class ConvertingTuple(tuple): - """A converting tuple wrapper.""" - def __getitem__(self, key): - value = tuple.__getitem__(self, key) - result = self.configurator.convert(value) - if value is not result: - if type(result) in (ConvertingDict, ConvertingList, - ConvertingTuple): - result.parent = self - result.key = key - return result - - class BaseConfigurator(object): - """ - The configurator base class which defines some useful defaults. - """ - - CONVERT_PATTERN = re.compile(r'^(?P[a-z]+)://(?P.*)$') - - WORD_PATTERN = re.compile(r'^\s*(\w+)\s*') - DOT_PATTERN = re.compile(r'^\.\s*(\w+)\s*') - INDEX_PATTERN = re.compile(r'^\[\s*(\w+)\s*\]\s*') - DIGIT_PATTERN = re.compile(r'^\d+$') - - value_converters = { - 'ext' : 'ext_convert', - 'cfg' : 'cfg_convert', - } - - # We might want to use a different one, e.g. importlib - importer = staticmethod(__import__) - - def __init__(self, config): - self.config = ConvertingDict(config) - self.config.configurator = self - - def resolve(self, s): - """ - Resolve strings to objects using standard import and attribute - syntax. - """ - name = s.split('.') - used = name.pop(0) - try: - found = self.importer(used) - for frag in name: - used += '.' + frag - try: - found = getattr(found, frag) - except AttributeError: - self.importer(used) - found = getattr(found, frag) - return found - except ImportError: - e, tb = sys.exc_info()[1:] - v = ValueError('Cannot resolve %r: %s' % (s, e)) - v.__cause__, v.__traceback__ = e, tb - raise v - - def ext_convert(self, value): - """Default converter for the ext:// protocol.""" - return self.resolve(value) - - def cfg_convert(self, value): - """Default converter for the cfg:// protocol.""" - rest = value - m = self.WORD_PATTERN.match(rest) - if m is None: - raise ValueError("Unable to convert %r" % value) - else: - rest = rest[m.end():] - d = self.config[m.groups()[0]] - #print d, rest - while rest: - m = self.DOT_PATTERN.match(rest) - if m: - d = d[m.groups()[0]] - else: - m = self.INDEX_PATTERN.match(rest) - if m: - idx = m.groups()[0] - if not self.DIGIT_PATTERN.match(idx): - d = d[idx] - else: - try: - n = int(idx) # try as number first (most likely) - d = d[n] - except TypeError: - d = d[idx] - if m: - rest = rest[m.end():] - else: - raise ValueError('Unable to convert ' - '%r at %r' % (value, rest)) - #rest should be empty - return d - - def convert(self, value): - """ - Convert values to an appropriate type. dicts, lists and tuples are - replaced by their converting alternatives. Strings are checked to - see if they have a conversion format and are converted if they do. - """ - if not isinstance(value, ConvertingDict) and isinstance(value, dict): - value = ConvertingDict(value) - value.configurator = self - elif not isinstance(value, ConvertingList) and isinstance(value, list): - value = ConvertingList(value) - value.configurator = self - elif not isinstance(value, ConvertingTuple) and\ - isinstance(value, tuple): - value = ConvertingTuple(value) - value.configurator = self - elif isinstance(value, string_types): - m = self.CONVERT_PATTERN.match(value) - if m: - d = m.groupdict() - prefix = d['prefix'] - converter = self.value_converters.get(prefix, None) - if converter: - suffix = d['suffix'] - converter = getattr(self, converter) - value = converter(suffix) - return value - - def configure_custom(self, config): - """Configure an object with a user-supplied factory.""" - c = config.pop('()') - if not callable(c): - c = self.resolve(c) - props = config.pop('.', None) - # Check for valid identifiers - kwargs = dict([(k, config[k]) for k in config if valid_ident(k)]) - result = c(**kwargs) - if props: - for name, value in props.items(): - setattr(result, name, value) - return result - - def as_tuple(self, value): - """Utility function which converts lists to tuples.""" - if isinstance(value, list): - value = tuple(value) - return value diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/database.py b/vendor/pip-1.5.6/pip/_vendor/distlib/database.py deleted file mode 100644 index 0f013ec..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/distlib/database.py +++ /dev/null @@ -1,1301 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012-2013 The Python Software Foundation. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -"""PEP 376 implementation.""" - -from __future__ import unicode_literals - -import base64 -import codecs -import contextlib -import hashlib -import logging -import os -import posixpath -import sys -import zipimport - -from . import DistlibException, resources -from .compat import StringIO -from .version import get_scheme, UnsupportedVersionError -from .metadata import Metadata, METADATA_FILENAME -from .util import (parse_requirement, cached_property, parse_name_and_version, - read_exports, write_exports, CSVReader, CSVWriter) - - -__all__ = ['Distribution', 'BaseInstalledDistribution', - 'InstalledDistribution', 'EggInfoDistribution', - 'DistributionPath'] - - -logger = logging.getLogger(__name__) - -EXPORTS_FILENAME = 'pydist-exports.json' -COMMANDS_FILENAME = 'pydist-commands.json' - -DIST_FILES = ('INSTALLER', METADATA_FILENAME, 'RECORD', 'REQUESTED', - 'RESOURCES', EXPORTS_FILENAME, 'SHARED') - -DISTINFO_EXT = '.dist-info' - - -class _Cache(object): - """ - A simple cache mapping names and .dist-info paths to distributions - """ - def __init__(self): - """ - Initialise an instance. There is normally one for each DistributionPath. - """ - self.name = {} - self.path = {} - self.generated = False - - def clear(self): - """ - Clear the cache, setting it to its initial state. - """ - self.name.clear() - self.path.clear() - self.generated = False - - def add(self, dist): - """ - Add a distribution to the cache. - :param dist: The distribution to add. - """ - if dist.path not in self.path: - self.path[dist.path] = dist - self.name.setdefault(dist.key, []).append(dist) - - -class DistributionPath(object): - """ - Represents a set of distributions installed on a path (typically sys.path). - """ - def __init__(self, path=None, include_egg=False): - """ - Create an instance from a path, optionally including legacy (distutils/ - setuptools/distribute) distributions. - :param path: The path to use, as a list of directories. If not specified, - sys.path is used. - :param include_egg: If True, this instance will look for and return legacy - distributions as well as those based on PEP 376. - """ - if path is None: - path = sys.path - self.path = path - self._include_dist = True - self._include_egg = include_egg - - self._cache = _Cache() - self._cache_egg = _Cache() - self._cache_enabled = True - self._scheme = get_scheme('default') - - def _get_cache_enabled(self): - return self._cache_enabled - - def _set_cache_enabled(self, value): - self._cache_enabled = value - - cache_enabled = property(_get_cache_enabled, _set_cache_enabled) - - def clear_cache(self): - """ - Clears the internal cache. - """ - self._cache.clear() - self._cache_egg.clear() - - - def _yield_distributions(self): - """ - Yield .dist-info and/or .egg(-info) distributions. - """ - # We need to check if we've seen some resources already, because on - # some Linux systems (e.g. some Debian/Ubuntu variants) there are - # symlinks which alias other files in the environment. - seen = set() - for path in self.path: - finder = resources.finder_for_path(path) - if finder is None: - continue - r = finder.find('') - if not r or not r.is_container: - continue - rset = sorted(r.resources) - for entry in rset: - r = finder.find(entry) - if not r or r.path in seen: - continue - if self._include_dist and entry.endswith(DISTINFO_EXT): - metadata_path = posixpath.join(entry, METADATA_FILENAME) - pydist = finder.find(metadata_path) - if not pydist: - continue - - metadata = Metadata(fileobj=pydist.as_stream(), - scheme='legacy') - logger.debug('Found %s', r.path) - seen.add(r.path) - yield new_dist_class(r.path, metadata=metadata, - env=self) - elif self._include_egg and entry.endswith(('.egg-info', - '.egg')): - logger.debug('Found %s', r.path) - seen.add(r.path) - yield old_dist_class(r.path, self) - - def _generate_cache(self): - """ - Scan the path for distributions and populate the cache with - those that are found. - """ - gen_dist = not self._cache.generated - gen_egg = self._include_egg and not self._cache_egg.generated - if gen_dist or gen_egg: - for dist in self._yield_distributions(): - if isinstance(dist, InstalledDistribution): - self._cache.add(dist) - else: - self._cache_egg.add(dist) - - if gen_dist: - self._cache.generated = True - if gen_egg: - self._cache_egg.generated = True - - @classmethod - def distinfo_dirname(cls, name, version): - """ - The *name* and *version* parameters are converted into their - filename-escaped form, i.e. any ``'-'`` characters are replaced - with ``'_'`` other than the one in ``'dist-info'`` and the one - separating the name from the version number. - - :parameter name: is converted to a standard distribution name by replacing - any runs of non- alphanumeric characters with a single - ``'-'``. - :type name: string - :parameter version: is converted to a standard version string. Spaces - become dots, and all other non-alphanumeric characters - (except dots) become dashes, with runs of multiple - dashes condensed to a single dash. - :type version: string - :returns: directory name - :rtype: string""" - name = name.replace('-', '_') - return '-'.join([name, version]) + DISTINFO_EXT - - def get_distributions(self): - """ - Provides an iterator that looks for distributions and returns - :class:`InstalledDistribution` or - :class:`EggInfoDistribution` instances for each one of them. - - :rtype: iterator of :class:`InstalledDistribution` and - :class:`EggInfoDistribution` instances - """ - if not self._cache_enabled: - for dist in self._yield_distributions(): - yield dist - else: - self._generate_cache() - - for dist in self._cache.path.values(): - yield dist - - if self._include_egg: - for dist in self._cache_egg.path.values(): - yield dist - - def get_distribution(self, name): - """ - Looks for a named distribution on the path. - - This function only returns the first result found, as no more than one - value is expected. If nothing is found, ``None`` is returned. - - :rtype: :class:`InstalledDistribution`, :class:`EggInfoDistribution` - or ``None`` - """ - result = None - name = name.lower() - if not self._cache_enabled: - for dist in self._yield_distributions(): - if dist.key == name: - result = dist - break - else: - self._generate_cache() - - if name in self._cache.name: - result = self._cache.name[name][0] - elif self._include_egg and name in self._cache_egg.name: - result = self._cache_egg.name[name][0] - return result - - def provides_distribution(self, name, version=None): - """ - Iterates over all distributions to find which distributions provide *name*. - If a *version* is provided, it will be used to filter the results. - - This function only returns the first result found, since no more than - one values are expected. If the directory is not found, returns ``None``. - - :parameter version: a version specifier that indicates the version - required, conforming to the format in ``PEP-345`` - - :type name: string - :type version: string - """ - matcher = None - if not version is None: - try: - matcher = self._scheme.matcher('%s (%s)' % (name, version)) - except ValueError: - raise DistlibException('invalid name or version: %r, %r' % - (name, version)) - - for dist in self.get_distributions(): - provided = dist.provides - - for p in provided: - p_name, p_ver = parse_name_and_version(p) - if matcher is None: - if p_name == name: - yield dist - break - else: - if p_name == name and matcher.match(p_ver): - yield dist - break - - def get_file_path(self, name, relative_path): - """ - Return the path to a resource file. - """ - dist = self.get_distribution(name) - if dist is None: - raise LookupError('no distribution named %r found' % name) - return dist.get_resource_path(relative_path) - - def get_exported_entries(self, category, name=None): - """ - Return all of the exported entries in a particular category. - - :param category: The category to search for entries. - :param name: If specified, only entries with that name are returned. - """ - for dist in self.get_distributions(): - r = dist.exports - if category in r: - d = r[category] - if name is not None: - if name in d: - yield d[name] - else: - for v in d.values(): - yield v - - -class Distribution(object): - """ - A base class for distributions, whether installed or from indexes. - Either way, it must have some metadata, so that's all that's needed - for construction. - """ - - build_time_dependency = False - """ - Set to True if it's known to be only a build-time dependency (i.e. - not needed after installation). - """ - - requested = False - """A boolean that indicates whether the ``REQUESTED`` metadata file is - present (in other words, whether the package was installed by user - request or it was installed as a dependency).""" - - def __init__(self, metadata): - """ - Initialise an instance. - :param metadata: The instance of :class:`Metadata` describing this - distribution. - """ - self.metadata = metadata - self.name = metadata.name - self.key = self.name.lower() # for case-insensitive comparisons - self.version = metadata.version - self.locator = None - self.digest = None - self.extras = None # additional features requested - self.context = None # environment marker overrides - - @property - def source_url(self): - """ - The source archive download URL for this distribution. - """ - return self.metadata.source_url - - download_url = source_url # Backward compatibility - - @property - def name_and_version(self): - """ - A utility property which displays the name and version in parentheses. - """ - return '%s (%s)' % (self.name, self.version) - - @property - def provides(self): - """ - A set of distribution names and versions provided by this distribution. - :return: A set of "name (version)" strings. - """ - plist = self.metadata.provides - s = '%s (%s)' % (self.name, self.version) - if s not in plist: - plist.append(s) - return plist - - def _get_requirements(self, req_attr): - reqts = getattr(self.metadata, req_attr) - return set(self.metadata.get_requirements(reqts, extras=self.extras, - env=self.context)) - - @property - def run_requires(self): - return self._get_requirements('run_requires') - - @property - def meta_requires(self): - return self._get_requirements('meta_requires') - - @property - def build_requires(self): - return self._get_requirements('build_requires') - - @property - def test_requires(self): - return self._get_requirements('test_requires') - - @property - def dev_requires(self): - return self._get_requirements('dev_requires') - - def matches_requirement(self, req): - """ - Say if this instance matches (fulfills) a requirement. - :param req: The requirement to match. - :rtype req: str - :return: True if it matches, else False. - """ - # Requirement may contain extras - parse to lose those - # from what's passed to the matcher - r = parse_requirement(req) - scheme = get_scheme(self.metadata.scheme) - try: - matcher = scheme.matcher(r.requirement) - except UnsupportedVersionError: - # XXX compat-mode if cannot read the version - logger.warning('could not read version %r - using name only', - req) - name = req.split()[0] - matcher = scheme.matcher(name) - - name = matcher.key # case-insensitive - - result = False - for p in self.provides: - p_name, p_ver = parse_name_and_version(p) - if p_name != name: - continue - try: - result = matcher.match(p_ver) - break - except UnsupportedVersionError: - pass - return result - - def __repr__(self): - """ - Return a textual representation of this instance, - """ - if self.source_url: - suffix = ' [%s]' % self.source_url - else: - suffix = '' - return '' % (self.name, self.version, suffix) - - def __eq__(self, other): - """ - See if this distribution is the same as another. - :param other: The distribution to compare with. To be equal to one - another. distributions must have the same type, name, - version and source_url. - :return: True if it is the same, else False. - """ - if type(other) is not type(self): - result = False - else: - result = (self.name == other.name and - self.version == other.version and - self.source_url == other.source_url) - return result - - def __hash__(self): - """ - Compute hash in a way which matches the equality test. - """ - return hash(self.name) + hash(self.version) + hash(self.source_url) - - -class BaseInstalledDistribution(Distribution): - """ - This is the base class for installed distributions (whether PEP 376 or - legacy). - """ - - hasher = None - - def __init__(self, metadata, path, env=None): - """ - Initialise an instance. - :param metadata: An instance of :class:`Metadata` which describes the - distribution. This will normally have been initialised - from a metadata file in the ``path``. - :param path: The path of the ``.dist-info`` or ``.egg-info`` - directory for the distribution. - :param env: This is normally the :class:`DistributionPath` - instance where this distribution was found. - """ - super(BaseInstalledDistribution, self).__init__(metadata) - self.path = path - self.dist_path = env - - def get_hash(self, data, hasher=None): - """ - Get the hash of some data, using a particular hash algorithm, if - specified. - - :param data: The data to be hashed. - :type data: bytes - :param hasher: The name of a hash implementation, supported by hashlib, - or ``None``. Examples of valid values are ``'sha1'``, - ``'sha224'``, ``'sha384'``, '``sha256'``, ``'md5'`` and - ``'sha512'``. If no hasher is specified, the ``hasher`` - attribute of the :class:`InstalledDistribution` instance - is used. If the hasher is determined to be ``None``, MD5 - is used as the hashing algorithm. - :returns: The hash of the data. If a hasher was explicitly specified, - the returned hash will be prefixed with the specified hasher - followed by '='. - :rtype: str - """ - if hasher is None: - hasher = self.hasher - if hasher is None: - hasher = hashlib.md5 - prefix = '' - else: - hasher = getattr(hashlib, hasher) - prefix = '%s=' % self.hasher - digest = hasher(data).digest() - digest = base64.urlsafe_b64encode(digest).rstrip(b'=').decode('ascii') - return '%s%s' % (prefix, digest) - - -class InstalledDistribution(BaseInstalledDistribution): - """ - Created with the *path* of the ``.dist-info`` directory provided to the - constructor. It reads the metadata contained in ``pydist.json`` when it is - instantiated., or uses a passed in Metadata instance (useful for when - dry-run mode is being used). - """ - - hasher = 'sha256' - - def __init__(self, path, metadata=None, env=None): - self.finder = finder = resources.finder_for_path(path) - if finder is None: - import pdb; pdb.set_trace () - if env and env._cache_enabled and path in env._cache.path: - metadata = env._cache.path[path].metadata - elif metadata is None: - r = finder.find(METADATA_FILENAME) - # Temporary - for legacy support - if r is None: - r = finder.find('METADATA') - if r is None: - raise ValueError('no %s found in %s' % (METADATA_FILENAME, - path)) - with contextlib.closing(r.as_stream()) as stream: - metadata = Metadata(fileobj=stream, scheme='legacy') - - super(InstalledDistribution, self).__init__(metadata, path, env) - - if env and env._cache_enabled: - env._cache.add(self) - - try: - r = finder.find('REQUESTED') - except AttributeError: - import pdb; pdb.set_trace () - self.requested = r is not None - - def __repr__(self): - return '' % ( - self.name, self.version, self.path) - - def __str__(self): - return "%s %s" % (self.name, self.version) - - def _get_records(self): - """ - Get the list of installed files for the distribution - :return: A list of tuples of path, hash and size. Note that hash and - size might be ``None`` for some entries. The path is exactly - as stored in the file (which is as in PEP 376). - """ - results = [] - r = self.get_distinfo_resource('RECORD') - with contextlib.closing(r.as_stream()) as stream: - with CSVReader(stream=stream) as record_reader: - # Base location is parent dir of .dist-info dir - #base_location = os.path.dirname(self.path) - #base_location = os.path.abspath(base_location) - for row in record_reader: - missing = [None for i in range(len(row), 3)] - path, checksum, size = row + missing - #if not os.path.isabs(path): - # path = path.replace('/', os.sep) - # path = os.path.join(base_location, path) - results.append((path, checksum, size)) - return results - - @cached_property - def exports(self): - """ - Return the information exported by this distribution. - :return: A dictionary of exports, mapping an export category to a dict - of :class:`ExportEntry` instances describing the individual - export entries, and keyed by name. - """ - result = {} - r = self.get_distinfo_resource(EXPORTS_FILENAME) - if r: - result = self.read_exports() - return result - - def read_exports(self): - """ - Read exports data from a file in .ini format. - - :return: A dictionary of exports, mapping an export category to a list - of :class:`ExportEntry` instances describing the individual - export entries. - """ - result = {} - r = self.get_distinfo_resource(EXPORTS_FILENAME) - if r: - with contextlib.closing(r.as_stream()) as stream: - result = read_exports(stream) - return result - - def write_exports(self, exports): - """ - Write a dictionary of exports to a file in .ini format. - :param exports: A dictionary of exports, mapping an export category to - a list of :class:`ExportEntry` instances describing the - individual export entries. - """ - rf = self.get_distinfo_file(EXPORTS_FILENAME) - with open(rf, 'w') as f: - write_exports(exports, f) - - def get_resource_path(self, relative_path): - """ - NOTE: This API may change in the future. - - Return the absolute path to a resource file with the given relative - path. - - :param relative_path: The path, relative to .dist-info, of the resource - of interest. - :return: The absolute path where the resource is to be found. - """ - r = self.get_distinfo_resource('RESOURCES') - with contextlib.closing(r.as_stream()) as stream: - with CSVReader(stream=stream) as resources_reader: - for relative, destination in resources_reader: - if relative == relative_path: - return destination - raise KeyError('no resource file with relative path %r ' - 'is installed' % relative_path) - - def list_installed_files(self): - """ - Iterates over the ``RECORD`` entries and returns a tuple - ``(path, hash, size)`` for each line. - - :returns: iterator of (path, hash, size) - """ - for result in self._get_records(): - yield result - - def write_installed_files(self, paths, prefix, dry_run=False): - """ - Writes the ``RECORD`` file, using the ``paths`` iterable passed in. Any - existing ``RECORD`` file is silently overwritten. - - prefix is used to determine when to write absolute paths. - """ - prefix = os.path.join(prefix, '') - base = os.path.dirname(self.path) - base_under_prefix = base.startswith(prefix) - base = os.path.join(base, '') - record_path = self.get_distinfo_file('RECORD') - logger.info('creating %s', record_path) - if dry_run: - return None - with CSVWriter(record_path) as writer: - for path in paths: - if os.path.isdir(path) or path.endswith(('.pyc', '.pyo')): - # do not put size and hash, as in PEP-376 - hash_value = size = '' - else: - size = '%d' % os.path.getsize(path) - with open(path, 'rb') as fp: - hash_value = self.get_hash(fp.read()) - if path.startswith(base) or (base_under_prefix and - path.startswith(prefix)): - path = os.path.relpath(path, base) - writer.writerow((path, hash_value, size)) - - # add the RECORD file itself - if record_path.startswith(base): - record_path = os.path.relpath(record_path, base) - writer.writerow((record_path, '', '')) - return record_path - - def check_installed_files(self): - """ - Checks that the hashes and sizes of the files in ``RECORD`` are - matched by the files themselves. Returns a (possibly empty) list of - mismatches. Each entry in the mismatch list will be a tuple consisting - of the path, 'exists', 'size' or 'hash' according to what didn't match - (existence is checked first, then size, then hash), the expected - value and the actual value. - """ - mismatches = [] - base = os.path.dirname(self.path) - record_path = self.get_distinfo_file('RECORD') - for path, hash_value, size in self.list_installed_files(): - if not os.path.isabs(path): - path = os.path.join(base, path) - if path == record_path: - continue - if not os.path.exists(path): - mismatches.append((path, 'exists', True, False)) - elif os.path.isfile(path): - actual_size = str(os.path.getsize(path)) - if size and actual_size != size: - mismatches.append((path, 'size', size, actual_size)) - elif hash_value: - if '=' in hash_value: - hasher = hash_value.split('=', 1)[0] - else: - hasher = None - - with open(path, 'rb') as f: - actual_hash = self.get_hash(f.read(), hasher) - if actual_hash != hash_value: - mismatches.append((path, 'hash', hash_value, actual_hash)) - return mismatches - - @cached_property - def shared_locations(self): - """ - A dictionary of shared locations whose keys are in the set 'prefix', - 'purelib', 'platlib', 'scripts', 'headers', 'data' and 'namespace'. - The corresponding value is the absolute path of that category for - this distribution, and takes into account any paths selected by the - user at installation time (e.g. via command-line arguments). In the - case of the 'namespace' key, this would be a list of absolute paths - for the roots of namespace packages in this distribution. - - The first time this property is accessed, the relevant information is - read from the SHARED file in the .dist-info directory. - """ - result = {} - shared_path = os.path.join(self.path, 'SHARED') - if os.path.isfile(shared_path): - with codecs.open(shared_path, 'r', encoding='utf-8') as f: - lines = f.read().splitlines() - for line in lines: - key, value = line.split('=', 1) - if key == 'namespace': - result.setdefault(key, []).append(value) - else: - result[key] = value - return result - - def write_shared_locations(self, paths, dry_run=False): - """ - Write shared location information to the SHARED file in .dist-info. - :param paths: A dictionary as described in the documentation for - :meth:`shared_locations`. - :param dry_run: If True, the action is logged but no file is actually - written. - :return: The path of the file written to. - """ - shared_path = os.path.join(self.path, 'SHARED') - logger.info('creating %s', shared_path) - if dry_run: - return None - lines = [] - for key in ('prefix', 'lib', 'headers', 'scripts', 'data'): - path = paths[key] - if os.path.isdir(paths[key]): - lines.append('%s=%s' % (key, path)) - for ns in paths.get('namespace', ()): - lines.append('namespace=%s' % ns) - - with codecs.open(shared_path, 'w', encoding='utf-8') as f: - f.write('\n'.join(lines)) - return shared_path - - def get_distinfo_resource(self, path): - if path not in DIST_FILES: - raise DistlibException('invalid path for a dist-info file: ' - '%r at %r' % (path, self.path)) - finder = resources.finder_for_path(self.path) - if finder is None: - raise DistlibException('Unable to get a finder for %s' % self.path) - return finder.find(path) - - def get_distinfo_file(self, path): - """ - Returns a path located under the ``.dist-info`` directory. Returns a - string representing the path. - - :parameter path: a ``'/'``-separated path relative to the - ``.dist-info`` directory or an absolute path; - If *path* is an absolute path and doesn't start - with the ``.dist-info`` directory path, - a :class:`DistlibException` is raised - :type path: str - :rtype: str - """ - # Check if it is an absolute path # XXX use relpath, add tests - if path.find(os.sep) >= 0: - # it's an absolute path? - distinfo_dirname, path = path.split(os.sep)[-2:] - if distinfo_dirname != self.path.split(os.sep)[-1]: - raise DistlibException( - 'dist-info file %r does not belong to the %r %s ' - 'distribution' % (path, self.name, self.version)) - - # The file must be relative - if path not in DIST_FILES: - raise DistlibException('invalid path for a dist-info file: ' - '%r at %r' % (path, self.path)) - - return os.path.join(self.path, path) - - def list_distinfo_files(self): - """ - Iterates over the ``RECORD`` entries and returns paths for each line if - the path is pointing to a file located in the ``.dist-info`` directory - or one of its subdirectories. - - :returns: iterator of paths - """ - base = os.path.dirname(self.path) - for path, checksum, size in self._get_records(): - # XXX add separator or use real relpath algo - if not os.path.isabs(path): - path = os.path.join(base, path) - if path.startswith(self.path): - yield path - - def __eq__(self, other): - return (isinstance(other, InstalledDistribution) and - self.path == other.path) - - # See http://docs.python.org/reference/datamodel#object.__hash__ - __hash__ = object.__hash__ - - -class EggInfoDistribution(BaseInstalledDistribution): - """Created with the *path* of the ``.egg-info`` directory or file provided - to the constructor. It reads the metadata contained in the file itself, or - if the given path happens to be a directory, the metadata is read from the - file ``PKG-INFO`` under that directory.""" - - requested = True # as we have no way of knowing, assume it was - shared_locations = {} - - def __init__(self, path, env=None): - def set_name_and_version(s, n, v): - s.name = n - s.key = n.lower() # for case-insensitive comparisons - s.version = v - - self.path = path - self.dist_path = env - if env and env._cache_enabled and path in env._cache_egg.path: - metadata = env._cache_egg.path[path].metadata - set_name_and_version(self, metadata.name, metadata.version) - else: - metadata = self._get_metadata(path) - - # Need to be set before caching - set_name_and_version(self, metadata.name, metadata.version) - - if env and env._cache_enabled: - env._cache_egg.add(self) - super(EggInfoDistribution, self).__init__(metadata, path, env) - - def _get_metadata(self, path): - requires = None - - def parse_requires_data(data): - """Create a list of dependencies from a requires.txt file. - - *data*: the contents of a setuptools-produced requires.txt file. - """ - reqs = [] - lines = data.splitlines() - for line in lines: - line = line.strip() - if line.startswith('['): - logger.warning('Unexpected line: quitting requirement scan: %r', - line) - break - r = parse_requirement(line) - if not r: - logger.warning('Not recognised as a requirement: %r', line) - continue - if r.extras: - logger.warning('extra requirements in requires.txt are ' - 'not supported') - if not r.constraints: - reqs.append(r.name) - else: - cons = ', '.join('%s%s' % c for c in r.constraints) - reqs.append('%s (%s)' % (r.name, cons)) - return reqs - - def parse_requires_path(req_path): - """Create a list of dependencies from a requires.txt file. - - *req_path*: the path to a setuptools-produced requires.txt file. - """ - - reqs = [] - try: - with codecs.open(req_path, 'r', 'utf-8') as fp: - reqs = parse_requires_data(fp.read()) - except IOError: - pass - return reqs - - if path.endswith('.egg'): - if os.path.isdir(path): - meta_path = os.path.join(path, 'EGG-INFO', 'PKG-INFO') - metadata = Metadata(path=meta_path, scheme='legacy') - req_path = os.path.join(path, 'EGG-INFO', 'requires.txt') - requires = parse_requires_path(req_path) - else: - # FIXME handle the case where zipfile is not available - zipf = zipimport.zipimporter(path) - fileobj = StringIO( - zipf.get_data('EGG-INFO/PKG-INFO').decode('utf8')) - metadata = Metadata(fileobj=fileobj, scheme='legacy') - try: - data = zipf.get_data('EGG-INFO/requires.txt') - requires = parse_requires_data(data.decode('utf-8')) - except IOError: - requires = None - elif path.endswith('.egg-info'): - if os.path.isdir(path): - path = os.path.join(path, 'PKG-INFO') - req_path = os.path.join(path, 'requires.txt') - requires = parse_requires_path(req_path) - metadata = Metadata(path=path, scheme='legacy') - else: - raise DistlibException('path must end with .egg-info or .egg, ' - 'got %r' % path) - - if requires: - metadata.add_requirements(requires) - return metadata - - def __repr__(self): - return '' % ( - self.name, self.version, self.path) - - def __str__(self): - return "%s %s" % (self.name, self.version) - - def check_installed_files(self): - """ - Checks that the hashes and sizes of the files in ``RECORD`` are - matched by the files themselves. Returns a (possibly empty) list of - mismatches. Each entry in the mismatch list will be a tuple consisting - of the path, 'exists', 'size' or 'hash' according to what didn't match - (existence is checked first, then size, then hash), the expected - value and the actual value. - """ - mismatches = [] - record_path = os.path.join(self.path, 'installed-files.txt') - if os.path.exists(record_path): - for path, _, _ in self.list_installed_files(): - if path == record_path: - continue - if not os.path.exists(path): - mismatches.append((path, 'exists', True, False)) - return mismatches - - def list_installed_files(self): - """ - Iterates over the ``installed-files.txt`` entries and returns a tuple - ``(path, hash, size)`` for each line. - - :returns: a list of (path, hash, size) - """ - - def _md5(path): - f = open(path, 'rb') - try: - content = f.read() - finally: - f.close() - return hashlib.md5(content).hexdigest() - - def _size(path): - return os.stat(path).st_size - - record_path = os.path.join(self.path, 'installed-files.txt') - result = [] - if os.path.exists(record_path): - with codecs.open(record_path, 'r', encoding='utf-8') as f: - for line in f: - line = line.strip() - p = os.path.normpath(os.path.join(self.path, line)) - # "./" is present as a marker between installed files - # and installation metadata files - if not os.path.exists(p): - logger.warning('Non-existent file: %s', p) - if p.endswith(('.pyc', '.pyo')): - continue - #otherwise fall through and fail - if not os.path.isdir(p): - result.append((p, _md5(p), _size(p))) - result.append((record_path, None, None)) - return result - - def list_distinfo_files(self, absolute=False): - """ - Iterates over the ``installed-files.txt`` entries and returns paths for - each line if the path is pointing to a file located in the - ``.egg-info`` directory or one of its subdirectories. - - :parameter absolute: If *absolute* is ``True``, each returned path is - transformed into a local absolute path. Otherwise the - raw value from ``installed-files.txt`` is returned. - :type absolute: boolean - :returns: iterator of paths - """ - record_path = os.path.join(self.path, 'installed-files.txt') - skip = True - with codecs.open(record_path, 'r', encoding='utf-8') as f: - for line in f: - line = line.strip() - if line == './': - skip = False - continue - if not skip: - p = os.path.normpath(os.path.join(self.path, line)) - if p.startswith(self.path): - if absolute: - yield p - else: - yield line - - def __eq__(self, other): - return (isinstance(other, EggInfoDistribution) and - self.path == other.path) - - # See http://docs.python.org/reference/datamodel#object.__hash__ - __hash__ = object.__hash__ - -new_dist_class = InstalledDistribution -old_dist_class = EggInfoDistribution - - -class DependencyGraph(object): - """ - Represents a dependency graph between distributions. - - The dependency relationships are stored in an ``adjacency_list`` that maps - distributions to a list of ``(other, label)`` tuples where ``other`` - is a distribution and the edge is labeled with ``label`` (i.e. the version - specifier, if such was provided). Also, for more efficient traversal, for - every distribution ``x``, a list of predecessors is kept in - ``reverse_list[x]``. An edge from distribution ``a`` to - distribution ``b`` means that ``a`` depends on ``b``. If any missing - dependencies are found, they are stored in ``missing``, which is a - dictionary that maps distributions to a list of requirements that were not - provided by any other distributions. - """ - - def __init__(self): - self.adjacency_list = {} - self.reverse_list = {} - self.missing = {} - - def add_distribution(self, distribution): - """Add the *distribution* to the graph. - - :type distribution: :class:`distutils2.database.InstalledDistribution` - or :class:`distutils2.database.EggInfoDistribution` - """ - self.adjacency_list[distribution] = [] - self.reverse_list[distribution] = [] - #self.missing[distribution] = [] - - def add_edge(self, x, y, label=None): - """Add an edge from distribution *x* to distribution *y* with the given - *label*. - - :type x: :class:`distutils2.database.InstalledDistribution` or - :class:`distutils2.database.EggInfoDistribution` - :type y: :class:`distutils2.database.InstalledDistribution` or - :class:`distutils2.database.EggInfoDistribution` - :type label: ``str`` or ``None`` - """ - self.adjacency_list[x].append((y, label)) - # multiple edges are allowed, so be careful - if x not in self.reverse_list[y]: - self.reverse_list[y].append(x) - - def add_missing(self, distribution, requirement): - """ - Add a missing *requirement* for the given *distribution*. - - :type distribution: :class:`distutils2.database.InstalledDistribution` - or :class:`distutils2.database.EggInfoDistribution` - :type requirement: ``str`` - """ - logger.debug('%s missing %r', distribution, requirement) - self.missing.setdefault(distribution, []).append(requirement) - - def _repr_dist(self, dist): - return '%s %s' % (dist.name, dist.version) - - def repr_node(self, dist, level=1): - """Prints only a subgraph""" - output = [self._repr_dist(dist)] - for other, label in self.adjacency_list[dist]: - dist = self._repr_dist(other) - if label is not None: - dist = '%s [%s]' % (dist, label) - output.append(' ' * level + str(dist)) - suboutput = self.repr_node(other, level + 1) - subs = suboutput.split('\n') - output.extend(subs[1:]) - return '\n'.join(output) - - def to_dot(self, f, skip_disconnected=True): - """Writes a DOT output for the graph to the provided file *f*. - - If *skip_disconnected* is set to ``True``, then all distributions - that are not dependent on any other distribution are skipped. - - :type f: has to support ``file``-like operations - :type skip_disconnected: ``bool`` - """ - disconnected = [] - - f.write("digraph dependencies {\n") - for dist, adjs in self.adjacency_list.items(): - if len(adjs) == 0 and not skip_disconnected: - disconnected.append(dist) - for other, label in adjs: - if not label is None: - f.write('"%s" -> "%s" [label="%s"]\n' % - (dist.name, other.name, label)) - else: - f.write('"%s" -> "%s"\n' % (dist.name, other.name)) - if not skip_disconnected and len(disconnected) > 0: - f.write('subgraph disconnected {\n') - f.write('label = "Disconnected"\n') - f.write('bgcolor = red\n') - - for dist in disconnected: - f.write('"%s"' % dist.name) - f.write('\n') - f.write('}\n') - f.write('}\n') - - def topological_sort(self): - """ - Perform a topological sort of the graph. - :return: A tuple, the first element of which is a topologically sorted - list of distributions, and the second element of which is a - list of distributions that cannot be sorted because they have - circular dependencies and so form a cycle. - """ - result = [] - # Make a shallow copy of the adjacency list - alist = {} - for k, v in self.adjacency_list.items(): - alist[k] = v[:] - while True: - # See what we can remove in this run - to_remove = [] - for k, v in list(alist.items())[:]: - if not v: - to_remove.append(k) - del alist[k] - if not to_remove: - # What's left in alist (if anything) is a cycle. - break - # Remove from the adjacency list of others - for k, v in alist.items(): - alist[k] = [(d, r) for d, r in v if d not in to_remove] - logger.debug('Moving to result: %s', - ['%s (%s)' % (d.name, d.version) for d in to_remove]) - result.extend(to_remove) - return result, list(alist.keys()) - - def __repr__(self): - """Representation of the graph""" - output = [] - for dist, adjs in self.adjacency_list.items(): - output.append(self.repr_node(dist)) - return '\n'.join(output) - - -def make_graph(dists, scheme='default'): - """Makes a dependency graph from the given distributions. - - :parameter dists: a list of distributions - :type dists: list of :class:`distutils2.database.InstalledDistribution` and - :class:`distutils2.database.EggInfoDistribution` instances - :rtype: a :class:`DependencyGraph` instance - """ - scheme = get_scheme(scheme) - graph = DependencyGraph() - provided = {} # maps names to lists of (version, dist) tuples - - # first, build the graph and find out what's provided - for dist in dists: - graph.add_distribution(dist) - - for p in dist.provides: - name, version = parse_name_and_version(p) - logger.debug('Add to provided: %s, %s, %s', name, version, dist) - provided.setdefault(name, []).append((version, dist)) - - # now make the edges - for dist in dists: - requires = (dist.run_requires | dist.meta_requires | - dist.build_requires | dist.dev_requires) - for req in requires: - try: - matcher = scheme.matcher(req) - except UnsupportedVersionError: - # XXX compat-mode if cannot read the version - logger.warning('could not read version %r - using name only', - req) - name = req.split()[0] - matcher = scheme.matcher(name) - - name = matcher.key # case-insensitive - - matched = False - if name in provided: - for version, provider in provided[name]: - try: - match = matcher.match(version) - except UnsupportedVersionError: - match = False - - if match: - graph.add_edge(dist, provider, req) - matched = True - break - if not matched: - graph.add_missing(dist, req) - return graph - - -def get_dependent_dists(dists, dist): - """Recursively generate a list of distributions from *dists* that are - dependent on *dist*. - - :param dists: a list of distributions - :param dist: a distribution, member of *dists* for which we are interested - """ - if dist not in dists: - raise DistlibException('given distribution %r is not a member ' - 'of the list' % dist.name) - graph = make_graph(dists) - - dep = [dist] # dependent distributions - todo = graph.reverse_list[dist] # list of nodes we should inspect - - while todo: - d = todo.pop() - dep.append(d) - for succ in graph.reverse_list[d]: - if succ not in dep: - todo.append(succ) - - dep.pop(0) # remove dist from dep, was there to prevent infinite loops - return dep - - -def get_required_dists(dists, dist): - """Recursively generate a list of distributions from *dists* that are - required by *dist*. - - :param dists: a list of distributions - :param dist: a distribution, member of *dists* for which we are interested - """ - if dist not in dists: - raise DistlibException('given distribution %r is not a member ' - 'of the list' % dist.name) - graph = make_graph(dists) - - req = [] # required distributions - todo = graph.adjacency_list[dist] # list of nodes we should inspect - - while todo: - d = todo.pop()[0] - req.append(d) - for pred in graph.adjacency_list[d]: - if pred not in req: - todo.append(pred) - - return req - - -def make_dist(name, version, **kwargs): - """ - A convenience method for making a dist given just a name and version. - """ - summary = kwargs.pop('summary', 'Placeholder for summary') - md = Metadata(**kwargs) - md.name = name - md.version = version - md.summary = summary or 'Plaeholder for summary' - return Distribution(md) diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/index.py b/vendor/pip-1.5.6/pip/_vendor/distlib/index.py deleted file mode 100644 index 83004b1..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/distlib/index.py +++ /dev/null @@ -1,488 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2013 Vinay Sajip. -# Licensed to the Python Software Foundation under a contributor agreement. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -import hashlib -import logging -import os -import shutil -import subprocess -import tempfile -try: - from threading import Thread -except ImportError: - from dummy_threading import Thread - -from . import DistlibException -from .compat import (HTTPBasicAuthHandler, Request, HTTPPasswordMgr, - urlparse, build_opener, string_types) -from .util import cached_property, zip_dir, ServerProxy - -logger = logging.getLogger(__name__) - -DEFAULT_INDEX = 'https://pypi.python.org/pypi' -DEFAULT_REALM = 'pypi' - -class PackageIndex(object): - """ - This class represents a package index compatible with PyPI, the Python - Package Index. - """ - - boundary = b'----------ThIs_Is_tHe_distlib_index_bouNdaRY_$' - - def __init__(self, url=None): - """ - Initialise an instance. - - :param url: The URL of the index. If not specified, the URL for PyPI is - used. - """ - self.url = url or DEFAULT_INDEX - self.read_configuration() - scheme, netloc, path, params, query, frag = urlparse(self.url) - if params or query or frag or scheme not in ('http', 'https'): - raise DistlibException('invalid repository: %s' % self.url) - self.password_handler = None - self.ssl_verifier = None - self.gpg = None - self.gpg_home = None - self.rpc_proxy = None - with open(os.devnull, 'w') as sink: - for s in ('gpg2', 'gpg'): - try: - rc = subprocess.check_call([s, '--version'], stdout=sink, - stderr=sink) - if rc == 0: - self.gpg = s - break - except OSError: - pass - - def _get_pypirc_command(self): - """ - Get the distutils command for interacting with PyPI configurations. - :return: the command. - """ - from distutils.core import Distribution - from distutils.config import PyPIRCCommand - d = Distribution() - return PyPIRCCommand(d) - - def read_configuration(self): - """ - Read the PyPI access configuration as supported by distutils, getting - PyPI to do the acutal work. This populates ``username``, ``password``, - ``realm`` and ``url`` attributes from the configuration. - """ - # get distutils to do the work - c = self._get_pypirc_command() - c.repository = self.url - cfg = c._read_pypirc() - self.username = cfg.get('username') - self.password = cfg.get('password') - self.realm = cfg.get('realm', 'pypi') - self.url = cfg.get('repository', self.url) - - def save_configuration(self): - """ - Save the PyPI access configuration. You must have set ``username`` and - ``password`` attributes before calling this method. - - Again, distutils is used to do the actual work. - """ - self.check_credentials() - # get distutils to do the work - c = self._get_pypirc_command() - c._store_pypirc(self.username, self.password) - - def check_credentials(self): - """ - Check that ``username`` and ``password`` have been set, and raise an - exception if not. - """ - if self.username is None or self.password is None: - raise DistlibException('username and password must be set') - pm = HTTPPasswordMgr() - _, netloc, _, _, _, _ = urlparse(self.url) - pm.add_password(self.realm, netloc, self.username, self.password) - self.password_handler = HTTPBasicAuthHandler(pm) - - def register(self, metadata): - """ - Register a distribution on PyPI, using the provided metadata. - - :param metadata: A :class:`Metadata` instance defining at least a name - and version number for the distribution to be - registered. - :return: The HTTP response received from PyPI upon submission of the - request. - """ - self.check_credentials() - metadata.validate() - d = metadata.todict() - d[':action'] = 'verify' - request = self.encode_request(d.items(), []) - response = self.send_request(request) - d[':action'] = 'submit' - request = self.encode_request(d.items(), []) - return self.send_request(request) - - def _reader(self, name, stream, outbuf): - """ - Thread runner for reading lines of from a subprocess into a buffer. - - :param name: The logical name of the stream (used for logging only). - :param stream: The stream to read from. This will typically a pipe - connected to the output stream of a subprocess. - :param outbuf: The list to append the read lines to. - """ - while True: - s = stream.readline() - if not s: - break - s = s.decode('utf-8').rstrip() - outbuf.append(s) - logger.debug('%s: %s' % (name, s)) - stream.close() - - def get_sign_command(self, filename, signer, sign_password): - """ - Return a suitable command for signing a file. - - :param filename: The pathname to the file to be signed. - :param signer: The identifier of the signer of the file. - :param sign_password: The passphrase for the signer's - private key used for signing. - :return: The signing command as a list suitable to be - passed to :class:`subprocess.Popen`. - """ - cmd = [self.gpg, '--status-fd', '2', '--no-tty'] - if self.gpg_home: - cmd.extend(['--homedir', self.gpg_home]) - if sign_password is not None: - cmd.extend(['--batch', '--passphrase-fd', '0']) - td = tempfile.mkdtemp() - sf = os.path.join(td, os.path.basename(filename) + '.asc') - cmd.extend(['--detach-sign', '--armor', '--local-user', - signer, '--output', sf, filename]) - logger.debug('invoking: %s', ' '.join(cmd)) - return cmd, sf - - def run_command(self, cmd, input_data=None): - """ - Run a command in a child process , passing it any input data specified. - - :param cmd: The command to run. - :param input_data: If specified, this must be a byte string containing - data to be sent to the child process. - :return: A tuple consisting of the subprocess' exit code, a list of - lines read from the subprocess' ``stdout``, and a list of - lines read from the subprocess' ``stderr``. - """ - kwargs = { - 'stdout': subprocess.PIPE, - 'stderr': subprocess.PIPE, - } - if input_data is not None: - kwargs['stdin'] = subprocess.PIPE - stdout = [] - stderr = [] - p = subprocess.Popen(cmd, **kwargs) - # We don't use communicate() here because we may need to - # get clever with interacting with the command - t1 = Thread(target=self._reader, args=('stdout', p.stdout, stdout)) - t1.start() - t2 = Thread(target=self._reader, args=('stderr', p.stderr, stderr)) - t2.start() - if input_data is not None: - p.stdin.write(input_data) - p.stdin.close() - - p.wait() - t1.join() - t2.join() - return p.returncode, stdout, stderr - - def sign_file(self, filename, signer, sign_password): - """ - Sign a file. - - :param filename: The pathname to the file to be signed. - :param signer: The identifier of the signer of the file. - :param sign_password: The passphrase for the signer's - private key used for signing. - :return: The absolute pathname of the file where the signature is - stored. - """ - cmd, sig_file = self.get_sign_command(filename, signer, sign_password) - rc, stdout, stderr = self.run_command(cmd, - sign_password.encode('utf-8')) - if rc != 0: - raise DistlibException('sign command failed with error ' - 'code %s' % rc) - return sig_file - - def upload_file(self, metadata, filename, signer=None, sign_password=None, - filetype='sdist', pyversion='source'): - """ - Upload a release file to the index. - - :param metadata: A :class:`Metadata` instance defining at least a name - and version number for the file to be uploaded. - :param filename: The pathname of the file to be uploaded. - :param signer: The identifier of the signer of the file. - :param sign_password: The passphrase for the signer's - private key used for signing. - :param filetype: The type of the file being uploaded. This is the - distutils command which produced that file, e.g. - ``sdist`` or ``bdist_wheel``. - :param pyversion: The version of Python which the release relates - to. For code compatible with any Python, this would - be ``source``, otherwise it would be e.g. ``3.2``. - :return: The HTTP response received from PyPI upon submission of the - request. - """ - self.check_credentials() - if not os.path.exists(filename): - raise DistlibException('not found: %s' % filename) - metadata.validate() - d = metadata.todict() - sig_file = None - if signer: - if not self.gpg: - logger.warning('no signing program available - not signed') - else: - sig_file = self.sign_file(filename, signer, sign_password) - with open(filename, 'rb') as f: - file_data = f.read() - md5_digest = hashlib.md5(file_data).hexdigest() - sha256_digest = hashlib.sha256(file_data).hexdigest() - d.update({ - ':action': 'file_upload', - 'protcol_version': '1', - 'filetype': filetype, - 'pyversion': pyversion, - 'md5_digest': md5_digest, - 'sha256_digest': sha256_digest, - }) - files = [('content', os.path.basename(filename), file_data)] - if sig_file: - with open(sig_file, 'rb') as f: - sig_data = f.read() - files.append(('gpg_signature', os.path.basename(sig_file), - sig_data)) - shutil.rmtree(os.path.dirname(sig_file)) - request = self.encode_request(d.items(), files) - return self.send_request(request) - - def upload_documentation(self, metadata, doc_dir): - """ - Upload documentation to the index. - - :param metadata: A :class:`Metadata` instance defining at least a name - and version number for the documentation to be - uploaded. - :param doc_dir: The pathname of the directory which contains the - documentation. This should be the directory that - contains the ``index.html`` for the documentation. - :return: The HTTP response received from PyPI upon submission of the - request. - """ - self.check_credentials() - if not os.path.isdir(doc_dir): - raise DistlibException('not a directory: %r' % doc_dir) - fn = os.path.join(doc_dir, 'index.html') - if not os.path.exists(fn): - raise DistlibException('not found: %r' % fn) - metadata.validate() - name, version = metadata.name, metadata.version - zip_data = zip_dir(doc_dir).getvalue() - fields = [(':action', 'doc_upload'), - ('name', name), ('version', version)] - files = [('content', name, zip_data)] - request = self.encode_request(fields, files) - return self.send_request(request) - - def get_verify_command(self, signature_filename, data_filename): - """ - Return a suitable command for verifying a file. - - :param signature_filename: The pathname to the file containing the - signature. - :param data_filename: The pathname to the file containing the - signed data. - :return: The verifying command as a list suitable to be - passed to :class:`subprocess.Popen`. - """ - cmd = [self.gpg, '--status-fd', '2', '--no-tty'] - if self.gpg_home: - cmd.extend(['--homedir', self.gpg_home]) - cmd.extend(['--verify', signature_filename, data_filename]) - logger.debug('invoking: %s', ' '.join(cmd)) - return cmd - - def verify_signature(self, signature_filename, data_filename): - """ - Verify a signature for a file. - - :param signature_filename: The pathname to the file containing the - signature. - :param data_filename: The pathname to the file containing the - signed data. - :return: True if the signature was verified, else False. - """ - if not self.gpg: - raise DistlibException('verification unavailable because gpg ' - 'unavailable') - cmd = self.get_verify_command(signature_filename, data_filename) - rc, stdout, stderr = self.run_command(cmd) - if rc not in (0, 1): - raise DistlibException('verify command failed with error ' - 'code %s' % rc) - return rc == 0 - - def download_file(self, url, destfile, digest=None, reporthook=None): - """ - This is a convenience method for downloading a file from an URL. - Normally, this will be a file from the index, though currently - no check is made for this (i.e. a file can be downloaded from - anywhere). - - The method is just like the :func:`urlretrieve` function in the - standard library, except that it allows digest computation to be - done during download and checking that the downloaded data - matched any expected value. - - :param url: The URL of the file to be downloaded (assumed to be - available via an HTTP GET request). - :param destfile: The pathname where the downloaded file is to be - saved. - :param digest: If specified, this must be a (hasher, value) - tuple, where hasher is the algorithm used (e.g. - ``'md5'``) and ``value`` is the expected value. - :param reporthook: The same as for :func:`urlretrieve` in the - standard library. - """ - if digest is None: - digester = None - logger.debug('No digest specified') - else: - if isinstance(digest, (list, tuple)): - hasher, digest = digest - else: - hasher = 'md5' - digester = getattr(hashlib, hasher)() - logger.debug('Digest specified: %s' % digest) - # The following code is equivalent to urlretrieve. - # We need to do it this way so that we can compute the - # digest of the file as we go. - with open(destfile, 'wb') as dfp: - # addinfourl is not a context manager on 2.x - # so we have to use try/finally - sfp = self.send_request(Request(url)) - try: - headers = sfp.info() - blocksize = 8192 - size = -1 - read = 0 - blocknum = 0 - if "content-length" in headers: - size = int(headers["Content-Length"]) - if reporthook: - reporthook(blocknum, blocksize, size) - while True: - block = sfp.read(blocksize) - if not block: - break - read += len(block) - dfp.write(block) - if digester: - digester.update(block) - blocknum += 1 - if reporthook: - reporthook(blocknum, blocksize, size) - finally: - sfp.close() - - # check that we got the whole file, if we can - if size >= 0 and read < size: - raise DistlibException( - 'retrieval incomplete: got only %d out of %d bytes' - % (read, size)) - # if we have a digest, it must match. - if digester: - actual = digester.hexdigest() - if digest != actual: - raise DistlibException('%s digest mismatch for %s: expected ' - '%s, got %s' % (hasher, destfile, - digest, actual)) - logger.debug('Digest verified: %s', digest) - - def send_request(self, req): - """ - Send a standard library :class:`Request` to PyPI and return its - response. - - :param req: The request to send. - :return: The HTTP response from PyPI (a standard library HTTPResponse). - """ - handlers = [] - if self.password_handler: - handlers.append(self.password_handler) - if self.ssl_verifier: - handlers.append(self.ssl_verifier) - opener = build_opener(*handlers) - return opener.open(req) - - def encode_request(self, fields, files): - """ - Encode fields and files for posting to an HTTP server. - - :param fields: The fields to send as a list of (fieldname, value) - tuples. - :param files: The files to send as a list of (fieldname, filename, - file_bytes) tuple. - """ - # Adapted from packaging, which in turn was adapted from - # http://code.activestate.com/recipes/146306 - - parts = [] - boundary = self.boundary - for k, values in fields: - if not isinstance(values, (list, tuple)): - values = [values] - - for v in values: - parts.extend(( - b'--' + boundary, - ('Content-Disposition: form-data; name="%s"' % - k).encode('utf-8'), - b'', - v.encode('utf-8'))) - for key, filename, value in files: - parts.extend(( - b'--' + boundary, - ('Content-Disposition: form-data; name="%s"; filename="%s"' % - (key, filename)).encode('utf-8'), - b'', - value)) - - parts.extend((b'--' + boundary + b'--', b'')) - - body = b'\r\n'.join(parts) - ct = b'multipart/form-data; boundary=' + boundary - headers = { - 'Content-type': ct, - 'Content-length': str(len(body)) - } - return Request(self.url, body, headers) - - def search(self, terms, operator=None): - if isinstance(terms, string_types): - terms = {'name': terms} - if self.rpc_proxy is None: - self.rpc_proxy = ServerProxy(self.url, timeout=3.0) - return self.rpc_proxy.search(terms, operator or 'and') diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/locators.py b/vendor/pip-1.5.6/pip/_vendor/distlib/locators.py deleted file mode 100644 index 07bc1fd..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/distlib/locators.py +++ /dev/null @@ -1,1194 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012-2013 Vinay Sajip. -# Licensed to the Python Software Foundation under a contributor agreement. -# See LICENSE.txt and CONTRIBUTORS.txt. -# - -import gzip -from io import BytesIO -import json -import logging -import os -import posixpath -import re -try: - import threading -except ImportError: - import dummy_threading as threading -import zlib - -from . import DistlibException -from .compat import (urljoin, urlparse, urlunparse, url2pathname, pathname2url, - queue, quote, unescape, string_types, build_opener, - HTTPRedirectHandler as BaseRedirectHandler, - Request, HTTPError, URLError) -from .database import Distribution, DistributionPath, make_dist -from .metadata import Metadata -from .util import (cached_property, parse_credentials, ensure_slash, - split_filename, get_project_data, parse_requirement, - parse_name_and_version, ServerProxy) -from .version import get_scheme, UnsupportedVersionError -from .wheel import Wheel, is_compatible - -logger = logging.getLogger(__name__) - -HASHER_HASH = re.compile('^(\w+)=([a-f0-9]+)') -CHARSET = re.compile(r';\s*charset\s*=\s*(.*)\s*$', re.I) -HTML_CONTENT_TYPE = re.compile('text/html|application/x(ht)?ml') -DEFAULT_INDEX = 'http://python.org/pypi' - -def get_all_distribution_names(url=None): - """ - Return all distribution names known by an index. - :param url: The URL of the index. - :return: A list of all known distribution names. - """ - if url is None: - url = DEFAULT_INDEX - client = ServerProxy(url, timeout=3.0) - return client.list_packages() - -class RedirectHandler(BaseRedirectHandler): - """ - A class to work around a bug in some Python 3.2.x releases. - """ - # There's a bug in the base version for some 3.2.x - # (e.g. 3.2.2 on Ubuntu Oneiric). If a Location header - # returns e.g. /abc, it bails because it says the scheme '' - # is bogus, when actually it should use the request's - # URL for the scheme. See Python issue #13696. - def http_error_302(self, req, fp, code, msg, headers): - # Some servers (incorrectly) return multiple Location headers - # (so probably same goes for URI). Use first header. - newurl = None - for key in ('location', 'uri'): - if key in headers: - newurl = headers[key] - break - if newurl is None: - return - urlparts = urlparse(newurl) - if urlparts.scheme == '': - newurl = urljoin(req.get_full_url(), newurl) - if hasattr(headers, 'replace_header'): - headers.replace_header(key, newurl) - else: - headers[key] = newurl - return BaseRedirectHandler.http_error_302(self, req, fp, code, msg, - headers) - - http_error_301 = http_error_303 = http_error_307 = http_error_302 - -class Locator(object): - """ - A base class for locators - things that locate distributions. - """ - source_extensions = ('.tar.gz', '.tar.bz2', '.tar', '.zip', '.tgz', '.tbz') - binary_extensions = ('.egg', '.exe', '.whl') - excluded_extensions = ('.pdf',) - - # A list of tags indicating which wheels you want to match. The default - # value of None matches against the tags compatible with the running - # Python. If you want to match other values, set wheel_tags on a locator - # instance to a list of tuples (pyver, abi, arch) which you want to match. - wheel_tags = None - - downloadable_extensions = source_extensions + ('.whl',) - - def __init__(self, scheme='default'): - """ - Initialise an instance. - :param scheme: Because locators look for most recent versions, they - need to know the version scheme to use. This specifies - the current PEP-recommended scheme - use ``'legacy'`` - if you need to support existing distributions on PyPI. - """ - self._cache = {} - self.scheme = scheme - # Because of bugs in some of the handlers on some of the platforms, - # we use our own opener rather than just using urlopen. - self.opener = build_opener(RedirectHandler()) - # If get_project() is called from locate(), the matcher instance - # is set from the requirement passed to locate(). See issue #18 for - # why this can be useful to know. - self.matcher = None - - def clear_cache(self): - self._cache.clear() - - def _get_scheme(self): - return self._scheme - - def _set_scheme(self, value): - self._scheme = value - - scheme = property(_get_scheme, _set_scheme) - - def _get_project(self, name): - """ - For a given project, get a dictionary mapping available versions to Distribution - instances. - - This should be implemented in subclasses. - - If called from a locate() request, self.matcher will be set to a - matcher for the requirement to satisfy, otherwise it will be None. - """ - raise NotImplementedError('Please implement in the subclass') - - def get_distribution_names(self): - """ - Return all the distribution names known to this locator. - """ - raise NotImplementedError('Please implement in the subclass') - - def get_project(self, name): - """ - For a given project, get a dictionary mapping available versions to Distribution - instances. - - This calls _get_project to do all the work, and just implements a caching layer on top. - """ - if self._cache is None: - result = self._get_project(name) - elif name in self._cache: - result = self._cache[name] - else: - result = self._get_project(name) - self._cache[name] = result - return result - - def score_url(self, url): - """ - Give an url a score which can be used to choose preferred URLs - for a given project release. - """ - t = urlparse(url) - return (t.scheme != 'https', 'pypi.python.org' in t.netloc, - posixpath.basename(t.path)) - - def prefer_url(self, url1, url2): - """ - Choose one of two URLs where both are candidates for distribution - archives for the same version of a distribution (for example, - .tar.gz vs. zip). - - The current implement favours http:// URLs over https://, archives - from PyPI over those from other locations and then the archive name. - """ - result = url2 - if url1: - s1 = self.score_url(url1) - s2 = self.score_url(url2) - if s1 > s2: - result = url1 - if result != url2: - logger.debug('Not replacing %r with %r', url1, url2) - else: - logger.debug('Replacing %r with %r', url1, url2) - return result - - def split_filename(self, filename, project_name): - """ - Attempt to split a filename in project name, version and Python version. - """ - return split_filename(filename, project_name) - - def convert_url_to_download_info(self, url, project_name): - """ - See if a URL is a candidate for a download URL for a project (the URL - has typically been scraped from an HTML page). - - If it is, a dictionary is returned with keys "name", "version", - "filename" and "url"; otherwise, None is returned. - """ - def same_project(name1, name2): - name1, name2 = name1.lower(), name2.lower() - if name1 == name2: - result = True - else: - # distribute replaces '-' by '_' in project names, so it - # can tell where the version starts in a filename. - result = name1.replace('_', '-') == name2.replace('_', '-') - return result - - result = None - scheme, netloc, path, params, query, frag = urlparse(url) - if frag.lower().startswith('egg='): - logger.debug('%s: version hint in fragment: %r', - project_name, frag) - m = HASHER_HASH.match(frag) - if m: - algo, digest = m.groups() - else: - algo, digest = None, None - origpath = path - if path and path[-1] == '/': - path = path[:-1] - if path.endswith('.whl'): - try: - wheel = Wheel(path) - if is_compatible(wheel, self.wheel_tags): - if project_name is None: - include = True - else: - include = same_project(wheel.name, project_name) - if include: - result = { - 'name': wheel.name, - 'version': wheel.version, - 'filename': wheel.filename, - 'url': urlunparse((scheme, netloc, origpath, - params, query, '')), - 'python-version': ', '.join( - ['.'.join(list(v[2:])) for v in wheel.pyver]), - } - except Exception as e: - logger.warning('invalid path for wheel: %s', path) - elif path.endswith(self.downloadable_extensions): - path = filename = posixpath.basename(path) - for ext in self.downloadable_extensions: - if path.endswith(ext): - path = path[:-len(ext)] - t = self.split_filename(path, project_name) - if not t: - logger.debug('No match for project/version: %s', path) - else: - name, version, pyver = t - if not project_name or same_project(project_name, name): - result = { - 'name': name, - 'version': version, - 'filename': filename, - 'url': urlunparse((scheme, netloc, origpath, - params, query, '')), - #'packagetype': 'sdist', - } - if pyver: - result['python-version'] = pyver - break - if result and algo: - result['%s_digest' % algo] = digest - return result - - def _get_digest(self, info): - """ - Get a digest from a dictionary by looking at 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 - return result - - def _update_version_data(self, result, info): - """ - Update a result dictionary (the final result from _get_project) with a dictionary for a - specific version, whih typically holds information gleaned from a filename or URL for an - archive for the distribution. - """ - name = info.pop('name') - version = info.pop('version') - if version in result: - dist = result[version] - md = dist.metadata - else: - dist = make_dist(name, version, scheme=self.scheme) - md = dist.metadata - dist.digest = self._get_digest(info) - if md.source_url != info['url']: - md.source_url = self.prefer_url(md.source_url, info['url']) - dist.locator = self - result[version] = dist - - def locate(self, requirement, prereleases=False): - """ - Find the most recent distribution which matches the given - requirement. - - :param requirement: A requirement of the form 'foo (1.0)' or perhaps - 'foo (>= 1.0, < 2.0, != 1.3)' - :param prereleases: If ``True``, allow pre-release versions - to be located. Otherwise, pre-release versions - are not returned. - :return: A :class:`Distribution` instance, or ``None`` if no such - distribution could be located. - """ - result = None - r = parse_requirement(requirement) - if r is None: - raise DistlibException('Not a valid requirement: %r' % requirement) - scheme = get_scheme(self.scheme) - self.matcher = matcher = scheme.matcher(r.requirement) - logger.debug('matcher: %s (%s)', matcher, type(matcher).__name__) - versions = self.get_project(r.name) - if versions: - # sometimes, versions are invalid - slist = [] - vcls = matcher.version_class - for k in versions: - try: - if not matcher.match(k): - logger.debug('%s did not match %r', matcher, k) - else: - if prereleases or not vcls(k).is_prerelease: - slist.append(k) - else: - logger.debug('skipping pre-release ' - 'version %s of %s', k, matcher.name) - except Exception: - logger.warning('error matching %s with %r', matcher, k) - pass # slist.append(k) - if len(slist) > 1: - slist = sorted(slist, key=scheme.key) - if slist: - logger.debug('sorted list: %s', slist) - result = versions[slist[-1]] - if result and r.extras: - result.extras = r.extras - self.matcher = None - return result - - -class PyPIRPCLocator(Locator): - """ - This locator uses XML-RPC to locate distributions. It therefore - cannot be used with simple mirrors (that only mirror file content). - """ - def __init__(self, url, **kwargs): - """ - Initialise an instance. - - :param url: The URL to use for XML-RPC. - :param kwargs: Passed to the superclass constructor. - """ - super(PyPIRPCLocator, self).__init__(**kwargs) - self.base_url = url - self.client = ServerProxy(url, timeout=3.0) - - def get_distribution_names(self): - """ - Return all the distribution names known to this locator. - """ - return set(self.client.list_packages()) - - def _get_project(self, name): - result = {} - versions = self.client.package_releases(name, True) - for v in versions: - urls = self.client.release_urls(name, v) - data = self.client.release_data(name, v) - metadata = Metadata(scheme=self.scheme) - metadata.name = data['name'] - metadata.version = data['version'] - metadata.license = data.get('license') - metadata.keywords = data.get('keywords', []) - metadata.summary = data.get('summary') - dist = Distribution(metadata) - if urls: - info = urls[0] - metadata.source_url = info['url'] - dist.digest = self._get_digest(info) - dist.locator = self - result[v] = dist - return result - -class PyPIJSONLocator(Locator): - """ - This locator uses PyPI's JSON interface. It's very limited in functionality - nad probably not worth using. - """ - def __init__(self, url, **kwargs): - super(PyPIJSONLocator, self).__init__(**kwargs) - self.base_url = ensure_slash(url) - - def get_distribution_names(self): - """ - Return all the distribution names known to this locator. - """ - raise NotImplementedError('Not available from this locator') - - def _get_project(self, name): - result = {} - url = urljoin(self.base_url, '%s/json' % quote(name)) - try: - resp = self.opener.open(url) - data = resp.read().decode() # for now - d = json.loads(data) - md = Metadata(scheme=self.scheme) - data = d['info'] - md.name = data['name'] - md.version = data['version'] - md.license = data.get('license') - md.keywords = data.get('keywords', []) - md.summary = data.get('summary') - dist = Distribution(md) - urls = d['urls'] - if urls: - info = urls[0] - md.source_url = info['url'] - dist.digest = self._get_digest(info) - dist.locator = self - result[md.version] = dist - except Exception as e: - logger.exception('JSON fetch failed: %s', e) - return result - - -class Page(object): - """ - This class represents a scraped HTML page. - """ - # The following slightly hairy-looking regex just looks for the contents of - # an anchor link, which has an attribute "href" either immediately preceded - # or immediately followed by a "rel" attribute. The attribute values can be - # declared with double quotes, single quotes or no quotes - which leads to - # the length of the expression. - _href = re.compile(""" -(rel\s*=\s*(?:"(?P[^"]*)"|'(?P[^']*)'|(?P[^>\s\n]*))\s+)? -href\s*=\s*(?:"(?P[^"]*)"|'(?P[^']*)'|(?P[^>\s\n]*)) -(\s+rel\s*=\s*(?:"(?P[^"]*)"|'(?P[^']*)'|(?P[^>\s\n]*)))? -""", re.I | re.S | re.X) - _base = re.compile(r"""]+)""", re.I | re.S) - - def __init__(self, data, url): - """ - Initialise an instance with the Unicode page contents and the URL they - came from. - """ - self.data = data - self.base_url = self.url = url - m = self._base.search(self.data) - if m: - self.base_url = m.group(1) - - _clean_re = re.compile(r'[^a-z0-9$&+,/:;=?@.#%_\\|-]', re.I) - - @cached_property - def links(self): - """ - Return the URLs of all the links on a page together with information - about their "rel" attribute, for determining which ones to treat as - downloads and which ones to queue for further scraping. - """ - def clean(url): - "Tidy up an URL." - scheme, netloc, path, params, query, frag = urlparse(url) - return urlunparse((scheme, netloc, quote(path), - params, query, frag)) - - result = set() - for match in self._href.finditer(self.data): - d = match.groupdict('') - rel = (d['rel1'] or d['rel2'] or d['rel3'] or - d['rel4'] or d['rel5'] or d['rel6']) - url = d['url1'] or d['url2'] or d['url3'] - url = urljoin(self.base_url, url) - url = unescape(url) - url = self._clean_re.sub(lambda m: '%%%2x' % ord(m.group(0)), url) - result.add((url, rel)) - # We sort the result, hoping to bring the most recent versions - # to the front - result = sorted(result, key=lambda t: t[0], reverse=True) - return result - - -class SimpleScrapingLocator(Locator): - """ - A locator which scrapes HTML pages to locate downloads for a distribution. - This runs multiple threads to do the I/O; performance is at least as good - as pip's PackageFinder, which works in an analogous fashion. - """ - - # These are used to deal with various Content-Encoding schemes. - decoders = { - 'deflate': zlib.decompress, - 'gzip': lambda b: gzip.GzipFile(fileobj=BytesIO(d)).read(), - 'none': lambda b: b, - } - - def __init__(self, url, timeout=None, num_workers=10, **kwargs): - """ - Initialise an instance. - :param url: The root URL to use for scraping. - :param timeout: The timeout, in seconds, to be applied to requests. - This defaults to ``None`` (no timeout specified). - :param num_workers: The number of worker threads you want to do I/O, - This defaults to 10. - :param kwargs: Passed to the superclass. - """ - super(SimpleScrapingLocator, self).__init__(**kwargs) - self.base_url = ensure_slash(url) - self.timeout = timeout - self._page_cache = {} - self._seen = set() - self._to_fetch = queue.Queue() - self._bad_hosts = set() - self.skip_externals = False - self.num_workers = num_workers - self._lock = threading.RLock() - # See issue #45: we need to be resilient when the locator is used - # in a thread, e.g. with concurrent.futures. We can't use self._lock - # as it is for coordinating our internal threads - the ones created - # in _prepare_threads. - self._gplock = threading.RLock() - - def _prepare_threads(self): - """ - Threads are created only when get_project is called, and terminate - before it returns. They are there primarily to parallelise I/O (i.e. - fetching web pages). - """ - self._threads = [] - for i in range(self.num_workers): - t = threading.Thread(target=self._fetch) - t.setDaemon(True) - t.start() - self._threads.append(t) - - def _wait_threads(self): - """ - Tell all the threads to terminate (by sending a sentinel value) and - wait for them to do so. - """ - # Note that you need two loops, since you can't say which - # thread will get each sentinel - for t in self._threads: - self._to_fetch.put(None) # sentinel - for t in self._threads: - t.join() - self._threads = [] - - def _get_project(self, name): - result = {} - with self._gplock: - self.result = result - self.project_name = name - url = urljoin(self.base_url, '%s/' % quote(name)) - self._seen.clear() - self._page_cache.clear() - self._prepare_threads() - try: - logger.debug('Queueing %s', url) - self._to_fetch.put(url) - self._to_fetch.join() - finally: - self._wait_threads() - del self.result - return result - - platform_dependent = re.compile(r'\b(linux-(i\d86|x86_64|arm\w+)|' - r'win(32|-amd64)|macosx-?\d+)\b', re.I) - - def _is_platform_dependent(self, url): - """ - Does an URL refer to a platform-specific download? - """ - return self.platform_dependent.search(url) - - def _process_download(self, url): - """ - See if an URL is a suitable download for a project. - - If it is, register information in the result dictionary (for - _get_project) about the specific version it's for. - - Note that the return value isn't actually used other than as a boolean - value. - """ - if self._is_platform_dependent(url): - info = None - else: - info = self.convert_url_to_download_info(url, self.project_name) - logger.debug('process_download: %s -> %s', url, info) - if info: - with self._lock: # needed because self.result is shared - self._update_version_data(self.result, info) - return info - - def _should_queue(self, link, referrer, rel): - """ - Determine whether a link URL from a referring page and with a - particular "rel" attribute should be queued for scraping. - """ - scheme, netloc, path, _, _, _ = urlparse(link) - if path.endswith(self.source_extensions + self.binary_extensions + - self.excluded_extensions): - result = False - elif self.skip_externals and not link.startswith(self.base_url): - result = False - elif not referrer.startswith(self.base_url): - result = False - elif rel not in ('homepage', 'download'): - result = False - elif scheme not in ('http', 'https', 'ftp'): - result = False - elif self._is_platform_dependent(link): - result = False - else: - host = netloc.split(':', 1)[0] - if host.lower() == 'localhost': - result = False - else: - result = True - logger.debug('should_queue: %s (%s) from %s -> %s', link, rel, - referrer, result) - return result - - def _fetch(self): - """ - Get a URL to fetch from the work queue, get the HTML page, examine its - links for download candidates and candidates for further scraping. - - This is a handy method to run in a thread. - """ - while True: - url = self._to_fetch.get() - try: - if url: - page = self.get_page(url) - if page is None: # e.g. after an error - continue - for link, rel in page.links: - if link not in self._seen: - self._seen.add(link) - if (not self._process_download(link) and - self._should_queue(link, url, rel)): - logger.debug('Queueing %s from %s', link, url) - self._to_fetch.put(link) - finally: - # always do this, to avoid hangs :-) - self._to_fetch.task_done() - if not url: - #logger.debug('Sentinel seen, quitting.') - break - - def get_page(self, url): - """ - Get the HTML for an URL, possibly from an in-memory cache. - - XXX TODO Note: this cache is never actually cleared. It's assumed that - the data won't get stale over the lifetime of a locator instance (not - necessarily true for the default_locator). - """ - # http://peak.telecommunity.com/DevCenter/EasyInstall#package-index-api - scheme, netloc, path, _, _, _ = urlparse(url) - if scheme == 'file' and os.path.isdir(url2pathname(path)): - url = urljoin(ensure_slash(url), 'index.html') - - if url in self._page_cache: - result = self._page_cache[url] - logger.debug('Returning %s from cache: %s', url, result) - else: - host = netloc.split(':', 1)[0] - result = None - if host in self._bad_hosts: - logger.debug('Skipping %s due to bad host %s', url, host) - else: - req = Request(url, headers={'Accept-encoding': 'identity'}) - try: - logger.debug('Fetching %s', url) - resp = self.opener.open(req, timeout=self.timeout) - logger.debug('Fetched %s', url) - headers = resp.info() - content_type = headers.get('Content-Type', '') - if HTML_CONTENT_TYPE.match(content_type): - final_url = resp.geturl() - data = resp.read() - encoding = headers.get('Content-Encoding') - if encoding: - decoder = self.decoders[encoding] # fail if not found - data = decoder(data) - encoding = 'utf-8' - m = CHARSET.search(content_type) - if m: - encoding = m.group(1) - try: - data = data.decode(encoding) - except UnicodeError: - data = data.decode('latin-1') # fallback - result = Page(data, final_url) - self._page_cache[final_url] = result - except HTTPError as e: - if e.code != 404: - logger.exception('Fetch failed: %s: %s', url, e) - except URLError as e: - logger.exception('Fetch failed: %s: %s', url, e) - with self._lock: - self._bad_hosts.add(host) - except Exception as e: - logger.exception('Fetch failed: %s: %s', url, e) - finally: - self._page_cache[url] = result # even if None (failure) - return result - - _distname_re = re.compile(']*>([^<]+)<') - - def get_distribution_names(self): - """ - Return all the distribution names known to this locator. - """ - result = set() - page = self.get_page(self.base_url) - if not page: - raise DistlibException('Unable to get %s' % self.base_url) - for match in self._distname_re.finditer(page.data): - result.add(match.group(1)) - return result - -class DirectoryLocator(Locator): - """ - This class locates distributions in a directory tree. - """ - - def __init__(self, path, **kwargs): - """ - Initialise an instance. - :param path: The root of the directory tree to search. - :param kwargs: Passed to the superclass constructor, - except for: - * recursive - if True (the default), subdirectories are - recursed into. If False, only the top-level directory - is searched, - """ - self.recursive = kwargs.pop('recursive', True) - super(DirectoryLocator, self).__init__(**kwargs) - path = os.path.abspath(path) - if not os.path.isdir(path): - raise DistlibException('Not a directory: %r' % path) - self.base_dir = path - - def should_include(self, filename, parent): - """ - Should a filename be considered as a candidate for a distribution - archive? As well as the filename, the directory which contains it - is provided, though not used by the current implementation. - """ - return filename.endswith(self.downloadable_extensions) - - def _get_project(self, name): - result = {} - for root, dirs, files in os.walk(self.base_dir): - for fn in files: - if self.should_include(fn, root): - fn = os.path.join(root, fn) - url = urlunparse(('file', '', - pathname2url(os.path.abspath(fn)), - '', '', '')) - info = self.convert_url_to_download_info(url, name) - if info: - self._update_version_data(result, info) - if not self.recursive: - break - return result - - def get_distribution_names(self): - """ - Return all the distribution names known to this locator. - """ - result = set() - for root, dirs, files in os.walk(self.base_dir): - for fn in files: - if self.should_include(fn, root): - fn = os.path.join(root, fn) - url = urlunparse(('file', '', - pathname2url(os.path.abspath(fn)), - '', '', '')) - info = self.convert_url_to_download_info(url, None) - if info: - result.add(info['name']) - if not self.recursive: - break - return result - -class JSONLocator(Locator): - """ - This locator uses special extended metadata (not available on PyPI) and is - the basis of performant dependency resolution in distlib. Other locators - require archive downloads before dependencies can be determined! As you - might imagine, that can be slow. - """ - def get_distribution_names(self): - """ - Return all the distribution names known to this locator. - """ - raise NotImplementedError('Not available from this locator') - - def _get_project(self, name): - result = {} - data = get_project_data(name) - if data: - for info in data.get('files', []): - if info['ptype'] != 'sdist' or info['pyversion'] != 'source': - continue - # We don't store summary in project metadata as it makes - # the data bigger for no benefit during dependency - # resolution - dist = make_dist(data['name'], info['version'], - summary=data.get('summary', - 'Placeholder for summary'), - scheme=self.scheme) - md = dist.metadata - md.source_url = info['url'] - # TODO SHA256 digest - if 'digest' in info and info['digest']: - dist.digest = ('md5', info['digest']) - md.dependencies = info.get('requirements', {}) - dist.exports = info.get('exports', {}) - result[dist.version] = dist - return result - -class DistPathLocator(Locator): - """ - This locator finds installed distributions in a path. It can be useful for - adding to an :class:`AggregatingLocator`. - """ - def __init__(self, distpath, **kwargs): - """ - Initialise an instance. - - :param distpath: A :class:`DistributionPath` instance to search. - """ - super(DistPathLocator, self).__init__(**kwargs) - assert isinstance(distpath, DistributionPath) - self.distpath = distpath - - def _get_project(self, name): - dist = self.distpath.get_distribution(name) - if dist is None: - result = {} - else: - result = { dist.version: dist } - return result - - -class AggregatingLocator(Locator): - """ - This class allows you to chain and/or merge a list of locators. - """ - def __init__(self, *locators, **kwargs): - """ - Initialise an instance. - - :param locators: The list of locators to search. - :param kwargs: Passed to the superclass constructor, - except for: - * merge - if False (the default), the first successful - search from any of the locators is returned. If True, - the results from all locators are merged (this can be - slow). - """ - self.merge = kwargs.pop('merge', False) - self.locators = locators - super(AggregatingLocator, self).__init__(**kwargs) - - def clear_cache(self): - super(AggregatingLocator, self).clear_cache() - for locator in self.locators: - locator.clear_cache() - - def _set_scheme(self, value): - self._scheme = value - for locator in self.locators: - locator.scheme = value - - scheme = property(Locator.scheme.fget, _set_scheme) - - def _get_project(self, name): - result = {} - for locator in self.locators: - d = locator.get_project(name) - if d: - if self.merge: - result.update(d) - else: - # See issue #18. If any dists are found and we're looking - # for specific constraints, we only return something if - # a match is found. For example, if a DirectoryLocator - # returns just foo (1.0) while we're looking for - # foo (>= 2.0), we'll pretend there was nothing there so - # that subsequent locators can be queried. Otherwise we - # would just return foo (1.0) which would then lead to a - # failure to find foo (>= 2.0), because other locators - # weren't searched. Note that this only matters when - # merge=False. - if self.matcher is None: - found = True - else: - found = False - for k in d: - if self.matcher.match(k): - found = True - break - if found: - result = d - break - return result - - def get_distribution_names(self): - """ - Return all the distribution names known to this locator. - """ - result = set() - for locator in self.locators: - try: - result |= locator.get_distribution_names() - except NotImplementedError: - pass - return result - - -# We use a legacy scheme simply because most of the dists on PyPI use legacy -# versions which don't conform to PEP 426 / PEP 440. -default_locator = AggregatingLocator( - JSONLocator(), - SimpleScrapingLocator('https://pypi.python.org/simple/', - timeout=3.0), - scheme='legacy') - -locate = default_locator.locate - -NAME_VERSION_RE = re.compile(r'(?P[\w-]+)\s*' - r'\(\s*(==\s*)?(?P[^)]+)\)$') - -class DependencyFinder(object): - """ - Locate dependencies for distributions. - """ - - def __init__(self, locator=None): - """ - Initialise an instance, using the specified locator - to locate distributions. - """ - self.locator = locator or default_locator - self.scheme = get_scheme(self.locator.scheme) - - def add_distribution(self, dist): - """ - Add a distribution to the finder. This will update internal information - about who provides what. - :param dist: The distribution to add. - """ - logger.debug('adding distribution %s', dist) - name = dist.key - self.dists_by_name[name] = dist - self.dists[(name, dist.version)] = dist - for p in dist.provides: - name, version = parse_name_and_version(p) - logger.debug('Add to provided: %s, %s, %s', name, version, dist) - self.provided.setdefault(name, set()).add((version, dist)) - - def remove_distribution(self, dist): - """ - Remove a distribution from the finder. This will update internal - information about who provides what. - :param dist: The distribution to remove. - """ - logger.debug('removing distribution %s', dist) - name = dist.key - del self.dists_by_name[name] - del self.dists[(name, dist.version)] - for p in dist.provides: - name, version = parse_name_and_version(p) - logger.debug('Remove from provided: %s, %s, %s', name, version, dist) - s = self.provided[name] - s.remove((version, dist)) - if not s: - del self.provided[name] - - def get_matcher(self, reqt): - """ - Get a version matcher for a requirement. - :param reqt: The requirement - :type reqt: str - :return: A version matcher (an instance of - :class:`distlib.version.Matcher`). - """ - try: - matcher = self.scheme.matcher(reqt) - except UnsupportedVersionError: - # XXX compat-mode if cannot read the version - name = reqt.split()[0] - matcher = self.scheme.matcher(name) - return matcher - - def find_providers(self, reqt): - """ - Find the distributions which can fulfill a requirement. - - :param reqt: The requirement. - :type reqt: str - :return: A set of distribution which can fulfill the requirement. - """ - matcher = self.get_matcher(reqt) - name = matcher.key # case-insensitive - result = set() - provided = self.provided - if name in provided: - for version, provider in provided[name]: - try: - match = matcher.match(version) - except UnsupportedVersionError: - match = False - - if match: - result.add(provider) - break - return result - - def try_to_replace(self, provider, other, problems): - """ - Attempt to replace one provider with another. This is typically used - when resolving dependencies from multiple sources, e.g. A requires - (B >= 1.0) while C requires (B >= 1.1). - - For successful replacement, ``provider`` must meet all the requirements - which ``other`` fulfills. - - :param provider: The provider we are trying to replace with. - :param other: The provider we're trying to replace. - :param problems: If False is returned, this will contain what - problems prevented replacement. This is currently - a tuple of the literal string 'cantreplace', - ``provider``, ``other`` and the set of requirements - that ``provider`` couldn't fulfill. - :return: True if we can replace ``other`` with ``provider``, else - False. - """ - rlist = self.reqts[other] - unmatched = set() - for s in rlist: - matcher = self.get_matcher(s) - if not matcher.match(provider.version): - unmatched.add(s) - if unmatched: - # can't replace other with provider - problems.add(('cantreplace', provider, other, unmatched)) - result = False - else: - # can replace other with provider - self.remove_distribution(other) - del self.reqts[other] - for s in rlist: - self.reqts.setdefault(provider, set()).add(s) - self.add_distribution(provider) - result = True - return result - - def find(self, requirement, meta_extras=None, prereleases=False): - """ - Find a distribution and all distributions it depends on. - - :param requirement: The requirement specifying the distribution to - find, or a Distribution instance. - :param meta_extras: A list of meta extras such as :test:, :build: and - so on. - :param prereleases: If ``True``, allow pre-release versions to be - returned - otherwise, don't return prereleases - unless they're all that's available. - - Return a set of :class:`Distribution` instances and a set of - problems. - - The distributions returned should be such that they have the - :attr:`required` attribute set to ``True`` if they were - from the ``requirement`` passed to ``find()``, and they have the - :attr:`build_time_dependency` attribute set to ``True`` unless they - are post-installation dependencies of the ``requirement``. - - The problems should be a tuple consisting of the string - ``'unsatisfied'`` and the requirement which couldn't be satisfied - by any distribution known to the locator. - """ - - self.provided = {} - self.dists = {} - self.dists_by_name = {} - self.reqts = {} - - meta_extras = set(meta_extras or []) - if ':*:' in meta_extras: - meta_extras.remove(':*:') - # :meta: and :run: are implicitly included - meta_extras |= set([':test:', ':build:', ':dev:']) - - if isinstance(requirement, Distribution): - dist = odist = requirement - logger.debug('passed %s as requirement', odist) - else: - dist = odist = self.locator.locate(requirement, - prereleases=prereleases) - if dist is None: - raise DistlibException('Unable to locate %r' % requirement) - logger.debug('located %s', odist) - dist.requested = True - problems = set() - todo = set([dist]) - install_dists = set([odist]) - while todo: - dist = todo.pop() - name = dist.key # case-insensitive - if name not in self.dists_by_name: - self.add_distribution(dist) - else: - #import pdb; pdb.set_trace() - other = self.dists_by_name[name] - if other != dist: - self.try_to_replace(dist, other, problems) - - ireqts = dist.run_requires | dist.meta_requires - sreqts = dist.build_requires - ereqts = set() - if dist in install_dists: - for key in ('test', 'build', 'dev'): - e = ':%s:' % key - if e in meta_extras: - ereqts |= getattr(dist, '%s_requires' % key) - all_reqts = ireqts | sreqts | ereqts - for r in all_reqts: - providers = self.find_providers(r) - if not providers: - logger.debug('No providers found for %r', r) - provider = self.locator.locate(r, prereleases=prereleases) - # If no provider is found and we didn't consider - # prereleases, consider them now. - if provider is None and not prereleases: - provider = self.locator.locate(r, prereleases=True) - if provider is None: - logger.debug('Cannot satisfy %r', r) - problems.add(('unsatisfied', r)) - else: - n, v = provider.key, provider.version - if (n, v) not in self.dists: - todo.add(provider) - providers.add(provider) - if r in ireqts and dist in install_dists: - install_dists.add(provider) - logger.debug('Adding %s to install_dists', - provider.name_and_version) - for p in providers: - name = p.key - if name not in self.dists_by_name: - self.reqts.setdefault(p, set()).add(r) - else: - other = self.dists_by_name[name] - if other != p: - # see if other can be replaced by p - self.try_to_replace(p, other, problems) - - dists = set(self.dists.values()) - for dist in dists: - dist.build_time_dependency = dist not in install_dists - if dist.build_time_dependency: - logger.debug('%s is a build-time dependency only.', - dist.name_and_version) - logger.debug('find done for %s', odist) - return dists, problems diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/manifest.py b/vendor/pip-1.5.6/pip/_vendor/distlib/manifest.py deleted file mode 100644 index c6b98c5..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/distlib/manifest.py +++ /dev/null @@ -1,364 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012-2013 Python Software Foundation. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -""" -Class representing the list of files in a distribution. - -Equivalent to distutils.filelist, but fixes some problems. -""" -import fnmatch -import logging -import os -import re - -from . import DistlibException -from .compat import fsdecode -from .util import convert_path - - -__all__ = ['Manifest'] - -logger = logging.getLogger(__name__) - -# a \ followed by some spaces + EOL -_COLLAPSE_PATTERN = re.compile('\\\w*\n', re.M) -_COMMENTED_LINE = re.compile('#.*?(?=\n)|\n(?=$)', re.M | re.S) - - -class Manifest(object): - """A list of files built by on exploring the filesystem and filtered by - applying various patterns to what we find there. - """ - - def __init__(self, base=None): - """ - Initialise an instance. - - :param base: The base directory to explore under. - """ - self.base = os.path.abspath(os.path.normpath(base or os.getcwd())) - self.prefix = self.base + os.sep - self.allfiles = None - self.files = set() - - # - # Public API - # - - def findall(self): - """Find all files under the base and set ``allfiles`` to the absolute - pathnames of files found. - """ - from stat import S_ISREG, S_ISDIR, S_ISLNK - - self.allfiles = allfiles = [] - root = self.base - stack = [root] - pop = stack.pop - push = stack.append - - while stack: - root = pop() - names = os.listdir(root) - - for name in names: - fullname = os.path.join(root, name) - - # Avoid excess stat calls -- just one will do, thank you! - stat = os.stat(fullname) - mode = stat.st_mode - if S_ISREG(mode): - allfiles.append(fsdecode(fullname)) - elif S_ISDIR(mode) and not S_ISLNK(mode): - push(fullname) - - def add(self, item): - """ - Add a file to the manifest. - - :param item: The pathname to add. This can be relative to the base. - """ - if not item.startswith(self.prefix): - item = os.path.join(self.base, item) - self.files.add(os.path.normpath(item)) - - def add_many(self, items): - """ - Add a list of files to the manifest. - - :param items: The pathnames to add. These can be relative to the base. - """ - for item in items: - self.add(item) - - def sorted(self, wantdirs=False): - """ - Return sorted files in directory order - """ - - def add_dir(dirs, d): - dirs.add(d) - logger.debug('add_dir added %s', d) - if d != self.base: - parent, _ = os.path.split(d) - assert parent not in ('', '/') - add_dir(dirs, parent) - - result = set(self.files) # make a copy! - if wantdirs: - dirs = set() - for f in result: - add_dir(dirs, os.path.dirname(f)) - result |= dirs - return [os.path.join(*path_tuple) for path_tuple in - sorted(os.path.split(path) for path in result)] - - def clear(self): - """Clear all collected files.""" - self.files = set() - self.allfiles = [] - - def process_directive(self, directive): - """ - Process a directive which either adds some files from ``allfiles`` to - ``files``, or removes some files from ``files``. - - :param directive: The directive to process. This should be in a format - compatible with distutils ``MANIFEST.in`` files: - - http://docs.python.org/distutils/sourcedist.html#commands - """ - # Parse the line: split it up, make sure the right number of words - # is there, and return the relevant words. 'action' is always - # defined: it's the first word of the line. Which of the other - # three are defined depends on the action; it'll be either - # patterns, (dir and patterns), or (dirpattern). - action, patterns, thedir, dirpattern = self._parse_directive(directive) - - # OK, now we know that the action is valid and we have the - # right number of words on the line for that action -- so we - # can proceed with minimal error-checking. - if action == 'include': - for pattern in patterns: - if not self._include_pattern(pattern, anchor=True): - logger.warning('no files found matching %r', pattern) - - elif action == 'exclude': - for pattern in patterns: - if not self._exclude_pattern(pattern, anchor=True): - logger.warning('no previously-included files ' - 'found matching %r', pattern) - - elif action == 'global-include': - for pattern in patterns: - if not self._include_pattern(pattern, anchor=False): - logger.warning('no files found matching %r ' - 'anywhere in distribution', pattern) - - elif action == 'global-exclude': - for pattern in patterns: - if not self._exclude_pattern(pattern, anchor=False): - logger.warning('no previously-included files ' - 'matching %r found anywhere in ' - 'distribution', pattern) - - elif action == 'recursive-include': - for pattern in patterns: - if not self._include_pattern(pattern, prefix=thedir): - logger.warning('no files found matching %r ' - 'under directory %r', pattern, thedir) - - elif action == 'recursive-exclude': - for pattern in patterns: - if not self._exclude_pattern(pattern, prefix=thedir): - logger.warning('no previously-included files ' - 'matching %r found under directory %r', - pattern, thedir) - - elif action == 'graft': - if not self._include_pattern(None, prefix=dirpattern): - logger.warning('no directories found matching %r', - dirpattern) - - elif action == 'prune': - if not self._exclude_pattern(None, prefix=dirpattern): - logger.warning('no previously-included directories found ' - 'matching %r', dirpattern) - else: # pragma: no cover - # This should never happen, as it should be caught in - # _parse_template_line - raise DistlibException( - 'invalid action %r' % action) - - # - # Private API - # - - def _parse_directive(self, directive): - """ - Validate a directive. - :param directive: The directive to validate. - :return: A tuple of action, patterns, thedir, dir_patterns - """ - words = directive.split() - if len(words) == 1 and words[0] not in ('include', 'exclude', - 'global-include', - 'global-exclude', - 'recursive-include', - 'recursive-exclude', - 'graft', 'prune'): - # no action given, let's use the default 'include' - words.insert(0, 'include') - - action = words[0] - patterns = thedir = dir_pattern = None - - if action in ('include', 'exclude', - 'global-include', 'global-exclude'): - if len(words) < 2: - raise DistlibException( - '%r expects ...' % action) - - patterns = [convert_path(word) for word in words[1:]] - - elif action in ('recursive-include', 'recursive-exclude'): - if len(words) < 3: - raise DistlibException( - '%r expects ...' % action) - - thedir = convert_path(words[1]) - patterns = [convert_path(word) for word in words[2:]] - - elif action in ('graft', 'prune'): - if len(words) != 2: - raise DistlibException( - '%r expects a single ' % action) - - dir_pattern = convert_path(words[1]) - - else: - raise DistlibException('unknown action %r' % action) - - return action, patterns, thedir, dir_pattern - - def _include_pattern(self, pattern, anchor=True, prefix=None, - is_regex=False): - """Select strings (presumably filenames) from 'self.files' that - match 'pattern', a Unix-style wildcard (glob) pattern. - - Patterns are not quite the same as implemented by the 'fnmatch' - module: '*' and '?' match non-special characters, where "special" - is platform-dependent: slash on Unix; colon, slash, and backslash on - DOS/Windows; and colon on Mac OS. - - If 'anchor' is true (the default), then the pattern match is more - stringent: "*.py" will match "foo.py" but not "foo/bar.py". If - 'anchor' is false, both of these will match. - - If 'prefix' is supplied, then only filenames starting with 'prefix' - (itself a pattern) and ending with 'pattern', with anything in between - them, will match. 'anchor' is ignored in this case. - - If 'is_regex' is true, 'anchor' and 'prefix' are ignored, and - 'pattern' is assumed to be either a string containing a regex or a - regex object -- no translation is done, the regex is just compiled - and used as-is. - - Selected strings will be added to self.files. - - Return True if files are found. - """ - # XXX docstring lying about what the special chars are? - found = False - pattern_re = self._translate_pattern(pattern, anchor, prefix, is_regex) - - # delayed loading of allfiles list - if self.allfiles is None: - self.findall() - - for name in self.allfiles: - if pattern_re.search(name): - self.files.add(name) - found = True - return found - - def _exclude_pattern(self, pattern, anchor=True, prefix=None, - is_regex=False): - """Remove strings (presumably filenames) from 'files' that match - 'pattern'. - - Other parameters are the same as for 'include_pattern()', above. - The list 'self.files' is modified in place. Return True if files are - found. - - This API is public to allow e.g. exclusion of SCM subdirs, e.g. when - packaging source distributions - """ - found = False - pattern_re = self._translate_pattern(pattern, anchor, prefix, is_regex) - for f in list(self.files): - if pattern_re.search(f): - self.files.remove(f) - found = True - return found - - def _translate_pattern(self, pattern, anchor=True, prefix=None, - is_regex=False): - """Translate a shell-like wildcard pattern to a compiled regular - expression. - - Return the compiled regex. If 'is_regex' true, - then 'pattern' is directly compiled to a regex (if it's a string) - or just returned as-is (assumes it's a regex object). - """ - if is_regex: - if isinstance(pattern, str): - return re.compile(pattern) - else: - return pattern - - if pattern: - pattern_re = self._glob_to_re(pattern) - else: - pattern_re = '' - - base = re.escape(os.path.join(self.base, '')) - if prefix is not None: - # ditch end of pattern character - empty_pattern = self._glob_to_re('') - prefix_re = self._glob_to_re(prefix)[:-len(empty_pattern)] - sep = os.sep - if os.sep == '\\': - sep = r'\\' - pattern_re = '^' + base + sep.join((prefix_re, - '.*' + pattern_re)) - else: # no prefix -- respect anchor flag - if anchor: - pattern_re = '^' + base + pattern_re - - return re.compile(pattern_re) - - def _glob_to_re(self, pattern): - """Translate a shell-like glob pattern to a regular expression. - - Return a string containing the regex. Differs from - 'fnmatch.translate()' in that '*' does not match "special characters" - (which are platform-specific). - """ - pattern_re = fnmatch.translate(pattern) - - # '?' and '*' in the glob pattern become '.' and '.*' in the RE, which - # IMHO is wrong -- '?' and '*' aren't supposed to match slash in Unix, - # and by extension they shouldn't match such "special characters" under - # any OS. So change all non-escaped dots in the RE to match any - # character except the special characters (currently: just os.sep). - sep = os.sep - if os.sep == '\\': - # we're using a regex to manipulate a regex, so we need - # to escape the backslash twice - sep = r'\\\\' - escaped = r'\1[^%s]' % sep - pattern_re = re.sub(r'((? y, - 'gte': lambda x, y: x >= y, - 'in': lambda x, y: x in y, - 'lt': lambda x, y: x < y, - 'lte': lambda x, y: x <= y, - 'not': lambda x: not x, - 'noteq': lambda x, y: x != y, - 'notin': lambda x, y: x not in y, - } - - allowed_values = { - 'sys_platform': sys.platform, - 'python_version': '%s.%s' % sys.version_info[:2], - # parsing sys.platform is not reliable, but there is no other - # way to get e.g. 2.7.2+, and the PEP is defined with sys.version - 'python_full_version': sys.version.split(' ', 1)[0], - 'os_name': os.name, - 'platform_in_venv': str(in_venv()), - 'platform_release': platform.release(), - 'platform_version': platform.version(), - 'platform_machine': platform.machine(), - 'platform_python_implementation': python_implementation(), - } - - def __init__(self, context=None): - """ - Initialise an instance. - - :param context: If specified, names are looked up in this mapping. - """ - self.context = context or {} - self.source = None - - def get_fragment(self, offset): - """ - Get the part of the source which is causing a problem. - """ - fragment_len = 10 - s = '%r' % (self.source[offset:offset + fragment_len]) - if offset + fragment_len < len(self.source): - s += '...' - return s - - def get_handler(self, node_type): - """ - Get a handler for the specified AST node type. - """ - return getattr(self, 'do_%s' % node_type, None) - - def evaluate(self, node, filename=None): - """ - Evaluate a source string or node, using ``filename`` when - displaying errors. - """ - if isinstance(node, string_types): - self.source = node - kwargs = {'mode': 'eval'} - if filename: - kwargs['filename'] = filename - try: - node = ast.parse(node, **kwargs) - except SyntaxError as e: - s = self.get_fragment(e.offset) - raise SyntaxError('syntax error %s' % s) - node_type = node.__class__.__name__.lower() - handler = self.get_handler(node_type) - if handler is None: - if self.source is None: - s = '(source not available)' - else: - s = self.get_fragment(node.col_offset) - raise SyntaxError("don't know how to evaluate %r %s" % ( - node_type, s)) - return handler(node) - - def get_attr_key(self, node): - assert isinstance(node, ast.Attribute), 'attribute node expected' - return '%s.%s' % (node.value.id, node.attr) - - def do_attribute(self, node): - if not isinstance(node.value, ast.Name): - valid = False - else: - key = self.get_attr_key(node) - valid = key in self.context or key in self.allowed_values - if not valid: - raise SyntaxError('invalid expression: %s' % key) - if key in self.context: - result = self.context[key] - else: - result = self.allowed_values[key] - return result - - def do_boolop(self, node): - result = self.evaluate(node.values[0]) - is_or = node.op.__class__ is ast.Or - is_and = node.op.__class__ is ast.And - assert is_or or is_and - if (is_and and result) or (is_or and not result): - for n in node.values[1:]: - result = self.evaluate(n) - if (is_or and result) or (is_and and not result): - break - return result - - def do_compare(self, node): - def sanity_check(lhsnode, rhsnode): - valid = True - if isinstance(lhsnode, ast.Str) and isinstance(rhsnode, ast.Str): - valid = False - #elif (isinstance(lhsnode, ast.Attribute) - # and isinstance(rhsnode, ast.Attribute)): - # klhs = self.get_attr_key(lhsnode) - # krhs = self.get_attr_key(rhsnode) - # valid = klhs != krhs - if not valid: - s = self.get_fragment(node.col_offset) - raise SyntaxError('Invalid comparison: %s' % s) - - lhsnode = node.left - lhs = self.evaluate(lhsnode) - result = True - for op, rhsnode in zip(node.ops, node.comparators): - sanity_check(lhsnode, rhsnode) - op = op.__class__.__name__.lower() - if op not in self.operators: - raise SyntaxError('unsupported operation: %r' % op) - rhs = self.evaluate(rhsnode) - result = self.operators[op](lhs, rhs) - if not result: - break - lhs = rhs - lhsnode = rhsnode - return result - - def do_expression(self, node): - return self.evaluate(node.body) - - def do_name(self, node): - valid = False - if node.id in self.context: - valid = True - result = self.context[node.id] - elif node.id in self.allowed_values: - valid = True - result = self.allowed_values[node.id] - if not valid: - raise SyntaxError('invalid expression: %s' % node.id) - return result - - def do_str(self, node): - return node.s - - -def interpret(marker, execution_context=None): - """ - Interpret a marker and return a result depending on environment. - - :param marker: The marker to interpret. - :type marker: str - :param execution_context: The context used for name lookup. - :type execution_context: mapping - """ - return Evaluator(execution_context).evaluate(marker.strip()) diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/metadata.py b/vendor/pip-1.5.6/pip/_vendor/distlib/metadata.py deleted file mode 100644 index 8441d8f..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/distlib/metadata.py +++ /dev/null @@ -1,1026 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012 The Python Software Foundation. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -"""Implementation of the Metadata for Python packages PEPs. - -Supports all metadata formats (1.0, 1.1, 1.2, and 2.0 experimental). -""" -from __future__ import unicode_literals - -import codecs -from email import message_from_file -import json -import logging -import re - - -from . import DistlibException, __version__ -from .compat import StringIO, string_types, text_type -from .markers import interpret -from .util import extract_by_key, get_extras -from .version import get_scheme, PEP426_VERSION_RE - -logger = logging.getLogger(__name__) - - -class MetadataMissingError(DistlibException): - """A required metadata is missing""" - - -class MetadataConflictError(DistlibException): - """Attempt to read or write metadata fields that are conflictual.""" - - -class MetadataUnrecognizedVersionError(DistlibException): - """Unknown metadata version number.""" - - -class MetadataInvalidError(DistlibException): - """A metadata value is invalid""" - -# public API of this module -__all__ = ['Metadata', 'PKG_INFO_ENCODING', 'PKG_INFO_PREFERRED_VERSION'] - -# Encoding used for the PKG-INFO files -PKG_INFO_ENCODING = 'utf-8' - -# preferred version. Hopefully will be changed -# to 1.2 once PEP 345 is supported everywhere -PKG_INFO_PREFERRED_VERSION = '1.1' - -_LINE_PREFIX = re.compile('\n \|') -_241_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', - 'Summary', 'Description', - 'Keywords', 'Home-page', 'Author', 'Author-email', - 'License') - -_314_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', - 'Supported-Platform', 'Summary', 'Description', - 'Keywords', 'Home-page', 'Author', 'Author-email', - 'License', 'Classifier', 'Download-URL', 'Obsoletes', - 'Provides', 'Requires') - -_314_MARKERS = ('Obsoletes', 'Provides', 'Requires', 'Classifier', - 'Download-URL') - -_345_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', - 'Supported-Platform', 'Summary', 'Description', - 'Keywords', 'Home-page', 'Author', 'Author-email', - 'Maintainer', 'Maintainer-email', 'License', - 'Classifier', 'Download-URL', 'Obsoletes-Dist', - 'Project-URL', 'Provides-Dist', 'Requires-Dist', - 'Requires-Python', 'Requires-External') - -_345_MARKERS = ('Provides-Dist', 'Requires-Dist', 'Requires-Python', - 'Obsoletes-Dist', 'Requires-External', 'Maintainer', - 'Maintainer-email', 'Project-URL') - -_426_FIELDS = ('Metadata-Version', 'Name', 'Version', 'Platform', - 'Supported-Platform', 'Summary', 'Description', - 'Keywords', 'Home-page', 'Author', 'Author-email', - 'Maintainer', 'Maintainer-email', 'License', - 'Classifier', 'Download-URL', 'Obsoletes-Dist', - 'Project-URL', 'Provides-Dist', 'Requires-Dist', - 'Requires-Python', 'Requires-External', 'Private-Version', - 'Obsoleted-By', 'Setup-Requires-Dist', 'Extension', - 'Provides-Extra') - -_426_MARKERS = ('Private-Version', 'Provides-Extra', 'Obsoleted-By', - 'Setup-Requires-Dist', 'Extension') - -_ALL_FIELDS = set() -_ALL_FIELDS.update(_241_FIELDS) -_ALL_FIELDS.update(_314_FIELDS) -_ALL_FIELDS.update(_345_FIELDS) -_ALL_FIELDS.update(_426_FIELDS) - -EXTRA_RE = re.compile(r'''extra\s*==\s*("([^"]+)"|'([^']+)')''') - - -def _version2fieldlist(version): - if version == '1.0': - return _241_FIELDS - elif version == '1.1': - return _314_FIELDS - elif version == '1.2': - return _345_FIELDS - elif version == '2.0': - return _426_FIELDS - raise MetadataUnrecognizedVersionError(version) - - -def _best_version(fields): - """Detect the best version depending on the fields used.""" - def _has_marker(keys, markers): - for marker in markers: - if marker in keys: - return True - return False - - keys = [] - for key, value in fields.items(): - if value in ([], 'UNKNOWN', None): - continue - keys.append(key) - - possible_versions = ['1.0', '1.1', '1.2', '2.0'] - - # first let's try to see if a field is not part of one of the version - for key in keys: - if key not in _241_FIELDS and '1.0' in possible_versions: - possible_versions.remove('1.0') - if key not in _314_FIELDS and '1.1' in possible_versions: - possible_versions.remove('1.1') - if key not in _345_FIELDS and '1.2' in possible_versions: - possible_versions.remove('1.2') - if key not in _426_FIELDS and '2.0' in possible_versions: - possible_versions.remove('2.0') - - # possible_version contains qualified versions - if len(possible_versions) == 1: - return possible_versions[0] # found ! - elif len(possible_versions) == 0: - raise MetadataConflictError('Unknown metadata set') - - # let's see if one unique marker is found - is_1_1 = '1.1' in possible_versions and _has_marker(keys, _314_MARKERS) - is_1_2 = '1.2' in possible_versions and _has_marker(keys, _345_MARKERS) - is_2_0 = '2.0' in possible_versions and _has_marker(keys, _426_MARKERS) - if int(is_1_1) + int(is_1_2) + int(is_2_0) > 1: - raise MetadataConflictError('You used incompatible 1.1/1.2/2.0 fields') - - # we have the choice, 1.0, or 1.2, or 2.0 - # - 1.0 has a broken Summary field but works with all tools - # - 1.1 is to avoid - # - 1.2 fixes Summary but has little adoption - # - 2.0 adds more features and is very new - if not is_1_1 and not is_1_2 and not is_2_0: - # we couldn't find any specific marker - if PKG_INFO_PREFERRED_VERSION in possible_versions: - return PKG_INFO_PREFERRED_VERSION - if is_1_1: - return '1.1' - if is_1_2: - return '1.2' - - return '2.0' - -_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', -} - -_PREDICATE_FIELDS = ('Requires-Dist', 'Obsoletes-Dist', 'Provides-Dist') -_VERSIONS_FIELDS = ('Requires-Python',) -_VERSION_FIELDS = ('Version',) -_LISTFIELDS = ('Platform', 'Classifier', 'Obsoletes', - 'Requires', 'Provides', 'Obsoletes-Dist', - 'Provides-Dist', 'Requires-Dist', 'Requires-External', - 'Project-URL', 'Supported-Platform', 'Setup-Requires-Dist', - 'Provides-Extra', 'Extension') -_LISTTUPLEFIELDS = ('Project-URL',) - -_ELEMENTSFIELD = ('Keywords',) - -_UNICODEFIELDS = ('Author', 'Maintainer', 'Summary', 'Description') - -_MISSING = object() - -_FILESAFE = re.compile('[^A-Za-z0-9.]+') - - -def _get_name_and_version(name, version, for_filename=False): - """Return the distribution name with version. - - If for_filename is true, return a filename-escaped form.""" - if for_filename: - # For both name and version any runs of non-alphanumeric or '.' - # characters are replaced with a single '-'. Additionally any - # spaces in the version string become '.' - name = _FILESAFE.sub('-', name) - version = _FILESAFE.sub('-', version.replace(' ', '.')) - return '%s-%s' % (name, version) - - -class LegacyMetadata(object): - """The legacy metadata of a release. - - Supports versions 1.0, 1.1 and 1.2 (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 - - *mapping* is a dict-like object - - *scheme* is a version scheme name - """ - # TODO document the mapping API and UNKNOWN default key - - def __init__(self, path=None, fileobj=None, mapping=None, - scheme='default'): - if [path, fileobj, mapping].count(None) < 2: - raise TypeError('path, fileobj and mapping are exclusive') - self._fields = {} - self.requires_files = [] - self._dependencies = None - self.scheme = scheme - if path is not None: - self.read(path) - elif fileobj is not None: - self.read_file(fileobj) - elif mapping is not None: - self.update(mapping) - self.set_metadata_version() - - def set_metadata_version(self): - self._fields['Metadata-Version'] = _best_version(self._fields) - - def _write_field(self, fileobj, name, value): - fileobj.write('%s: %s\n' % (name, value)) - - def __getitem__(self, name): - return self.get(name) - - def __setitem__(self, name, value): - return self.set(name, value) - - def __delitem__(self, name): - field_name = self._convert_name(name) - try: - del self._fields[field_name] - except KeyError: - raise KeyError(name) - - def __contains__(self, name): - return (name in self._fields or - self._convert_name(name) in self._fields) - - def _convert_name(self, name): - if name in _ALL_FIELDS: - return name - name = name.replace('-', '_').lower() - return _ATTR2FIELD.get(name, name) - - def _default_value(self, name): - if name in _LISTFIELDS or name in _ELEMENTSFIELD: - return [] - return 'UNKNOWN' - - def _remove_line_prefix(self, value): - return _LINE_PREFIX.sub('\n', value) - - def __getattr__(self, name): - if name in _ATTR2FIELD: - return self[name] - raise AttributeError(name) - - # - # Public API - # - -# dependencies = property(_get_dependencies, _set_dependencies) - - def get_fullname(self, filesafe=False): - """Return the distribution name with version. - - If filesafe is true, return a filename-escaped form.""" - return _get_name_and_version(self['Name'], self['Version'], filesafe) - - def is_field(self, name): - """return True if name is a valid metadata key""" - name = self._convert_name(name) - return name in _ALL_FIELDS - - def is_multi_field(self, name): - name = self._convert_name(name) - return name in _LISTFIELDS - - def read(self, filepath): - """Read the metadata values from a file path.""" - fp = codecs.open(filepath, 'r', encoding='utf-8') - try: - self.read_file(fp) - finally: - fp.close() - - def read_file(self, fileob): - """Read the metadata values from a file object.""" - msg = message_from_file(fileob) - self._fields['Metadata-Version'] = msg['metadata-version'] - - # When reading, get all the fields we can - for field in _ALL_FIELDS: - if field not in msg: - continue - if field in _LISTFIELDS: - # we can have multiple lines - values = msg.get_all(field) - if field in _LISTTUPLEFIELDS and values is not None: - values = [tuple(value.split(',')) for value in values] - self.set(field, values) - else: - # single line - value = msg[field] - if value is not None and value != 'UNKNOWN': - self.set(field, value) - self.set_metadata_version() - - def write(self, filepath, skip_unknown=False): - """Write the metadata fields to filepath.""" - fp = codecs.open(filepath, 'w', encoding='utf-8') - try: - self.write_file(fp, skip_unknown) - finally: - fp.close() - - def write_file(self, fileobject, skip_unknown=False): - """Write the PKG-INFO format data to a file object.""" - self.set_metadata_version() - - for field in _version2fieldlist(self['Metadata-Version']): - values = self.get(field) - if skip_unknown and values in ('UNKNOWN', [], ['UNKNOWN']): - continue - if field in _ELEMENTSFIELD: - self._write_field(fileobject, field, ','.join(values)) - continue - if field not in _LISTFIELDS: - if field == 'Description': - values = values.replace('\n', '\n |') - values = [values] - - if field in _LISTTUPLEFIELDS: - values = [','.join(value) for value in values] - - for value in values: - self._write_field(fileobject, field, value) - - def update(self, other=None, **kwargs): - """Set metadata values from the given iterable `other` and kwargs. - - Behavior is like `dict.update`: If `other` has a ``keys`` method, - they are looped over and ``self[key]`` is assigned ``other[key]``. - Else, ``other`` is an iterable of ``(key, value)`` iterables. - - Keys that don't match a metadata field or that have an empty value are - dropped. - """ - def _set(key, value): - if key in _ATTR2FIELD and value: - self.set(self._convert_name(key), value) - - if not other: - # other is None or empty container - pass - elif hasattr(other, 'keys'): - for k in other.keys(): - _set(k, other[k]) - else: - for k, v in other: - _set(k, v) - - if kwargs: - for k, v in kwargs.items(): - _set(k, v) - - def set(self, name, value): - """Control then set a metadata field.""" - name = self._convert_name(name) - - if ((name in _ELEMENTSFIELD or name == 'Platform') and - not isinstance(value, (list, tuple))): - if isinstance(value, string_types): - value = [v.strip() for v in value.split(',')] - else: - value = [] - elif (name in _LISTFIELDS and - not isinstance(value, (list, tuple))): - if isinstance(value, string_types): - value = [value] - else: - value = [] - - if logger.isEnabledFor(logging.WARNING): - project_name = self['Name'] - - scheme = get_scheme(self.scheme) - if name in _PREDICATE_FIELDS and value is not None: - for v in value: - # check that the values are valid - if not scheme.is_valid_matcher(v.split(';')[0]): - logger.warning( - '%r: %r is not valid (field %r)', - project_name, v, name) - # FIXME this rejects UNKNOWN, is that right? - elif name in _VERSIONS_FIELDS and value is not None: - if not scheme.is_valid_constraint_list(value): - logger.warning('%r: %r is not a valid version (field %r)', - project_name, value, name) - elif name in _VERSION_FIELDS and value is not None: - if not scheme.is_valid_version(value): - logger.warning('%r: %r is not a valid version (field %r)', - project_name, value, name) - - if name in _UNICODEFIELDS: - if name == 'Description': - value = self._remove_line_prefix(value) - - self._fields[name] = value - - def get(self, name, default=_MISSING): - """Get a metadata field.""" - name = self._convert_name(name) - if name not in self._fields: - if default is _MISSING: - default = self._default_value(name) - return default - if name in _UNICODEFIELDS: - value = self._fields[name] - return value - elif name in _LISTFIELDS: - value = self._fields[name] - if value is None: - return [] - res = [] - for val in value: - if name not in _LISTTUPLEFIELDS: - res.append(val) - else: - # That's for Project-URL - res.append((val[0], val[1])) - return res - - elif name in _ELEMENTSFIELD: - value = self._fields[name] - if isinstance(value, string_types): - return value.split(',') - return self._fields[name] - - def check(self, strict=False): - """Check if the metadata is compliant. If strict is True then raise if - no Name or Version are provided""" - self.set_metadata_version() - - # XXX should check the versions (if the file was loaded) - missing, warnings = [], [] - - for attr in ('Name', 'Version'): # required by PEP 345 - if attr not in self: - missing.append(attr) - - if strict and missing != []: - msg = 'missing required metadata: %s' % ', '.join(missing) - raise MetadataMissingError(msg) - - for attr in ('Home-page', 'Author'): - if attr not in self: - missing.append(attr) - - # checking metadata 1.2 (XXX needs to check 1.1, 1.0) - if self['Metadata-Version'] != '1.2': - return missing, warnings - - scheme = get_scheme(self.scheme) - - def are_valid_constraints(value): - for v in value: - if not scheme.is_valid_matcher(v.split(';')[0]): - return False - return True - - for fields, controller in ((_PREDICATE_FIELDS, are_valid_constraints), - (_VERSIONS_FIELDS, - scheme.is_valid_constraint_list), - (_VERSION_FIELDS, - scheme.is_valid_version)): - for field in fields: - value = self.get(field, None) - if value is not None and not controller(value): - warnings.append('Wrong value for %r: %s' % (field, value)) - - return missing, warnings - - def todict(self, skip_missing=False): - """Return fields as a dict. - - Field names will be converted to use the underscore-lowercase style - instead of hyphen-mixed case (i.e. home_page instead of Home-page). - """ - 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'), - ('classifier', 'Classifier'), - ('download_url', 'Download-URL'), - ) - - data = {} - for key, field_name in mapping_1_0: - 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: - data[key] = self[field_name] - - return data - - def add_requirements(self, requirements): - if self['Metadata-Version'] == '1.1': - # we can't have 1.1 metadata *and* Setuptools requires - for field in ('Obsoletes', 'Requires', 'Provides'): - if field in self: - del self[field] - self['Requires-Dist'] += requirements - - # Mapping API - # TODO could add iter* variants - - def keys(self): - return list(_version2fieldlist(self['Metadata-Version'])) - - def __iter__(self): - for key in self.keys(): - yield key - - def values(self): - return [self[key] for key in self.keys()] - - def items(self): - return [(key, self[key]) for key in self.keys()] - - def __repr__(self): - return '<%s %s %s>' % (self.__class__.__name__, self.name, - self.version) - - -METADATA_FILENAME = 'pydist.json' - - -class Metadata(object): - """ - The metadata of a release. This implementation uses 2.0 (JSON) - metadata where possible. If not possible, it wraps a LegacyMetadata - instance which handles the key-value metadata format. - """ - - METADATA_VERSION_MATCHER = re.compile('^\d+(\.\d+)*$') - - NAME_MATCHER = re.compile('^[0-9A-Z]([0-9A-Z_.-]*[0-9A-Z])?$', re.I) - - VERSION_MATCHER = PEP426_VERSION_RE - - SUMMARY_MATCHER = re.compile('.{1,2047}') - - METADATA_VERSION = '2.0' - - GENERATOR = 'distlib (%s)' % __version__ - - MANDATORY_KEYS = { - 'name': (), - 'version': (), - 'summary': ('legacy',), - } - - INDEX_KEYS = ('name version license summary description author ' - 'author_email keywords platform home_page classifiers ' - 'download_url') - - DEPENDENCY_KEYS = ('extras run_requires test_requires build_requires ' - 'dev_requires provides meta_requires obsoleted_by ' - 'supports_environments') - - SYNTAX_VALIDATORS = { - 'metadata_version': (METADATA_VERSION_MATCHER, ()), - 'name': (NAME_MATCHER, ('legacy',)), - 'version': (VERSION_MATCHER, ('legacy',)), - 'summary': (SUMMARY_MATCHER, ('legacy',)), - } - - __slots__ = ('_legacy', '_data', 'scheme') - - def __init__(self, path=None, fileobj=None, mapping=None, - scheme='default'): - if [path, fileobj, mapping].count(None) < 2: - raise TypeError('path, fileobj and mapping are exclusive') - self._legacy = None - self._data = None - self.scheme = scheme - #import pdb; pdb.set_trace() - if mapping is not None: - try: - self._validate_mapping(mapping, scheme) - self._data = mapping - except MetadataUnrecognizedVersionError: - self._legacy = LegacyMetadata(mapping=mapping, scheme=scheme) - self.validate() - else: - data = None - if path: - with open(path, 'rb') as f: - data = f.read() - elif fileobj: - data = fileobj.read() - if data is None: - # Initialised with no args - to be added - self._data = { - 'metadata_version': self.METADATA_VERSION, - 'generator': self.GENERATOR, - } - else: - if not isinstance(data, text_type): - data = data.decode('utf-8') - try: - self._data = json.loads(data) - self._validate_mapping(self._data, scheme) - except ValueError: - # Note: MetadataUnrecognizedVersionError does not - # inherit from ValueError (it's a DistlibException, - # which should not inherit from ValueError). - # The ValueError comes from the json.load - if that - # succeeds and we get a validation error, we want - # that to propagate - self._legacy = LegacyMetadata(fileobj=StringIO(data), - scheme=scheme) - self.validate() - - common_keys = set(('name', 'version', 'license', 'keywords', 'summary')) - - none_list = (None, list) - none_dict = (None, dict) - - mapped_keys = { - 'run_requires': ('Requires-Dist', list), - 'build_requires': ('Setup-Requires-Dist', list), - 'dev_requires': none_list, - 'test_requires': none_list, - 'meta_requires': none_list, - 'extras': ('Provides-Extra', list), - 'modules': none_list, - 'namespaces': none_list, - 'exports': none_dict, - 'commands': none_dict, - 'classifiers': ('Classifier', list), - 'source_url': ('Download-URL', None), - 'metadata_version': ('Metadata-Version', None), - } - - del none_list, none_dict - - def __getattribute__(self, key): - common = object.__getattribute__(self, 'common_keys') - mapped = object.__getattribute__(self, 'mapped_keys') - if key in mapped: - lk, maker = mapped[key] - if self._legacy: - if lk is None: - result = None if maker is None else maker() - else: - result = self._legacy.get(lk) - else: - value = None if maker is None else maker() - result = self._data.get(key, value) - elif key not in common: - result = object.__getattribute__(self, key) - elif self._legacy: - result = self._legacy.get(key) - else: - result = self._data.get(key) - return result - - def _validate_value(self, key, value, scheme=None): - if key in self.SYNTAX_VALIDATORS: - pattern, exclusions = self.SYNTAX_VALIDATORS[key] - if (scheme or self.scheme) not in exclusions: - m = pattern.match(value) - if not m: - raise MetadataInvalidError('%r is an invalid value for ' - 'the %r property' % (value, - key)) - - def __setattr__(self, key, value): - self._validate_value(key, value) - common = object.__getattribute__(self, 'common_keys') - mapped = object.__getattribute__(self, 'mapped_keys') - if key in mapped: - lk, _ = mapped[key] - if self._legacy: - if lk is None: - raise NotImplementedError - self._legacy[lk] = value - else: - self._data[key] = value - elif key not in common: - object.__setattr__(self, key, value) - else: - if key == 'keywords': - if isinstance(value, string_types): - value = value.strip() - if value: - value = value.split() - else: - value = [] - if self._legacy: - self._legacy[key] = value - else: - self._data[key] = value - - @property - def name_and_version(self): - return _get_name_and_version(self.name, self.version, True) - - @property - def provides(self): - if self._legacy: - result = self._legacy['Provides-Dist'] - else: - result = self._data.setdefault('provides', []) - s = '%s (%s)' % (self.name, self.version) - if s not in result: - result.append(s) - return result - - @provides.setter - def provides(self, value): - if self._legacy: - self._legacy['Provides-Dist'] = value - else: - self._data['provides'] = value - - def get_requirements(self, reqts, extras=None, env=None): - """ - Base method to get dependencies, given a set of extras - to satisfy and an optional environment context. - :param reqts: A list of sometimes-wanted dependencies, - perhaps dependent on extras and environment. - :param extras: A list of optional components being requested. - :param env: An optional environment for marker evaluation. - """ - if self._legacy: - result = reqts - else: - result = [] - extras = get_extras(extras or [], self.extras) - for d in reqts: - if 'extra' not in d and 'environment' not in d: - # unconditional - include = True - else: - if 'extra' not in d: - # Not extra-dependent - only environment-dependent - include = True - else: - include = d.get('extra') in extras - if include: - # Not excluded because of extras, check environment - marker = d.get('environment') - if marker: - include = interpret(marker, env) - if include: - result.extend(d['requires']) - for key in ('build', 'dev', 'test'): - e = ':%s:' % key - if e in extras: - extras.remove(e) - # A recursive call, but it should terminate since 'test' - # has been removed from the extras - reqts = self._data.get('%s_requires' % key, []) - result.extend(self.get_requirements(reqts, extras=extras, - env=env)) - return result - - @property - def dictionary(self): - if self._legacy: - return self._from_legacy() - return self._data - - @property - def dependencies(self): - if self._legacy: - raise NotImplementedError - else: - return extract_by_key(self._data, self.DEPENDENCY_KEYS) - - @dependencies.setter - def dependencies(self, value): - if self._legacy: - raise NotImplementedError - else: - self._data.update(value) - - def _validate_mapping(self, mapping, scheme): - if mapping.get('metadata_version') != self.METADATA_VERSION: - raise MetadataUnrecognizedVersionError() - missing = [] - for key, exclusions in self.MANDATORY_KEYS.items(): - if key not in mapping: - if scheme not in exclusions: - missing.append(key) - if missing: - msg = 'Missing metadata items: %s' % ', '.join(missing) - raise MetadataMissingError(msg) - for k, v in mapping.items(): - self._validate_value(k, v, scheme) - - def validate(self): - if self._legacy: - missing, warnings = self._legacy.check(True) - if missing or warnings: - logger.warning('Metadata: missing: %s, warnings: %s', - missing, warnings) - else: - self._validate_mapping(self._data, self.scheme) - - def todict(self): - if self._legacy: - return self._legacy.todict(True) - else: - result = extract_by_key(self._data, self.INDEX_KEYS) - return result - - def _from_legacy(self): - assert self._legacy and not self._data - result = { - 'metadata_version': self.METADATA_VERSION, - 'generator': self.GENERATOR, - } - lmd = self._legacy.todict(True) # skip missing ones - for k in ('name', 'version', 'license', 'summary', 'description', - 'classifier'): - if k in lmd: - if k == 'classifier': - nk = 'classifiers' - else: - nk = k - result[nk] = lmd[k] - kw = lmd.get('Keywords', []) - if kw == ['']: - kw = [] - result['keywords'] = kw - keys = (('requires_dist', 'run_requires'), - ('setup_requires_dist', 'build_requires')) - for ok, nk in keys: - if ok in lmd and lmd[ok]: - result[nk] = [{'requires': lmd[ok]}] - result['provides'] = self.provides - author = {} - maintainer = {} - return result - - LEGACY_MAPPING = { - 'name': 'Name', - 'version': 'Version', - 'license': 'License', - 'summary': 'Summary', - 'description': 'Description', - 'classifiers': 'Classifier', - } - - def _to_legacy(self): - def process_entries(entries): - reqts = set() - for e in entries: - extra = e.get('extra') - env = e.get('environment') - rlist = e['requires'] - for r in rlist: - if not env and not extra: - reqts.add(r) - else: - marker = '' - if extra: - marker = 'extra == "%s"' % extra - if env: - if marker: - marker = '(%s) and %s' % (env, marker) - else: - marker = env - reqts.add(';'.join((r, marker))) - return reqts - - assert self._data and not self._legacy - result = LegacyMetadata() - nmd = self._data - for nk, ok in self.LEGACY_MAPPING.items(): - if nk in nmd: - result[ok] = nmd[nk] - 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 - return result - - def write(self, path=None, fileobj=None, legacy=False, skip_unknown=True): - if [path, fileobj].count(None) != 1: - raise ValueError('Exactly one of path and fileobj is needed') - self.validate() - if legacy: - if self._legacy: - legacy_md = self._legacy - else: - legacy_md = self._to_legacy() - if path: - legacy_md.write(path, skip_unknown=skip_unknown) - else: - legacy_md.write_file(fileobj, skip_unknown=skip_unknown) - else: - if self._legacy: - d = self._from_legacy() - else: - d = self._data - if fileobj: - json.dump(d, fileobj, ensure_ascii=True, indent=2, - sort_keys=True) - else: - with codecs.open(path, 'w', 'utf-8') as f: - json.dump(d, f, ensure_ascii=True, indent=2, - sort_keys=True) - - def add_requirements(self, requirements): - if self._legacy: - self._legacy.add_requirements(requirements) - else: - run_requires = self._data.setdefault('run_requires', []) - always = None - for entry in run_requires: - if 'environment' not in entry and 'extra' not in entry: - always = entry - break - if always is None: - always = { 'requires': requirements } - run_requires.insert(0, always) - else: - rset = set(always['requires']) | set(requirements) - always['requires'] = sorted(rset) - - def __repr__(self): - name = self.name or '(no name)' - version = self.version or 'no version' - return '<%s %s %s (%s)>' % (self.__class__.__name__, - self.metadata_version, name, version) diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/resources.py b/vendor/pip-1.5.6/pip/_vendor/distlib/resources.py deleted file mode 100644 index 567840e..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/distlib/resources.py +++ /dev/null @@ -1,317 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2013 Vinay Sajip. -# Licensed to the Python Software Foundation under a contributor agreement. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -from __future__ import unicode_literals - -import bisect -import io -import logging -import os -import pkgutil -import shutil -import sys -import types -import zipimport - -from . import DistlibException -from .util import cached_property, get_cache_base, path_to_cache_dir, Cache - -logger = logging.getLogger(__name__) - - -cache = None # created when needed - - -class ResourceCache(Cache): - def __init__(self, base=None): - if base is None: - # Use native string to avoid issues on 2.x: see Python #20140. - base = os.path.join(get_cache_base(), str('resource-cache')) - super(ResourceCache, self).__init__(base) - - def is_stale(self, resource, path): - """ - Is the cache stale for the given resource? - - :param resource: The :class:`Resource` being cached. - :param path: The path of the resource in the cache. - :return: True if the cache is stale. - """ - # Cache invalidation is a hard problem :-) - return True - - def get(self, resource): - """ - Get a resource into the cache, - - :param resource: A :class:`Resource` instance. - :return: The pathname of the resource in the cache. - """ - prefix, path = resource.finder.get_cache_info(resource) - if prefix is None: - result = path - else: - result = os.path.join(self.base, self.prefix_to_dir(prefix), path) - dirname = os.path.dirname(result) - if not os.path.isdir(dirname): - os.makedirs(dirname) - if not os.path.exists(result): - stale = True - else: - stale = self.is_stale(resource, path) - if stale: - # write the bytes of the resource to the cache location - with open(result, 'wb') as f: - f.write(resource.bytes) - return result - - -class ResourceBase(object): - def __init__(self, finder, name): - self.finder = finder - self.name = name - - -class Resource(ResourceBase): - """ - A class representing an in-package resource, such as a data file. This is - not normally instantiated by user code, but rather by a - :class:`ResourceFinder` which manages the resource. - """ - is_container = False # Backwards compatibility - - def as_stream(self): - """ - Get the resource as a stream. - - This is not a property to make it obvious that it returns a new stream - each time. - """ - return self.finder.get_stream(self) - - @cached_property - def file_path(self): - global cache - if cache is None: - cache = ResourceCache() - return cache.get(self) - - @cached_property - def bytes(self): - return self.finder.get_bytes(self) - - @cached_property - def size(self): - return self.finder.get_size(self) - - -class ResourceContainer(ResourceBase): - is_container = True # Backwards compatibility - - @cached_property - def resources(self): - return self.finder.get_resources(self) - - -class ResourceFinder(object): - """ - Resource finder for file system resources. - """ - def __init__(self, module): - self.module = module - self.loader = getattr(module, '__loader__', None) - self.base = os.path.dirname(getattr(module, '__file__', '')) - - def _adjust_path(self, path): - return os.path.realpath(path) - - def _make_path(self, resource_name): - parts = resource_name.split('/') - parts.insert(0, self.base) - result = os.path.join(*parts) - return self._adjust_path(result) - - def _find(self, path): - return os.path.exists(path) - - def get_cache_info(self, resource): - return None, resource.path - - def find(self, resource_name): - path = self._make_path(resource_name) - if not self._find(path): - result = None - else: - if self._is_directory(path): - result = ResourceContainer(self, resource_name) - else: - result = Resource(self, resource_name) - result.path = path - return result - - def get_stream(self, resource): - return open(resource.path, 'rb') - - def get_bytes(self, resource): - with open(resource.path, 'rb') as f: - return f.read() - - def get_size(self, resource): - return os.path.getsize(resource.path) - - def get_resources(self, resource): - def allowed(f): - return f != '__pycache__' and not f.endswith(('.pyc', '.pyo')) - return set([f for f in os.listdir(resource.path) if allowed(f)]) - - def is_container(self, resource): - return self._is_directory(resource.path) - - _is_directory = staticmethod(os.path.isdir) - - -class ZipResourceFinder(ResourceFinder): - """ - Resource finder for resources in .zip files. - """ - def __init__(self, module): - super(ZipResourceFinder, self).__init__(module) - archive = self.loader.archive - self.prefix_len = 1 + len(archive) - # PyPy doesn't have a _files attr on zipimporter, and you can't set one - if hasattr(self.loader, '_files'): - self._files = self.loader._files - else: - self._files = zipimport._zip_directory_cache[archive] - self.index = sorted(self._files) - - def _adjust_path(self, path): - return path - - def _find(self, path): - path = path[self.prefix_len:] - if path in self._files: - result = True - else: - if path and path[-1] != os.sep: - path = path + os.sep - i = bisect.bisect(self.index, path) - try: - result = self.index[i].startswith(path) - except IndexError: - result = False - if not result: - logger.debug('_find failed: %r %r', path, self.loader.prefix) - else: - logger.debug('_find worked: %r %r', path, self.loader.prefix) - return result - - def get_cache_info(self, resource): - prefix = self.loader.archive - path = resource.path[1 + len(prefix):] - return prefix, path - - def get_bytes(self, resource): - return self.loader.get_data(resource.path) - - def get_stream(self, resource): - return io.BytesIO(self.get_bytes(resource)) - - def get_size(self, resource): - path = resource.path[self.prefix_len:] - return self._files[path][3] - - def get_resources(self, resource): - path = resource.path[self.prefix_len:] - if path and path[-1] != os.sep: - path += os.sep - plen = len(path) - result = set() - i = bisect.bisect(self.index, path) - while i < len(self.index): - if not self.index[i].startswith(path): - break - s = self.index[i][plen:] - result.add(s.split(os.sep, 1)[0]) # only immediate children - i += 1 - return result - - def _is_directory(self, path): - path = path[self.prefix_len:] - if path and path[-1] != os.sep: - path += os.sep - i = bisect.bisect(self.index, path) - try: - result = self.index[i].startswith(path) - except IndexError: - result = False - return result - -_finder_registry = { - type(None): ResourceFinder, - zipimport.zipimporter: ZipResourceFinder -} - -try: - import _frozen_importlib - _finder_registry[_frozen_importlib.SourceFileLoader] = ResourceFinder - _finder_registry[_frozen_importlib.FileFinder] = ResourceFinder -except (ImportError, AttributeError): - pass - - -def register_finder(loader, finder_maker): - _finder_registry[type(loader)] = finder_maker - -_finder_cache = {} - - -def finder(package): - """ - Return a resource finder for a package. - :param package: The name of the package. - :return: A :class:`ResourceFinder` instance for the package. - """ - if package in _finder_cache: - result = _finder_cache[package] - else: - if package not in sys.modules: - __import__(package) - module = sys.modules[package] - path = getattr(module, '__path__', None) - if path is None: - raise DistlibException('You cannot get a finder for a module, ' - 'only for a package') - loader = getattr(module, '__loader__', None) - finder_maker = _finder_registry.get(type(loader)) - if finder_maker is None: - raise DistlibException('Unable to locate finder for %r' % package) - result = finder_maker(module) - _finder_cache[package] = result - return result - - -_dummy_module = types.ModuleType(str('__dummy__')) - - -def finder_for_path(path): - """ - Return a resource finder for a path, which should represent a container. - - :param path: The path. - :return: A :class:`ResourceFinder` instance for the path. - """ - result = None - # calls any path hooks, gets importer into cache - pkgutil.get_importer(path) - loader = sys.path_importer_cache.get(path) - finder = _finder_registry.get(type(loader)) - if finder: - module = _dummy_module - module.__file__ = os.path.join(path, '') - module.__loader__ = loader - result = finder(module) - return result diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/scripts.py b/vendor/pip-1.5.6/pip/_vendor/distlib/scripts.py deleted file mode 100644 index 36850b2..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/distlib/scripts.py +++ /dev/null @@ -1,323 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2013 Vinay Sajip. -# Licensed to the Python Software Foundation under a contributor agreement. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -from io import BytesIO -import logging -import os -import re -import struct -import sys - -from .compat import sysconfig, fsencode, detect_encoding, ZipFile -from .resources import finder -from .util import (FileOperator, get_export_entry, convert_path, - get_executable, in_venv) - -logger = logging.getLogger(__name__) - -_DEFAULT_MANIFEST = ''' - - - - - - - - - - - - -'''.strip() - -# check if Python is called on the first line with this expression -FIRST_LINE_RE = re.compile(b'^#!.*pythonw?[0-9.]*([ \t].*)?$') -SCRIPT_TEMPLATE = '''# -*- coding: utf-8 -*- -if __name__ == '__main__': - import sys, re - - def _resolve(module, func): - __import__(module) - mod = sys.modules[module] - parts = func.split('.') - result = getattr(mod, parts.pop(0)) - for p in parts: - result = getattr(result, p) - return result - - try: - sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) - - func = _resolve('%(module)s', '%(func)s') - rc = func() # None interpreted as 0 - except Exception as e: # only supporting Python >= 2.6 - sys.stderr.write('%%s\\n' %% e) - rc = 1 - sys.exit(rc) -''' - - -class ScriptMaker(object): - """ - A class to copy or create scripts from source scripts or callable - specifications. - """ - script_template = SCRIPT_TEMPLATE - - executable = None # for shebangs - - def __init__(self, source_dir, target_dir, add_launchers=True, - dry_run=False, fileop=None): - self.source_dir = source_dir - self.target_dir = target_dir - self.add_launchers = add_launchers - self.force = False - self.clobber = False - # It only makes sense to set mode bits on POSIX. - self.set_mode = (os.name == 'posix') - self.variants = set(('', 'X.Y')) - self._fileop = fileop or FileOperator(dry_run) - - def _get_alternate_executable(self, executable, options): - if options.get('gui', False) and os.name == 'nt': - dn, fn = os.path.split(executable) - fn = fn.replace('python', 'pythonw') - executable = os.path.join(dn, fn) - return executable - - def _get_shebang(self, encoding, post_interp=b'', options=None): - enquote = True - if self.executable: - executable = self.executable - enquote = False # assume this will be taken care of - elif not sysconfig.is_python_build(): - executable = get_executable() - elif in_venv(): - executable = os.path.join(sysconfig.get_path('scripts'), - 'python%s' % sysconfig.get_config_var('EXE')) - else: - executable = os.path.join( - sysconfig.get_config_var('BINDIR'), - 'python%s%s' % (sysconfig.get_config_var('VERSION'), - sysconfig.get_config_var('EXE'))) - if options: - executable = self._get_alternate_executable(executable, options) - - # 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 and ' ' in executable: - executable = '"%s"' % executable - executable = fsencode(executable) - shebang = b'#!' + executable + post_interp + b'\n' - # Python parser starts to read a script using UTF-8 until - # it gets a #coding:xxx cookie. The shebang has to be the - # first line of a file, the #coding:xxx cookie cannot be - # written before. So the shebang has to be decodable from - # UTF-8. - try: - shebang.decode('utf-8') - except UnicodeDecodeError: - raise ValueError( - 'The shebang (%r) is not decodable from utf-8' % shebang) - # If the script is encoded to a custom encoding (use a - # #coding:xxx cookie), the shebang has to be decodable from - # the script encoding too. - if encoding != 'utf-8': - try: - shebang.decode(encoding) - except UnicodeDecodeError: - raise ValueError( - 'The shebang (%r) is not decodable ' - 'from the script encoding (%r)' % (shebang, encoding)) - return shebang - - def _get_script_text(self, entry): - return self.script_template % dict(module=entry.prefix, - func=entry.suffix) - - manifest = _DEFAULT_MANIFEST - - def get_manifest(self, exename): - base = os.path.basename(exename) - return self.manifest % base - - def _write_script(self, names, shebang, script_bytes, filenames, ext): - use_launcher = self.add_launchers and os.name == 'nt' - linesep = os.linesep.encode('utf-8') - if not use_launcher: - script_bytes = shebang + linesep + script_bytes - else: - if ext == 'py': - launcher = self._get_launcher('t') - else: - launcher = self._get_launcher('w') - stream = BytesIO() - with ZipFile(stream, 'w') as zf: - zf.writestr('__main__.py', script_bytes) - zip_data = stream.getvalue() - script_bytes = launcher + shebang + linesep + zip_data - for name in names: - outname = os.path.join(self.target_dir, name) - if use_launcher: - n, e = os.path.splitext(outname) - if e.startswith('.py'): - outname = n - outname = '%s.exe' % outname - try: - self._fileop.write_binary_file(outname, script_bytes) - except Exception: - # Failed writing an executable - it might be in use. - logger.warning('Failed to write executable - trying to ' - 'use .deleteme logic') - dfname = '%s.deleteme' % outname - if os.path.exists(dfname): - os.remove(dfname) # Not allowed to fail here - os.rename(outname, dfname) # nor here - self._fileop.write_binary_file(outname, script_bytes) - logger.debug('Able to replace executable using ' - '.deleteme logic') - try: - os.remove(dfname) - except Exception: - pass # still in use - ignore error - else: - if os.name == 'nt' and not outname.endswith('.' + ext): - outname = '%s.%s' % (outname, ext) - if os.path.exists(outname) and not self.clobber: - logger.warning('Skipping existing file %s', outname) - continue - self._fileop.write_binary_file(outname, script_bytes) - if self.set_mode: - self._fileop.set_executable_mode([outname]) - filenames.append(outname) - - def _make_script(self, entry, filenames, options=None): - shebang = self._get_shebang('utf-8', options=options) - script = self._get_script_text(entry).encode('utf-8') - name = entry.name - scriptnames = set() - if '' in self.variants: - scriptnames.add(name) - if 'X' in self.variants: - scriptnames.add('%s%s' % (name, sys.version[0])) - if 'X.Y' in self.variants: - scriptnames.add('%s-%s' % (name, sys.version[:3])) - if options and options.get('gui', False): - ext = 'pyw' - else: - ext = 'py' - self._write_script(scriptnames, shebang, script, filenames, ext) - - def _copy_script(self, script, filenames): - adjust = False - script = os.path.join(self.source_dir, convert_path(script)) - outname = os.path.join(self.target_dir, os.path.basename(script)) - if not self.force and not self._fileop.newer(script, outname): - logger.debug('not copying %s (up-to-date)', script) - return - - # Always open the file, but ignore failures in dry-run mode -- - # that way, we'll get accurate feedback if we can read the - # script. - try: - f = open(script, 'rb') - except IOError: - if not self.dry_run: - raise - f = None - else: - encoding, lines = detect_encoding(f.readline) - f.seek(0) - first_line = f.readline() - if not first_line: - logger.warning('%s: %s is an empty file (skipping)', - self.get_command_name(), script) - return - - match = FIRST_LINE_RE.match(first_line.replace(b'\r\n', b'\n')) - if match: - adjust = True - post_interp = match.group(1) or b'' - - if not adjust: - if f: - f.close() - self._fileop.copy_file(script, outname) - if self.set_mode: - self._fileop.set_executable_mode([outname]) - filenames.append(outname) - else: - logger.info('copying and adjusting %s -> %s', script, - self.target_dir) - if not self._fileop.dry_run: - shebang = self._get_shebang(encoding, post_interp) - if b'pythonw' in first_line: - ext = 'pyw' - else: - ext = 'py' - n = os.path.basename(outname) - self._write_script([n], shebang, f.read(), filenames, ext) - if f: - f.close() - - @property - def dry_run(self): - return self._fileop.dry_run - - @dry_run.setter - def dry_run(self, value): - self._fileop.dry_run = value - - if os.name == 'nt': - # Executable launcher support. - # Launchers are from https://bitbucket.org/vinay.sajip/simple_launcher/ - - def _get_launcher(self, kind): - if struct.calcsize('P') == 8: # 64-bit - bits = '64' - else: - bits = '32' - name = '%s%s.exe' % (kind, bits) - # 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 - - # Public API follows - - def make(self, specification, options=None): - """ - Make a script. - - :param specification: The specification, which is either a valid export - entry specification (to make a script from a - callable) or a filename (to make a script by - copying from a source location). - :param options: A dictionary of options controlling script generation. - :return: A list of all absolute pathnames written to. - """ - filenames = [] - entry = get_export_entry(specification) - if entry is None: - self._copy_script(specification, filenames) - else: - self._make_script(entry, filenames, options=options) - return filenames - - def make_multiple(self, specifications, options=None): - """ - Take a list of specifications and make scripts from them, - :param specifications: A list of specifications. - :return: A list of all absolute pathnames written to, - """ - filenames = [] - for specification in specifications: - filenames.extend(self.make(specification, options)) - return filenames diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/t32.exe b/vendor/pip-1.5.6/pip/_vendor/distlib/t32.exe deleted file mode 100644 index 43f39f31e980ee403577a508fb64dddadf24477f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 91136 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∈;+_`Yk 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 MlkRZf|BD0v1$34UW&i*H diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/util.py b/vendor/pip-1.5.6/pip/_vendor/distlib/util.py deleted file mode 100644 index 29ec519..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/distlib/util.py +++ /dev/null @@ -1,1575 +0,0 @@ -# -# Copyright (C) 2012-2013 The Python Software Foundation. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -import codecs -from collections import deque -import contextlib -import csv -from glob import iglob as std_iglob -import io -import json -import logging -import os -import py_compile -import re -import shutil -import socket -import ssl -import subprocess -import sys -import tarfile -import tempfile -try: - import threading -except ImportError: - import dummy_threading as threading -import time - -from . import DistlibException -from .compat import (string_types, text_type, shutil, raw_input, StringIO, - cache_from_source, urlopen, httplib, xmlrpclib, splittype, - HTTPHandler, HTTPSHandler as BaseHTTPSHandler, - BaseConfigurator, valid_ident, Container, configparser, - URLError, match_hostname, CertificateError, ZipFile) - -logger = logging.getLogger(__name__) - -# -# Requirement parsing code for name + optional constraints + optional extras -# -# e.g. 'foo >= 1.2, < 2.0 [bar, baz]' -# -# The regex can seem a bit hairy, so we build it up out of smaller pieces -# which are manageable. -# - -COMMA = r'\s*,\s*' -COMMA_RE = re.compile(COMMA) - -IDENT = r'(\w|[.-])+' -EXTRA_IDENT = r'(\*|:(\*|\w+):|' + IDENT + ')' -VERSPEC = IDENT + r'\*?' - -RELOP = '([<>=!~]=)|[<>]' - -# -# The first relop is optional - if absent, will be taken as '~=' -# -BARE_CONSTRAINTS = ('(' + RELOP + r')?\s*(' + VERSPEC + ')(' + COMMA + '(' + - RELOP + r')\s*(' + VERSPEC + '))*') - -DIRECT_REF = '(from\s+(?P.*))' - -# -# Either the bare constraints or the bare constraints in parentheses -# -CONSTRAINTS = (r'\(\s*(?P' + BARE_CONSTRAINTS + '|' + DIRECT_REF + - r')\s*\)|(?P' + BARE_CONSTRAINTS + '\s*)') - -EXTRA_LIST = EXTRA_IDENT + '(' + COMMA + EXTRA_IDENT + ')*' -EXTRAS = r'\[\s*(?P' + EXTRA_LIST + r')?\s*\]' -REQUIREMENT = ('(?P' + IDENT + r')\s*(' + EXTRAS + r'\s*)?(\s*' + - CONSTRAINTS + ')?$') -REQUIREMENT_RE = re.compile(REQUIREMENT) - -# -# Used to scan through the constraints -# -RELOP_IDENT = '(?P' + RELOP + r')\s*(?P' + VERSPEC + ')' -RELOP_IDENT_RE = re.compile(RELOP_IDENT) - -def parse_requirement(s): - - def get_constraint(m): - d = m.groupdict() - return d['op'], d['vn'] - - result = None - m = REQUIREMENT_RE.match(s) - if m: - d = m.groupdict() - name = d['dn'] - cons = d['c1'] or d['c2'] - if not d['diref']: - url = None - else: - # direct reference - cons = None - url = d['diref'].strip() - if not cons: - cons = None - constr = '' - rs = d['dn'] - else: - if cons[0] not in '<>!=': - cons = '~=' + cons - iterator = RELOP_IDENT_RE.finditer(cons) - cons = [get_constraint(m) for m in iterator] - rs = '%s (%s)' % (name, ', '.join(['%s %s' % con for con in cons])) - if not d['ex']: - extras = None - else: - extras = COMMA_RE.split(d['ex']) - result = Container(name=name, constraints=cons, extras=extras, - requirement=rs, source=s, url=url) - return result - - -def get_resources_dests(resources_root, rules): - """Find destinations for resources files""" - - def get_rel_path(base, path): - # normalizes and returns a lstripped-/-separated path - base = base.replace(os.path.sep, '/') - path = path.replace(os.path.sep, '/') - assert path.startswith(base) - return path[len(base):].lstrip('/') - - - destinations = {} - for base, suffix, dest in rules: - prefix = os.path.join(resources_root, base) - for abs_base in iglob(prefix): - abs_glob = os.path.join(abs_base, suffix) - for abs_path in iglob(abs_glob): - resource_file = get_rel_path(resources_root, abs_path) - if dest is None: # remove the entry if it was here - destinations.pop(resource_file, None) - else: - rel_path = get_rel_path(abs_base, abs_path) - rel_dest = dest.replace(os.path.sep, '/').rstrip('/') - destinations[resource_file] = rel_dest + '/' + rel_path - return destinations - - -def in_venv(): - if hasattr(sys, 'real_prefix'): - # virtualenv venvs - result = True - else: - # PEP 405 venvs - result = sys.prefix != getattr(sys, 'base_prefix', sys.prefix) - return result - - -def get_executable(): - if sys.platform == 'darwin' and ('__PYVENV_LAUNCHER__' - in os.environ): - result = os.environ['__PYVENV_LAUNCHER__'] - else: - result = sys.executable - return result - - -def proceed(prompt, allowed_chars, error_prompt=None, default=None): - p = prompt - while True: - s = raw_input(p) - p = prompt - if not s and default: - s = default - if s: - c = s[0].lower() - if c in allowed_chars: - break - if error_prompt: - p = '%c: %s\n%s' % (c, error_prompt, prompt) - return c - - -def extract_by_key(d, keys): - if isinstance(keys, string_types): - keys = keys.split() - result = {} - for key in keys: - if key in d: - result[key] = d[key] - return result - -def read_exports(stream): - if sys.version_info[0] >= 3: - # needs to be a text stream - stream = codecs.getreader('utf-8')(stream) - # Try to load as JSON, falling back on legacy format - data = stream.read() - stream = StringIO(data) - try: - data = json.load(stream) - result = data['exports'] - for group, entries in result.items(): - for k, v in entries.items(): - s = '%s = %s' % (k, v) - entry = get_export_entry(s) - assert entry is not None - entries[k] = entry - return result - except Exception: - stream.seek(0, 0) - cp = configparser.ConfigParser() - if hasattr(cp, 'read_file'): - cp.read_file(stream) - else: - cp.readfp(stream) - result = {} - for key in cp.sections(): - result[key] = entries = {} - for name, value in cp.items(key): - s = '%s = %s' % (name, value) - entry = get_export_entry(s) - assert entry is not None - #entry.dist = self - entries[name] = entry - return result - - -def write_exports(exports, stream): - if sys.version_info[0] >= 3: - # needs to be a text stream - stream = codecs.getwriter('utf-8')(stream) - cp = configparser.ConfigParser() - for k, v in exports.items(): - # TODO check k, v for valid values - cp.add_section(k) - for entry in v.values(): - if entry.suffix is None: - s = entry.prefix - else: - s = '%s:%s' % (entry.prefix, entry.suffix) - if entry.flags: - s = '%s [%s]' % (s, ', '.join(entry.flags)) - cp.set(k, entry.name, s) - cp.write(stream) - - -@contextlib.contextmanager -def tempdir(): - td = tempfile.mkdtemp() - try: - yield td - finally: - shutil.rmtree(td) - -@contextlib.contextmanager -def chdir(d): - cwd = os.getcwd() - try: - os.chdir(d) - yield - finally: - os.chdir(cwd) - - -@contextlib.contextmanager -def socket_timeout(seconds=15): - cto = socket.getdefaulttimeout() - try: - socket.setdefaulttimeout(seconds) - yield - finally: - socket.setdefaulttimeout(cto) - - -class cached_property(object): - def __init__(self, func): - self.func = func - #for attr in ('__name__', '__module__', '__doc__'): - # setattr(self, attr, getattr(func, attr, None)) - - def __get__(self, obj, cls=None): - if obj is None: - return self - value = self.func(obj) - object.__setattr__(obj, self.func.__name__, value) - #obj.__dict__[self.func.__name__] = value = self.func(obj) - return value - -def convert_path(pathname): - """Return 'pathname' as a name that will work on the native filesystem. - - The path is split on '/' and put back together again using the current - directory separator. Needed because filenames in the setup script are - always supplied in Unix style, and have to be converted to the local - convention before we can actually use them in the filesystem. Raises - ValueError on non-Unix-ish systems if 'pathname' either starts or - ends with a slash. - """ - if os.sep == '/': - return pathname - if not pathname: - return pathname - if pathname[0] == '/': - raise ValueError("path '%s' cannot be absolute" % pathname) - if pathname[-1] == '/': - raise ValueError("path '%s' cannot end with '/'" % pathname) - - paths = pathname.split('/') - while os.curdir in paths: - paths.remove(os.curdir) - if not paths: - return os.curdir - return os.path.join(*paths) - - -class FileOperator(object): - def __init__(self, dry_run=False): - self.dry_run = dry_run - self.ensured = set() - self._init_record() - - def _init_record(self): - self.record = False - self.files_written = set() - self.dirs_created = set() - - def record_as_written(self, path): - if self.record: - self.files_written.add(path) - - def newer(self, source, target): - """Tell if the target is newer than the source. - - Returns true if 'source' exists and is more recently modified than - 'target', or if 'source' exists and 'target' doesn't. - - Returns false if both exist and 'target' is the same age or younger - than 'source'. Raise PackagingFileError if 'source' does not exist. - - Note that this test is not very accurate: files created in the same - second will have the same "age". - """ - if not os.path.exists(source): - raise DistlibException("file '%r' does not exist" % - os.path.abspath(source)) - if not os.path.exists(target): - return True - - return os.stat(source).st_mtime > os.stat(target).st_mtime - - def copy_file(self, infile, outfile, check=True): - """Copy a file respecting dry-run and force flags. - """ - self.ensure_dir(os.path.dirname(outfile)) - logger.info('Copying %s to %s', infile, outfile) - if not self.dry_run: - msg = None - if check: - if os.path.islink(outfile): - msg = '%s is a symlink' % outfile - elif os.path.exists(outfile) and not os.path.isfile(outfile): - msg = '%s is a non-regular file' % outfile - if msg: - raise ValueError(msg + ' which would be overwritten') - shutil.copyfile(infile, outfile) - self.record_as_written(outfile) - - def copy_stream(self, instream, outfile, encoding=None): - assert not os.path.isdir(outfile) - self.ensure_dir(os.path.dirname(outfile)) - logger.info('Copying stream %s to %s', instream, outfile) - if not self.dry_run: - if encoding is None: - outstream = open(outfile, 'wb') - else: - outstream = codecs.open(outfile, 'w', encoding=encoding) - try: - shutil.copyfileobj(instream, outstream) - finally: - outstream.close() - self.record_as_written(outfile) - - def write_binary_file(self, path, data): - self.ensure_dir(os.path.dirname(path)) - if not self.dry_run: - with open(path, 'wb') as f: - f.write(data) - self.record_as_written(path) - - def write_text_file(self, path, data, encoding): - self.ensure_dir(os.path.dirname(path)) - if not self.dry_run: - with open(path, 'wb') as f: - f.write(data.encode(encoding)) - self.record_as_written(path) - - def set_mode(self, bits, mask, files): - if os.name == 'posix': - # Set the executable bits (owner, group, and world) on - # all the files specified. - for f in files: - if self.dry_run: - logger.info("changing mode of %s", f) - else: - mode = (os.stat(f).st_mode | bits) & mask - logger.info("changing mode of %s to %o", f, mode) - os.chmod(f, mode) - - set_executable_mode = lambda s, f: s.set_mode(0o555, 0o7777, f) - - def ensure_dir(self, path): - path = os.path.abspath(path) - if path not in self.ensured and not os.path.exists(path): - self.ensured.add(path) - d, f = os.path.split(path) - self.ensure_dir(d) - logger.info('Creating %s' % path) - if not self.dry_run: - os.mkdir(path) - if self.record: - self.dirs_created.add(path) - - def byte_compile(self, path, optimize=False, force=False, prefix=None): - dpath = cache_from_source(path, not optimize) - logger.info('Byte-compiling %s to %s', path, dpath) - if not self.dry_run: - if force or self.newer(path, dpath): - if not prefix: - diagpath = None - else: - assert path.startswith(prefix) - diagpath = path[len(prefix):] - py_compile.compile(path, dpath, diagpath, True) # raise error - self.record_as_written(dpath) - return dpath - - def ensure_removed(self, path): - if os.path.exists(path): - if os.path.isdir(path) and not os.path.islink(path): - logger.debug('Removing directory tree at %s', path) - if not self.dry_run: - shutil.rmtree(path) - if self.record: - if path in self.dirs_created: - self.dirs_created.remove(path) - else: - if os.path.islink(path): - s = 'link' - else: - s = 'file' - logger.debug('Removing %s %s', s, path) - if not self.dry_run: - os.remove(path) - if self.record: - if path in self.files_written: - self.files_written.remove(path) - - def is_writable(self, path): - result = False - while not result: - if os.path.exists(path): - result = os.access(path, os.W_OK) - break - parent = os.path.dirname(path) - if parent == path: - break - path = parent - return result - - def commit(self): - """ - Commit recorded changes, turn off recording, return - changes. - """ - assert self.record - result = self.files_written, self.dirs_created - self._init_record() - return result - - def rollback(self): - if not self.dry_run: - for f in list(self.files_written): - if os.path.exists(f): - os.remove(f) - # dirs should all be empty now, except perhaps for - # __pycache__ subdirs - # reverse so that subdirs appear before their parents - dirs = sorted(self.dirs_created, reverse=True) - for d in dirs: - flist = os.listdir(d) - if flist: - assert flist == ['__pycache__'] - sd = os.path.join(d, flist[0]) - os.rmdir(sd) - os.rmdir(d) # should fail if non-empty - self._init_record() - -def resolve(module_name, dotted_path): - if module_name in sys.modules: - mod = sys.modules[module_name] - else: - mod = __import__(module_name) - if dotted_path is None: - result = mod - else: - parts = dotted_path.split('.') - result = getattr(mod, parts.pop(0)) - for p in parts: - result = getattr(result, p) - return result - - -class ExportEntry(object): - def __init__(self, name, prefix, suffix, flags): - self.name = name - self.prefix = prefix - self.suffix = suffix - self.flags = flags - - @cached_property - def value(self): - return resolve(self.prefix, self.suffix) - - def __repr__(self): - return '' % (self.name, self.prefix, - self.suffix, self.flags) - - def __eq__(self, other): - if not isinstance(other, ExportEntry): - result = False - else: - result = (self.name == other.name and - self.prefix == other.prefix and - self.suffix == other.suffix and - self.flags == other.flags) - return result - - __hash__ = object.__hash__ - - -ENTRY_RE = re.compile(r'''(?P(\w|[-.])+) - \s*=\s*(?P(\w+)([:\.]\w+)*) - \s*(\[\s*(?P\w+(=\w+)?(,\s*\w+(=\w+)?)*)\s*\])? - ''', re.VERBOSE) - - -def get_export_entry(specification): - m = ENTRY_RE.search(specification) - if not m: - result = None - if '[' in specification or ']' in specification: - raise DistlibException('Invalid specification ' - '%r' % specification) - else: - d = m.groupdict() - name = d['name'] - path = d['callable'] - colons = path.count(':') - if colons == 0: - prefix, suffix = path, None - else: - if colons != 1: - raise DistlibException('Invalid specification ' - '%r' % specification) - prefix, suffix = path.split(':') - flags = d['flags'] - if flags is None: - if '[' in specification or ']' in specification: - raise DistlibException('Invalid specification ' - '%r' % specification) - flags = [] - else: - flags = [f.strip() for f in flags.split(',')] - result = ExportEntry(name, prefix, suffix, flags) - return result - - -def get_cache_base(suffix=None): - """ - Return the default base location for distlib caches. If the directory does - not exist, it is created. Use the suffix provided for the base directory, - and default to '.distlib' if it isn't provided. - - On Windows, if LOCALAPPDATA is defined in the environment, then it is - assumed to be a directory, and will be the parent directory of the result. - On POSIX, and on Windows if LOCALAPPDATA is not defined, the user's home - directory - using os.expanduser('~') - will be the parent directory of - the result. - - The result is just the directory '.distlib' in the parent directory as - determined above, or with the name specified with ``suffix``. - """ - if suffix is None: - suffix = '.distlib' - if os.name == 'nt' and 'LOCALAPPDATA' in os.environ: - result = os.path.expandvars('$localappdata') - else: - # Assume posix, or old Windows - result = os.path.expanduser('~') - # we use 'isdir' instead of 'exists', because we want to - # fail if there's a file with that name - if os.path.isdir(result): - usable = os.access(result, os.W_OK) - if not usable: - logger.warning('Directory exists but is not writable: %s', result) - else: - try: - os.makedirs(result) - usable = True - except OSError: - logger.warning('Unable to create %s', result, exc_info=True) - usable = False - if not usable: - result = tempfile.mkdtemp() - logger.warning('Default location unusable, using %s', result) - return os.path.join(result, suffix) - - -def path_to_cache_dir(path): - """ - Convert an absolute path to a directory name for use in a cache. - - The algorithm used is: - - #. On Windows, any ``':'`` in the drive is replaced with ``'---'``. - #. Any occurrence of ``os.sep`` is replaced with ``'--'``. - #. ``'.cache'`` is appended. - """ - d, p = os.path.splitdrive(os.path.abspath(path)) - if d: - d = d.replace(':', '---') - p = p.replace(os.sep, '--') - return d + p + '.cache' - - -def ensure_slash(s): - if not s.endswith('/'): - return s + '/' - return s - - -def parse_credentials(netloc): - username = password = None - if '@' in netloc: - prefix, netloc = netloc.split('@', 1) - if ':' not in prefix: - username = prefix - else: - username, password = prefix.split(':', 1) - return username, password, netloc - - -def get_process_umask(): - result = os.umask(0o22) - os.umask(result) - return result - -def is_string_sequence(seq): - result = True - i = None - for i, s in enumerate(seq): - if not isinstance(s, string_types): - result = False - break - assert i is not None - return result - -PROJECT_NAME_AND_VERSION = re.compile('([a-z0-9_]+([.-][a-z_][a-z0-9_]*)*)-' - '([a-z0-9_.+-]+)', re.I) -PYTHON_VERSION = re.compile(r'-py(\d\.?\d?)') - - -def split_filename(filename, project_name=None): - """ - Extract name, version, python version from a filename (no extension) - - Return name, version, pyver or None - """ - result = None - pyver = None - m = PYTHON_VERSION.search(filename) - if m: - pyver = m.group(1) - filename = filename[:m.start()] - if project_name and len(filename) > len(project_name) + 1: - m = re.match(re.escape(project_name) + r'\b', filename) - if m: - n = m.end() - result = filename[:n], filename[n + 1:], pyver - if result is None: - m = PROJECT_NAME_AND_VERSION.match(filename) - if m: - result = m.group(1), m.group(3), pyver - return result - -# Allow spaces in name because of legacy dists like "Twisted Core" -NAME_VERSION_RE = re.compile(r'(?P[\w .-]+)\s*' - r'\(\s*(?P[^\s)]+)\)$') - -def parse_name_and_version(p): - """ - A utility method used to get name and version from a string. - - From e.g. a Provides-Dist value. - - :param p: A value in a form 'foo (1.0)' - :return: The name and version as a tuple. - """ - m = NAME_VERSION_RE.match(p) - if not m: - raise DistlibException('Ill-formed name/version string: \'%s\'' % p) - d = m.groupdict() - return d['name'].strip().lower(), d['ver'] - -def get_extras(requested, available): - result = set() - requested = set(requested or []) - available = set(available or []) - if '*' in requested: - requested.remove('*') - result |= available - for r in requested: - if r == '-': - result.add(r) - elif r.startswith('-'): - unwanted = r[1:] - if unwanted not in available: - logger.warning('undeclared extra: %s' % unwanted) - if unwanted in result: - result.remove(unwanted) - else: - if r not in available: - logger.warning('undeclared extra: %s' % r) - result.add(r) - return result -# -# Extended metadata functionality -# - -def _get_external_data(url): - result = {} - try: - # urlopen might fail if it runs into redirections, - # because of Python issue #13696. Fixed in locators - # using a custom redirect handler. - resp = urlopen(url) - headers = resp.info() - if headers.get('Content-Type') != 'application/json': - logger.debug('Unexpected response for JSON request') - else: - reader = codecs.getreader('utf-8')(resp) - #data = reader.read().decode('utf-8') - #result = json.loads(data) - result = json.load(reader) - except Exception as e: - logger.exception('Failed to get external data for %s: %s', url, e) - return result - - -def get_project_data(name): - url = ('https://www.red-dove.com/pypi/projects/' - '%s/%s/project.json' % (name[0].upper(), name)) - result = _get_external_data(url) - return result - -def get_package_data(name, version): - url = ('https://www.red-dove.com/pypi/projects/' - '%s/%s/package-%s.json' % (name[0].upper(), name, version)) - return _get_external_data(url) - - -class Cache(object): - """ - A class implementing a cache for resources that need to live in the file system - e.g. shared libraries. This class was moved from resources to here because it - could be used by other modules, e.g. the wheel module. - """ - - def __init__(self, base): - """ - Initialise an instance. - - :param base: The base directory where the cache should be located. - """ - # we use 'isdir' instead of 'exists', because we want to - # fail if there's a file with that name - if not os.path.isdir(base): - os.makedirs(base) - if (os.stat(base).st_mode & 0o77) != 0: - logger.warning('Directory \'%s\' is not private', base) - self.base = os.path.abspath(os.path.normpath(base)) - - def prefix_to_dir(self, prefix): - """ - Converts a resource prefix to a directory name in the cache. - """ - return path_to_cache_dir(prefix) - - def clear(self): - """ - Clear the cache. - """ - not_removed = [] - for fn in os.listdir(self.base): - fn = os.path.join(self.base, fn) - try: - if os.path.islink(fn) or os.path.isfile(fn): - os.remove(fn) - elif os.path.isdir(fn): - shutil.rmtree(fn) - except Exception: - not_removed.append(fn) - return not_removed - - -class EventMixin(object): - """ - A very simple publish/subscribe system. - """ - def __init__(self): - self._subscribers = {} - - def add(self, event, subscriber, append=True): - """ - Add a subscriber for an event. - - :param event: The name of an event. - :param subscriber: The subscriber to be added (and called when the - event is published). - :param append: Whether to append or prepend the subscriber to an - existing subscriber list for the event. - """ - subs = self._subscribers - if event not in subs: - subs[event] = deque([subscriber]) - else: - sq = subs[event] - if append: - sq.append(subscriber) - else: - sq.appendleft(subscriber) - - def remove(self, event, subscriber): - """ - Remove a subscriber for an event. - - :param event: The name of an event. - :param subscriber: The subscriber to be removed. - """ - subs = self._subscribers - if event not in subs: - raise ValueError('No subscribers: %r' % event) - subs[event].remove(subscriber) - - def get_subscribers(self, event): - """ - Return an iterator for the subscribers for an event. - :param event: The event to return subscribers for. - """ - return iter(self._subscribers.get(event, ())) - - def publish(self, event, *args, **kwargs): - """ - Publish a event and return a list of values returned by its - subscribers. - - :param event: The event to publish. - :param args: The positional arguments to pass to the event's - subscribers. - :param kwargs: The keyword arguments to pass to the event's - subscribers. - """ - result = [] - for subscriber in self.get_subscribers(event): - try: - value = subscriber(event, *args, **kwargs) - except Exception: - logger.exception('Exception during event publication') - value = None - result.append(value) - logger.debug('publish %s: args = %s, kwargs = %s, result = %s', - event, args, kwargs, result) - return result - -# -# Simple sequencing -# -class Sequencer(object): - def __init__(self): - self._preds = {} - self._succs = {} - self._nodes = set() # nodes with no preds/succs - - def add_node(self, node): - self._nodes.add(node) - - def remove_node(self, node, edges=False): - if node in self._nodes: - self._nodes.remove(node) - if edges: - for p in set(self._preds.get(node, ())): - self.remove(p, node) - for s in set(self._succs.get(node, ())): - self.remove(node, s) - # Remove empties - for k, v in list(self._preds.items()): - if not v: - del self._preds[k] - for k, v in list(self._succs.items()): - if not v: - del self._succs[k] - - def add(self, pred, succ): - assert pred != succ - self._preds.setdefault(succ, set()).add(pred) - self._succs.setdefault(pred, set()).add(succ) - - def remove(self, pred, succ): - assert pred != succ - try: - preds = self._preds[succ] - succs = self._succs[pred] - except KeyError: - raise ValueError('%r not a successor of anything' % succ) - try: - preds.remove(pred) - succs.remove(succ) - except KeyError: - raise ValueError('%r not a successor of %r' % (succ, pred)) - - def is_step(self, step): - return (step in self._preds or step in self._succs or - step in self._nodes) - - def get_steps(self, final): - if not self.is_step(final): - raise ValueError('Unknown: %r' % final) - result = [] - todo = [] - seen = set() - todo.append(final) - while todo: - step = todo.pop(0) - if step in seen: - # if a step was already seen, - # move it to the end (so it will appear earlier - # when reversed on return) ... but not for the - # final step, as that would be confusing for - # users - if step != final: - result.remove(step) - result.append(step) - else: - seen.add(step) - result.append(step) - preds = self._preds.get(step, ()) - todo.extend(preds) - return reversed(result) - - @property - def strong_connections(self): - #http://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm - index_counter = [0] - stack = [] - lowlinks = {} - index = {} - result = [] - - graph = self._succs - - def strongconnect(node): - # set the depth index for this node to the smallest unused index - index[node] = index_counter[0] - lowlinks[node] = index_counter[0] - index_counter[0] += 1 - stack.append(node) - - # Consider successors - try: - successors = graph[node] - except Exception: - successors = [] - for successor in successors: - if successor not in lowlinks: - # Successor has not yet been visited - strongconnect(successor) - lowlinks[node] = min(lowlinks[node],lowlinks[successor]) - elif successor in stack: - # the successor is in the stack and hence in the current - # strongly connected component (SCC) - lowlinks[node] = min(lowlinks[node],index[successor]) - - # If `node` is a root node, pop the stack and generate an SCC - if lowlinks[node] == index[node]: - connected_component = [] - - while True: - successor = stack.pop() - connected_component.append(successor) - if successor == node: break - component = tuple(connected_component) - # storing the result - result.append(component) - - for node in graph: - if node not in lowlinks: - strongconnect(node) - - return result - - @property - def dot(self): - result = ['digraph G {'] - for succ in self._preds: - preds = self._preds[succ] - for pred in preds: - result.append(' %s -> %s;' % (pred, succ)) - for node in self._nodes: - result.append(' %s;' % node) - result.append('}') - return '\n'.join(result) - -# -# Unarchiving functionality for zip, tar, tgz, tbz, whl -# - -ARCHIVE_EXTENSIONS = ('.tar.gz', '.tar.bz2', '.tar', '.zip', - '.tgz', '.tbz', '.whl') - -def unarchive(archive_filename, dest_dir, format=None, check=True): - - def check_path(path): - if not isinstance(path, text_type): - path = path.decode('utf-8') - p = os.path.abspath(os.path.join(dest_dir, path)) - if not p.startswith(dest_dir) or p[plen] != os.sep: - raise ValueError('path outside destination: %r' % p) - - dest_dir = os.path.abspath(dest_dir) - plen = len(dest_dir) - archive = None - if format is None: - if archive_filename.endswith(('.zip', '.whl')): - format = 'zip' - elif archive_filename.endswith(('.tar.gz', '.tgz')): - format = 'tgz' - mode = 'r:gz' - elif archive_filename.endswith(('.tar.bz2', '.tbz')): - format = 'tbz' - mode = 'r:bz2' - elif archive_filename.endswith('.tar'): - format = 'tar' - mode = 'r' - else: - raise ValueError('Unknown format for %r' % archive_filename) - try: - if format == 'zip': - archive = ZipFile(archive_filename, 'r') - if check: - names = archive.namelist() - for name in names: - check_path(name) - else: - archive = tarfile.open(archive_filename, mode) - if check: - names = archive.getnames() - for name in names: - check_path(name) - if format != 'zip' and sys.version_info[0] < 3: - # See Python issue 17153. If the dest path contains Unicode, - # tarfile extraction fails on Python 2.x if a member path name - # contains non-ASCII characters - it leads to an implicit - # bytes -> unicode conversion using ASCII to decode. - for tarinfo in archive.getmembers(): - if not isinstance(tarinfo.name, text_type): - tarinfo.name = tarinfo.name.decode('utf-8') - archive.extractall(dest_dir) - - finally: - if archive: - archive.close() - - -def zip_dir(directory): - """zip a directory tree into a BytesIO object""" - result = io.BytesIO() - dlen = len(directory) - with ZipFile(result, "w") as zf: - for root, dirs, files in os.walk(directory): - for name in files: - full = os.path.join(root, name) - rel = root[dlen:] - dest = os.path.join(rel, name) - zf.write(full, dest) - return result - -# -# Simple progress bar -# - -UNITS = ('', 'K', 'M', 'G','T','P') - - -class Progress(object): - unknown = 'UNKNOWN' - - def __init__(self, minval=0, maxval=100): - assert maxval is None or maxval >= minval - self.min = self.cur = minval - self.max = maxval - self.started = None - self.elapsed = 0 - self.done = False - - def update(self, curval): - assert self.min <= curval - assert self.max is None or curval <= self.max - self.cur = curval - now = time.time() - if self.started is None: - self.started = now - else: - self.elapsed = now - self.started - - def increment(self, incr): - assert incr >= 0 - self.update(self.cur + incr) - - def start(self): - self.update(self.min) - return self - - def stop(self): - if self.max is not None: - self.update(self.max) - self.done = True - - @property - def maximum(self): - return self.unknown if self.max is None else self.max - - @property - def percentage(self): - if self.done: - result = '100 %' - elif self.max is None: - result = ' ?? %' - else: - v = 100.0 * (self.cur - self.min) / (self.max - self.min) - result = '%3d %%' % v - return result - - def format_duration(self, duration): - if (duration <= 0) and self.max is None or self.cur == self.min: - result = '??:??:??' - #elif duration < 1: - # result = '--:--:--' - else: - result = time.strftime('%H:%M:%S', time.gmtime(duration)) - return result - - @property - def ETA(self): - if self.done: - prefix = 'Done' - t = self.elapsed - #import pdb; pdb.set_trace() - else: - prefix = 'ETA ' - if self.max is None: - t = -1 - elif self.elapsed == 0 or (self.cur == self.min): - t = 0 - else: - #import pdb; pdb.set_trace() - t = float(self.max - self.min) - t /= self.cur - self.min - t = (t - 1) * self.elapsed - return '%s: %s' % (prefix, self.format_duration(t)) - - @property - def speed(self): - if self.elapsed == 0: - result = 0.0 - else: - result = (self.cur - self.min) / self.elapsed - for unit in UNITS: - if result < 1000: - break - result /= 1000.0 - return '%d %sB/s' % (result, unit) - -# -# Glob functionality -# - -RICH_GLOB = re.compile(r'\{([^}]*)\}') -_CHECK_RECURSIVE_GLOB = re.compile(r'[^/\\,{]\*\*|\*\*[^/\\,}]') -_CHECK_MISMATCH_SET = re.compile(r'^[^{]*\}|\{[^}]*$') - - -def iglob(path_glob): - """Extended globbing function that supports ** and {opt1,opt2,opt3}.""" - if _CHECK_RECURSIVE_GLOB.search(path_glob): - msg = """invalid glob %r: recursive glob "**" must be used alone""" - raise ValueError(msg % path_glob) - if _CHECK_MISMATCH_SET.search(path_glob): - msg = """invalid glob %r: mismatching set marker '{' or '}'""" - raise ValueError(msg % path_glob) - return _iglob(path_glob) - - -def _iglob(path_glob): - rich_path_glob = RICH_GLOB.split(path_glob, 1) - if len(rich_path_glob) > 1: - assert len(rich_path_glob) == 3, rich_path_glob - prefix, set, suffix = rich_path_glob - for item in set.split(','): - for path in _iglob(''.join((prefix, item, suffix))): - yield path - else: - if '**' not in path_glob: - for item in std_iglob(path_glob): - yield item - else: - prefix, radical = path_glob.split('**', 1) - if prefix == '': - prefix = '.' - if radical == '': - radical = '*' - else: - # we support both - radical = radical.lstrip('/') - radical = radical.lstrip('\\') - for path, dir, files in os.walk(prefix): - path = os.path.normpath(path) - for fn in _iglob(os.path.join(path, radical)): - yield fn - - - -# -# HTTPSConnection which verifies certificates/matches domains -# - -class HTTPSConnection(httplib.HTTPSConnection): - ca_certs = None # set this to the path to the certs file (.pem) - check_domain = True # only used if ca_certs is not None - - # noinspection PyPropertyAccess - def connect(self): - sock = socket.create_connection((self.host, self.port), self.timeout) - if getattr(self, '_tunnel_host', False): - self.sock = sock - self._tunnel() - - if not hasattr(ssl, 'SSLContext'): - # For 2.x - if self.ca_certs: - cert_reqs = ssl.CERT_REQUIRED - else: - cert_reqs = ssl.CERT_NONE - self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, - cert_reqs=cert_reqs, - ssl_version=ssl.PROTOCOL_SSLv23, - ca_certs=self.ca_certs) - else: - context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) - context.options |= ssl.OP_NO_SSLv2 - if self.cert_file: - context.load_cert_chain(self.cert_file, self.key_file) - kwargs = {} - if self.ca_certs: - context.verify_mode = ssl.CERT_REQUIRED - context.load_verify_locations(cafile=self.ca_certs) - if getattr(ssl, 'HAS_SNI', False): - kwargs['server_hostname'] = self.host - self.sock = context.wrap_socket(sock, **kwargs) - if self.ca_certs and self.check_domain: - try: - match_hostname(self.sock.getpeercert(), self.host) - logger.debug('Host verified: %s', self.host) - except CertificateError: - self.sock.shutdown(socket.SHUT_RDWR) - self.sock.close() - raise - -class HTTPSHandler(BaseHTTPSHandler): - def __init__(self, ca_certs, check_domain=True): - BaseHTTPSHandler.__init__(self) - self.ca_certs = ca_certs - self.check_domain = check_domain - - def _conn_maker(self, *args, **kwargs): - """ - This is called to create a connection instance. Normally you'd - pass a connection class to do_open, but it doesn't actually check for - a class, and just expects a callable. As long as we behave just as a - constructor would have, we should be OK. If it ever changes so that - we *must* pass a class, we'll create an UnsafeHTTPSConnection class - which just sets check_domain to False in the class definition, and - choose which one to pass to do_open. - """ - result = HTTPSConnection(*args, **kwargs) - if self.ca_certs: - result.ca_certs = self.ca_certs - result.check_domain = self.check_domain - return result - - def https_open(self, req): - try: - return self.do_open(self._conn_maker, req) - except URLError as e: - if 'certificate verify failed' in str(e.reason): - raise CertificateError('Unable to verify server certificate ' - 'for %s' % req.host) - else: - raise - -# -# To prevent against mixing HTTP traffic with HTTPS (examples: A Man-In-The- -# Middle proxy using HTTP listens on port 443, or an index mistakenly serves -# HTML containing a http://xyz link when it should be https://xyz), -# you can use the following handler class, which does not allow HTTP traffic. -# -# It works by inheriting from HTTPHandler - so build_opener won't add a -# handler for HTTP itself. -# -class HTTPSOnlyHandler(HTTPSHandler, HTTPHandler): - def http_open(self, req): - raise URLError('Unexpected HTTP request on what should be a secure ' - 'connection: %s' % req) - -# -# XML-RPC with timeouts -# - -_ver_info = sys.version_info[:2] - -if _ver_info == (2, 6): - class HTTP(httplib.HTTP): - def __init__(self, host='', port=None, **kwargs): - if port == 0: # 0 means use port 0, not the default port - port = None - self._setup(self._connection_class(host, port, **kwargs)) - - - class HTTPS(httplib.HTTPS): - def __init__(self, host='', port=None, **kwargs): - if port == 0: # 0 means use port 0, not the default port - port = None - self._setup(self._connection_class(host, port, **kwargs)) - - -class Transport(xmlrpclib.Transport): - def __init__(self, timeout, use_datetime=0): - self.timeout = timeout - xmlrpclib.Transport.__init__(self, use_datetime) - - def make_connection(self, host): - h, eh, x509 = self.get_host_info(host) - if _ver_info == (2, 6): - result = HTTP(h, timeout=self.timeout) - else: - if not self._connection or host != self._connection[0]: - self._extra_headers = eh - self._connection = host, httplib.HTTPConnection(h) - result = self._connection[1] - return result - -class SafeTransport(xmlrpclib.SafeTransport): - def __init__(self, timeout, use_datetime=0): - self.timeout = timeout - xmlrpclib.SafeTransport.__init__(self, use_datetime) - - def make_connection(self, host): - h, eh, kwargs = self.get_host_info(host) - if not kwargs: - kwargs = {} - kwargs['timeout'] = self.timeout - if _ver_info == (2, 6): - result = HTTPS(host, None, **kwargs) - else: - if not self._connection or host != self._connection[0]: - self._extra_headers = eh - self._connection = host, httplib.HTTPSConnection(h, None, - **kwargs) - result = self._connection[1] - return result - - -class ServerProxy(xmlrpclib.ServerProxy): - def __init__(self, uri, **kwargs): - self.timeout = timeout = kwargs.pop('timeout', None) - # The above classes only come into play if a timeout - # is specified - if timeout is not None: - scheme, _ = splittype(uri) - use_datetime = kwargs.get('use_datetime', 0) - if scheme == 'https': - tcls = SafeTransport - else: - tcls = Transport - kwargs['transport'] = t = tcls(timeout, use_datetime=use_datetime) - self.transport = t - xmlrpclib.ServerProxy.__init__(self, uri, **kwargs) - -# -# CSV functionality. This is provided because on 2.x, the csv module can't -# handle Unicode. However, we need to deal with Unicode in e.g. RECORD files. -# - -def _csv_open(fn, mode, **kwargs): - if sys.version_info[0] < 3: - mode += 'b' - else: - kwargs['newline'] = '' - return open(fn, mode, **kwargs) - - -class CSVBase(object): - defaults = { - 'delimiter': str(','), # The strs are used because we need native - 'quotechar': str('"'), # str in the csv API (2.x won't take - 'lineterminator': str('\n') # Unicode) - } - - def __enter__(self): - return self - - def __exit__(self, *exc_info): - self.stream.close() - - -class CSVReader(CSVBase): - def __init__(self, **kwargs): - if 'stream' in kwargs: - stream = kwargs['stream'] - if sys.version_info[0] >= 3: - # needs to be a text stream - stream = codecs.getreader('utf-8')(stream) - self.stream = stream - else: - self.stream = _csv_open(kwargs['path'], 'r') - self.reader = csv.reader(self.stream, **self.defaults) - - def __iter__(self): - return self - - def next(self): - result = next(self.reader) - if sys.version_info[0] < 3: - for i, item in enumerate(result): - if not isinstance(item, text_type): - result[i] = item.decode('utf-8') - return result - - __next__ = next - -class CSVWriter(CSVBase): - def __init__(self, fn, **kwargs): - self.stream = _csv_open(fn, 'w') - self.writer = csv.writer(self.stream, **self.defaults) - - def writerow(self, row): - if sys.version_info[0] < 3: - r = [] - for item in row: - if isinstance(item, text_type): - item = item.encode('utf-8') - r.append(item) - row = r - self.writer.writerow(row) - -# -# Configurator functionality -# - -class Configurator(BaseConfigurator): - - value_converters = dict(BaseConfigurator.value_converters) - value_converters['inc'] = 'inc_convert' - - def __init__(self, config, base=None): - super(Configurator, self).__init__(config) - self.base = base or os.getcwd() - - def configure_custom(self, config): - def convert(o): - if isinstance(o, (list, tuple)): - result = type(o)([convert(i) for i in o]) - elif isinstance(o, dict): - if '()' in o: - result = self.configure_custom(o) - else: - result = {} - for k in o: - result[k] = convert(o[k]) - else: - result = self.convert(o) - return result - - c = config.pop('()') - if not callable(c): - c = self.resolve(c) - props = config.pop('.', None) - # Check for valid identifiers - args = config.pop('[]', ()) - if args: - args = tuple([convert(o) for o in args]) - items = [(k, convert(config[k])) for k in config if valid_ident(k)] - kwargs = dict(items) - result = c(*args, **kwargs) - if props: - for n, v in props.items(): - setattr(result, n, convert(v)) - return result - - def __getitem__(self, key): - result = self.config[key] - if isinstance(result, dict) and '()' in result: - self.config[key] = result = self.configure_custom(result) - return result - - def inc_convert(self, value): - """Default converter for the inc:// protocol.""" - if not os.path.isabs(value): - value = os.path.join(self.base, value) - with codecs.open(value, 'r', encoding='utf-8') as f: - result = json.load(f) - return result - -# -# Mixin for running subprocesses and capturing their output -# - -class SubprocessMixin(object): - def __init__(self, verbose=False, progress=None): - self.verbose = verbose - self.progress = progress - - def reader(self, stream, context): - """ - Read lines from a subprocess' output stream and either pass to a progress - callable (if specified) or write progress information to sys.stderr. - """ - progress = self.progress - verbose = self.verbose - while True: - s = stream.readline() - if not s: - break - if progress is not None: - progress(s, context) - else: - if not verbose: - sys.stderr.write('.') - else: - sys.stderr.write(s.decode('utf-8')) - sys.stderr.flush() - stream.close() - - def run_command(self, cmd, **kwargs): - p = subprocess.Popen(cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE, **kwargs) - t1 = threading.Thread(target=self.reader, args=(p.stdout, 'stdout')) - t1.start() - t2 = threading.Thread(target=self.reader, args=(p.stderr, 'stderr')) - t2.start() - p.wait() - t1.join() - t2.join() - if self.progress is not None: - self.progress('done.', 'main') - elif self.verbose: - sys.stderr.write('done.\n') - return p diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/version.py b/vendor/pip-1.5.6/pip/_vendor/distlib/version.py deleted file mode 100644 index f0e62c4..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/distlib/version.py +++ /dev/null @@ -1,721 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2012-2013 The Python Software Foundation. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -""" -Implementation of a flexible versioning scheme providing support for PEP-386, -distribute-compatible and semantic versioning. -""" - -import logging -import re - -from .compat import string_types - -__all__ = ['NormalizedVersion', 'NormalizedMatcher', - 'LegacyVersion', 'LegacyMatcher', - 'SemanticVersion', 'SemanticMatcher', - 'UnsupportedVersionError', 'get_scheme'] - -logger = logging.getLogger(__name__) - - -class UnsupportedVersionError(ValueError): - """This is an unsupported version.""" - pass - - -class Version(object): - def __init__(self, s): - self._string = s = s.strip() - self._parts = parts = self.parse(s) - assert isinstance(parts, tuple) - assert len(parts) > 0 - - def parse(self, s): - raise NotImplementedError('please implement in a subclass') - - def _check_compatible(self, other): - if type(self) != type(other): - raise TypeError('cannot compare %r and %r' % (self, other)) - - def __eq__(self, other): - self._check_compatible(other) - return self._parts == other._parts - - def __ne__(self, other): - return not self.__eq__(other) - - def __lt__(self, other): - self._check_compatible(other) - return self._parts < other._parts - - def __gt__(self, other): - return not (self.__lt__(other) or self.__eq__(other)) - - def __le__(self, other): - return self.__lt__(other) or self.__eq__(other) - - def __ge__(self, other): - return self.__gt__(other) or self.__eq__(other) - - # See http://docs.python.org/reference/datamodel#object.__hash__ - def __hash__(self): - return hash(self._parts) - - def __repr__(self): - return "%s('%s')" % (self.__class__.__name__, self._string) - - def __str__(self): - return self._string - - @property - def is_prerelease(self): - raise NotImplementedError('Please implement in subclasses.') - - -class Matcher(object): - version_class = None - - dist_re = re.compile(r"^(\w[\s\w'.-]*)(\((.*)\))?") - comp_re = re.compile(r'^(<=|>=|<|>|!=|==|~=)?\s*([^\s,]+)$') - num_re = re.compile(r'^\d+(\.\d+)*$') - - # value is either a callable or the name of a method - _operators = { - '<': lambda v, c, p: v < c, - '>': lambda v, c, p: v > c, - '<=': lambda v, c, p: v == c or v < c, - '>=': lambda v, c, p: v == c or v > c, - '==': lambda v, c, p: v == c, - # by default, compatible => >=. - '~=': lambda v, c, p: v == c or v > c, - '!=': lambda v, c, p: v != c, - } - - def __init__(self, s): - if self.version_class is None: - raise ValueError('Please specify a version class') - self._string = s = s.strip() - m = self.dist_re.match(s) - if not m: - raise ValueError('Not valid: %r' % s) - groups = m.groups('') - self.name = groups[0].strip() - self.key = self.name.lower() # for case-insensitive comparisons - clist = [] - if groups[2]: - constraints = [c.strip() for c in groups[2].split(',')] - for c in constraints: - m = self.comp_re.match(c) - if not m: - raise ValueError('Invalid %r in %r' % (c, s)) - groups = m.groups() - op = groups[0] or '~=' - s = groups[1] - if s.endswith('.*'): - if op not in ('==', '!='): - raise ValueError('\'.*\' not allowed for ' - '%r constraints' % op) - # Could be a partial version (e.g. for '2.*') which - # won't parse as a version, so keep it as a string - vn, prefix = s[:-2], True - if not self.num_re.match(vn): - # Just to check that vn is a valid version - self.version_class(vn) - else: - # Should parse as a version, so we can create an - # instance for the comparison - vn, prefix = self.version_class(s), False - clist.append((op, vn, prefix)) - self._parts = tuple(clist) - - def match(self, version): - """ - Check if the provided version matches the constraints. - - :param version: The version to match against this instance. - :type version: Strring or :class:`Version` instance. - """ - if isinstance(version, string_types): - version = self.version_class(version) - for operator, constraint, prefix in self._parts: - f = self._operators.get(operator) - if isinstance(f, string_types): - f = getattr(self, f) - if not f: - msg = ('%r not implemented ' - 'for %s' % (operator, self.__class__.__name__)) - raise NotImplementedError(msg) - if not f(version, constraint, prefix): - return False - return True - - @property - def exact_version(self): - result = None - if len(self._parts) == 1 and self._parts[0][0] == '==': - result = self._parts[0][1] - return result - - def _check_compatible(self, other): - if type(self) != type(other) or self.name != other.name: - raise TypeError('cannot compare %s and %s' % (self, other)) - - def __eq__(self, other): - self._check_compatible(other) - return self.key == other.key and self._parts == other._parts - - def __ne__(self, other): - return not self.__eq__(other) - - # See http://docs.python.org/reference/datamodel#object.__hash__ - def __hash__(self): - return hash(self.key) + hash(self._parts) - - def __repr__(self): - return "%s(%r)" % (self.__class__.__name__, self._string) - - def __str__(self): - return self._string - - -PEP426_VERSION_RE = re.compile(r'^(\d+(\.\d+)*)((a|b|c|rc)(\d+))?' - r'(\.(post)(\d+))?(\.(dev)(\d+))?' - r'(-(\d+(\.\d+)?))?$') - - -def _pep426_key(s): - s = s.strip() - m = PEP426_VERSION_RE.match(s) - if not m: - raise UnsupportedVersionError('Not a valid version: %s' % s) - groups = m.groups() - nums = tuple(int(v) for v in groups[0].split('.')) - while len(nums) > 1 and nums[-1] == 0: - nums = nums[:-1] - - pre = groups[3:5] - post = groups[6:8] - dev = groups[9:11] - local = groups[12] - if pre == (None, None): - pre = () - else: - pre = pre[0], int(pre[1]) - if post == (None, None): - post = () - else: - post = post[0], int(post[1]) - if dev == (None, None): - dev = () - else: - dev = dev[0], int(dev[1]) - if local is None: - local = () - else: - local = tuple([int(s) for s in local.split('.')]) - if not pre: - # either before pre-release, or final release and after - if not post and dev: - # before pre-release - pre = ('a', -1) # to sort before a0 - else: - pre = ('z',) # to sort after all pre-releases - # now look at the state of post and dev. - if not post: - post = ('_',) # sort before 'a' - if not dev: - dev = ('final',) - - #print('%s -> %s' % (s, m.groups())) - return nums, pre, post, dev, local - - -_normalized_key = _pep426_key - - -class NormalizedVersion(Version): - """A rational version. - - Good: - 1.2 # equivalent to "1.2.0" - 1.2.0 - 1.2a1 - 1.2.3a2 - 1.2.3b1 - 1.2.3c1 - 1.2.3.4 - TODO: fill this out - - Bad: - 1 # mininum two numbers - 1.2a # release level must have a release serial - 1.2.3b - """ - def parse(self, s): - result = _normalized_key(s) - # _normalized_key loses trailing zeroes in the release - # clause, since that's needed to ensure that X.Y == X.Y.0 == X.Y.0.0 - # However, PEP 440 prefix matching needs it: for example, - # (~= 1.4.5.0) matches differently to (~= 1.4.5.0.0). - m = PEP426_VERSION_RE.match(s) # must succeed - groups = m.groups() - self._release_clause = tuple(int(v) for v in groups[0].split('.')) - return result - - PREREL_TAGS = set(['a', 'b', 'c', 'rc', 'dev']) - - @property - def is_prerelease(self): - return any(t[0] in self.PREREL_TAGS for t in self._parts if t) - - -def _match_prefix(x, y): - x = str(x) - y = str(y) - if x == y: - return True - if not x.startswith(y): - return False - n = len(y) - return x[n] == '.' - - -class NormalizedMatcher(Matcher): - version_class = NormalizedVersion - - # value is either a callable or the name of a method - _operators = { - '~=': '_match_compatible', - '<': '_match_lt', - '>': '_match_gt', - '<=': '_match_le', - '>=': '_match_ge', - '==': '_match_eq', - '!=': '_match_ne', - } - - def _adjust_local(self, version, constraint, prefix): - if prefix: - strip_local = '-' not in constraint and version._parts[-1] - else: - # both constraint and version are - # NormalizedVersion instances. - # If constraint does not have a local component, - # ensure the version doesn't, either. - strip_local = not constraint._parts[-1] and version._parts[-1] - if strip_local: - s = version._string.split('-', 1)[0] - version = self.version_class(s) - return version, constraint - - def _match_lt(self, version, constraint, prefix): - version, constraint = self._adjust_local(version, constraint, prefix) - if version >= constraint: - return False - release_clause = constraint._release_clause - pfx = '.'.join([str(i) for i in release_clause]) - return not _match_prefix(version, pfx) - - def _match_gt(self, version, constraint, prefix): - version, constraint = self._adjust_local(version, constraint, prefix) - if version <= constraint: - return False - release_clause = constraint._release_clause - pfx = '.'.join([str(i) for i in release_clause]) - return not _match_prefix(version, pfx) - - def _match_le(self, version, constraint, prefix): - version, constraint = self._adjust_local(version, constraint, prefix) - return version <= constraint - - def _match_ge(self, version, constraint, prefix): - version, constraint = self._adjust_local(version, constraint, prefix) - return version >= constraint - - def _match_eq(self, version, constraint, prefix): - version, constraint = self._adjust_local(version, constraint, prefix) - if not prefix: - result = (version == constraint) - else: - result = _match_prefix(version, constraint) - return result - - def _match_ne(self, version, constraint, prefix): - version, constraint = self._adjust_local(version, constraint, prefix) - if not prefix: - result = (version != constraint) - else: - result = not _match_prefix(version, constraint) - return result - - def _match_compatible(self, version, constraint, prefix): - version, constraint = self._adjust_local(version, constraint, prefix) - if version == constraint: - return True - if version < constraint: - return False - release_clause = constraint._release_clause - if len(release_clause) > 1: - release_clause = release_clause[:-1] - pfx = '.'.join([str(i) for i in release_clause]) - return _match_prefix(version, pfx) - -_REPLACEMENTS = ( - (re.compile('[.+-]$'), ''), # remove trailing puncts - (re.compile(r'^[.](\d)'), r'0.\1'), # .N -> 0.N at start - (re.compile('^[.-]'), ''), # remove leading puncts - (re.compile(r'^\((.*)\)$'), r'\1'), # remove parentheses - (re.compile(r'^v(ersion)?\s*(\d+)'), r'\2'), # remove leading v(ersion) - (re.compile(r'^r(ev)?\s*(\d+)'), r'\2'), # remove leading v(ersion) - (re.compile('[.]{2,}'), '.'), # multiple runs of '.' - (re.compile(r'\b(alfa|apha)\b'), 'alpha'), # misspelt alpha - (re.compile(r'\b(pre-alpha|prealpha)\b'), - 'pre.alpha'), # standardise - (re.compile(r'\(beta\)$'), 'beta'), # remove parentheses -) - -_SUFFIX_REPLACEMENTS = ( - (re.compile('^[:~._+-]+'), ''), # remove leading puncts - (re.compile('[,*")([\]]'), ''), # remove unwanted chars - (re.compile('[~:+_ -]'), '.'), # replace illegal chars - (re.compile('[.]{2,}'), '.'), # multiple runs of '.' - (re.compile(r'\.$'), ''), # trailing '.' -) - -_NUMERIC_PREFIX = re.compile(r'(\d+(\.\d+)*)') - - -def _suggest_semantic_version(s): - """ - Try to suggest a semantic form for a version for which - _suggest_normalized_version couldn't come up with anything. - """ - result = s.strip().lower() - for pat, repl in _REPLACEMENTS: - result = pat.sub(repl, result) - if not result: - result = '0.0.0' - - # Now look for numeric prefix, and separate it out from - # the rest. - #import pdb; pdb.set_trace() - m = _NUMERIC_PREFIX.match(result) - if not m: - prefix = '0.0.0' - suffix = result - else: - prefix = m.groups()[0].split('.') - prefix = [int(i) for i in prefix] - while len(prefix) < 3: - prefix.append(0) - if len(prefix) == 3: - suffix = result[m.end():] - else: - suffix = '.'.join([str(i) for i in prefix[3:]]) + result[m.end():] - prefix = prefix[:3] - prefix = '.'.join([str(i) for i in prefix]) - suffix = suffix.strip() - if suffix: - #import pdb; pdb.set_trace() - # massage the suffix. - for pat, repl in _SUFFIX_REPLACEMENTS: - suffix = pat.sub(repl, suffix) - - if not suffix: - result = prefix - else: - sep = '-' if 'dev' in suffix else '+' - result = prefix + sep + suffix - if not is_semver(result): - result = None - return result - - -def _suggest_normalized_version(s): - """Suggest a normalized version close to the given version string. - - If you have a version string that isn't rational (i.e. NormalizedVersion - doesn't like it) then you might be able to get an equivalent (or close) - rational version from this function. - - This does a number of simple normalizations to the given string, based - on observation of versions currently in use on PyPI. Given a dump of - those version during PyCon 2009, 4287 of them: - - 2312 (53.93%) match NormalizedVersion without change - with the automatic suggestion - - 3474 (81.04%) match when using this suggestion method - - @param s {str} An irrational version string. - @returns A rational version string, or None, if couldn't determine one. - """ - try: - _normalized_key(s) - return s # already rational - except UnsupportedVersionError: - pass - - rs = s.lower() - - # part of this could use maketrans - for orig, repl in (('-alpha', 'a'), ('-beta', 'b'), ('alpha', 'a'), - ('beta', 'b'), ('rc', 'c'), ('-final', ''), - ('-pre', 'c'), - ('-release', ''), ('.release', ''), ('-stable', ''), - ('+', '.'), ('_', '.'), (' ', ''), ('.final', ''), - ('final', '')): - rs = rs.replace(orig, repl) - - # if something ends with dev or pre, we add a 0 - rs = re.sub(r"pre$", r"pre0", rs) - rs = re.sub(r"dev$", r"dev0", rs) - - # if we have something like "b-2" or "a.2" at the end of the - # version, that is pobably beta, alpha, etc - # let's remove the dash or dot - rs = re.sub(r"([abc]|rc)[\-\.](\d+)$", r"\1\2", rs) - - # 1.0-dev-r371 -> 1.0.dev371 - # 0.1-dev-r79 -> 0.1.dev79 - rs = re.sub(r"[\-\.](dev)[\-\.]?r?(\d+)$", r".\1\2", rs) - - # Clean: 2.0.a.3, 2.0.b1, 0.9.0~c1 - rs = re.sub(r"[.~]?([abc])\.?", r"\1", rs) - - # Clean: v0.3, v1.0 - if rs.startswith('v'): - rs = rs[1:] - - # Clean leading '0's on numbers. - #TODO: unintended side-effect on, e.g., "2003.05.09" - # PyPI stats: 77 (~2%) better - rs = re.sub(r"\b0+(\d+)(?!\d)", r"\1", rs) - - # Clean a/b/c with no version. E.g. "1.0a" -> "1.0a0". Setuptools infers - # zero. - # PyPI stats: 245 (7.56%) better - rs = re.sub(r"(\d+[abc])$", r"\g<1>0", rs) - - # the 'dev-rNNN' tag is a dev tag - rs = re.sub(r"\.?(dev-r|dev\.r)\.?(\d+)$", r".dev\2", rs) - - # clean the - when used as a pre delimiter - rs = re.sub(r"-(a|b|c)(\d+)$", r"\1\2", rs) - - # a terminal "dev" or "devel" can be changed into ".dev0" - rs = re.sub(r"[\.\-](dev|devel)$", r".dev0", rs) - - # a terminal "dev" can be changed into ".dev0" - rs = re.sub(r"(?![\.\-])dev$", r".dev0", rs) - - # a terminal "final" or "stable" can be removed - rs = re.sub(r"(final|stable)$", "", rs) - - # The 'r' and the '-' tags are post release tags - # 0.4a1.r10 -> 0.4a1.post10 - # 0.9.33-17222 -> 0.9.33.post17222 - # 0.9.33-r17222 -> 0.9.33.post17222 - rs = re.sub(r"\.?(r|-|-r)\.?(\d+)$", r".post\2", rs) - - # Clean 'r' instead of 'dev' usage: - # 0.9.33+r17222 -> 0.9.33.dev17222 - # 1.0dev123 -> 1.0.dev123 - # 1.0.git123 -> 1.0.dev123 - # 1.0.bzr123 -> 1.0.dev123 - # 0.1a0dev.123 -> 0.1a0.dev123 - # PyPI stats: ~150 (~4%) better - rs = re.sub(r"\.?(dev|git|bzr)\.?(\d+)$", r".dev\2", rs) - - # Clean '.pre' (normalized from '-pre' above) instead of 'c' usage: - # 0.2.pre1 -> 0.2c1 - # 0.2-c1 -> 0.2c1 - # 1.0preview123 -> 1.0c123 - # PyPI stats: ~21 (0.62%) better - rs = re.sub(r"\.?(pre|preview|-c)(\d+)$", r"c\g<2>", rs) - - # Tcl/Tk uses "px" for their post release markers - rs = re.sub(r"p(\d+)$", r".post\1", rs) - - try: - _normalized_key(rs) - except UnsupportedVersionError: - rs = None - return rs - -# -# Legacy version processing (distribute-compatible) -# - -_VERSION_PART = re.compile(r'([a-z]+|\d+|[\.-])', re.I) -_VERSION_REPLACE = { - 'pre': 'c', - 'preview': 'c', - '-': 'final-', - 'rc': 'c', - 'dev': '@', - '': None, - '.': None, -} - - -def _legacy_key(s): - def get_parts(s): - result = [] - for p in _VERSION_PART.split(s.lower()): - p = _VERSION_REPLACE.get(p, p) - if p: - if '0' <= p[:1] <= '9': - p = p.zfill(8) - else: - p = '*' + p - result.append(p) - result.append('*final') - return result - - result = [] - for p in get_parts(s): - if p.startswith('*'): - if p < '*final': - while result and result[-1] == '*final-': - result.pop() - while result and result[-1] == '00000000': - result.pop() - result.append(p) - return tuple(result) - - -class LegacyVersion(Version): - def parse(self, s): - return _legacy_key(s) - - @property - def is_prerelease(self): - result = False - for x in self._parts: - if (isinstance(x, string_types) and x.startswith('*') and - x < '*final'): - result = True - break - return result - - -class LegacyMatcher(Matcher): - version_class = LegacyVersion - - _operators = dict(Matcher._operators) - _operators['~='] = '_match_compatible' - - numeric_re = re.compile('^(\d+(\.\d+)*)') - - def _match_compatible(self, version, constraint, prefix): - if version < constraint: - return False - m = self.numeric_re.match(str(constraint)) - if not m: - logger.warning('Cannot compute compatible match for version %s ' - ' and constraint %s', version, constraint) - return True - s = m.groups()[0] - if '.' in s: - s = s.rsplit('.', 1)[0] - return _match_prefix(version, s) - -# -# Semantic versioning -# - -_SEMVER_RE = re.compile(r'^(\d+)\.(\d+)\.(\d+)' - r'(-[a-z0-9]+(\.[a-z0-9-]+)*)?' - r'(\+[a-z0-9]+(\.[a-z0-9-]+)*)?$', re.I) - - -def is_semver(s): - return _SEMVER_RE.match(s) - - -def _semantic_key(s): - def make_tuple(s, absent): - if s is None: - result = (absent,) - else: - parts = s[1:].split('.') - # We can't compare ints and strings on Python 3, so fudge it - # by zero-filling numeric values so simulate a numeric comparison - result = tuple([p.zfill(8) if p.isdigit() else p for p in parts]) - return result - - m = is_semver(s) - if not m: - raise UnsupportedVersionError(s) - groups = m.groups() - major, minor, patch = [int(i) for i in groups[:3]] - # choose the '|' and '*' so that versions sort correctly - pre, build = make_tuple(groups[3], '|'), make_tuple(groups[5], '*') - return (major, minor, patch), pre, build - - -class SemanticVersion(Version): - def parse(self, s): - return _semantic_key(s) - - @property - def is_prerelease(self): - return self._parts[1][0] != '|' - - -class SemanticMatcher(Matcher): - version_class = SemanticVersion - - -class VersionScheme(object): - def __init__(self, key, matcher, suggester=None): - self.key = key - self.matcher = matcher - self.suggester = suggester - - def is_valid_version(self, s): - try: - self.matcher.version_class(s) - result = True - except UnsupportedVersionError: - result = False - return result - - def is_valid_matcher(self, s): - try: - self.matcher(s) - result = True - except UnsupportedVersionError: - result = False - return result - - def is_valid_constraint_list(self, s): - """ - Used for processing some metadata fields - """ - return self.is_valid_matcher('dummy_name (%s)' % s) - - def suggest(self, s): - if self.suggester is None: - result = None - else: - result = self.suggester(s) - return result - -_SCHEMES = { - 'normalized': VersionScheme(_normalized_key, NormalizedMatcher, - _suggest_normalized_version), - 'legacy': VersionScheme(_legacy_key, LegacyMatcher, lambda self, s: s), - 'semantic': VersionScheme(_semantic_key, SemanticMatcher, - _suggest_semantic_version), -} - -_SCHEMES['default'] = _SCHEMES['normalized'] - - -def get_scheme(name): - if name not in _SCHEMES: - raise ValueError('unknown scheme name: %r' % name) - return _SCHEMES[name] diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/w32.exe b/vendor/pip-1.5.6/pip/_vendor/distlib/w32.exe deleted file mode 100644 index 09e76354f7b45b4a90272ed578ff14bbbf5ab540..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 87040 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 diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/w64.exe b/vendor/pip-1.5.6/pip/_vendor/distlib/w64.exe deleted file mode 100644 index 29e44e1f8a4215238d7af0f5ee8a9a6dabaaf18d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 91648 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

S7V%iUn;9oxpVta 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 diff --git a/vendor/pip-1.5.6/pip/_vendor/distlib/wheel.py b/vendor/pip-1.5.6/pip/_vendor/distlib/wheel.py deleted file mode 100644 index d67d4bc..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/distlib/wheel.py +++ /dev/null @@ -1,958 +0,0 @@ -# -*- coding: utf-8 -*- -# -# Copyright (C) 2013-2014 Vinay Sajip. -# Licensed to the Python Software Foundation under a contributor agreement. -# See LICENSE.txt and CONTRIBUTORS.txt. -# -from __future__ import unicode_literals - -import base64 -import codecs -import datetime -import distutils.util -from email import message_from_file -import hashlib -import imp -import json -import logging -import os -import posixpath -import re -import shutil -import sys -import tempfile -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 -from .util import (FileOperator, convert_path, CSVReader, CSVWriter, Cache, - cached_property, get_cache_base, read_exports, tempdir) -from .version import NormalizedVersion, UnsupportedVersionError - -logger = logging.getLogger(__name__) - -cache = None # created when needed - -if hasattr(sys, 'pypy_version_info'): - IMP_PREFIX = 'pp' -elif sys.platform.startswith('java'): - IMP_PREFIX = 'jy' -elif sys.platform == 'cli': - IMP_PREFIX = 'ip' -else: - IMP_PREFIX = 'cp' - -VER_SUFFIX = sysconfig.get_config_var('py_version_nodot') -if not VER_SUFFIX: # pragma: no cover - VER_SUFFIX = '%s%s' % sys.version_info[:2] -PYVER = 'py' + VER_SUFFIX -IMPVER = IMP_PREFIX + VER_SUFFIX - -ARCH = distutils.util.get_platform().replace('-', '_').replace('.', '_') - -ABI = sysconfig.get_config_var('SOABI') -if ABI and ABI.startswith('cpython-'): - ABI = ABI.replace('cpython-', 'cp') -else: - def _derive_abi(): - parts = ['cp', VER_SUFFIX] - if sysconfig.get_config_var('Py_DEBUG'): - parts.append('d') - if sysconfig.get_config_var('WITH_PYMALLOC'): - parts.append('m') - if sysconfig.get_config_var('Py_UNICODE_SIZE') == 4: - parts.append('u') - return ''.join(parts) - ABI = _derive_abi() - del _derive_abi - -FILENAME_RE = re.compile(r''' -(?P[^-]+) --(?P\d+[^-]*) -(-(?P\d+[^-]*))? --(?P\w+\d+(\.\w+\d+)*) --(?P\w+) --(?P\w+) -\.whl$ -''', re.IGNORECASE | re.VERBOSE) - -NAME_VERSION_RE = re.compile(r''' -(?P[^-]+) --(?P\d+[^-]*) -(-(?P\d+[^-]*))?$ -''', re.IGNORECASE | re.VERBOSE) - -SHEBANG_RE = re.compile(br'\s*#![^\r\n]*') - -if os.sep == '/': - to_posix = lambda o: o -else: - to_posix = lambda o: o.replace(os.sep, '/') - - -class Mounter(object): - def __init__(self): - self.impure_wheels = {} - self.libs = {} - - def add(self, pathname, extensions): - self.impure_wheels[pathname] = extensions - self.libs.update(extensions) - - def remove(self, pathname): - extensions = self.impure_wheels.pop(pathname) - for k, v in extensions: - if k in self.libs: - del self.libs[k] - - def find_module(self, fullname, path=None): - if fullname in self.libs: - result = self - else: - result = None - return result - - def load_module(self, fullname): - if fullname in sys.modules: - result = sys.modules[fullname] - else: - if fullname not in self.libs: - raise ImportError('unable to find extension for %s' % fullname) - result = imp.load_dynamic(fullname, self.libs[fullname]) - result.__loader__ = self - parts = fullname.rsplit('.', 1) - if len(parts) > 1: - result.__package__ = parts[0] - return result - -_hook = Mounter() - - -class Wheel(object): - """ - Class to build and install from Wheel files (PEP 427). - """ - - wheel_version = (1, 1) - hash_kind = 'sha256' - - def __init__(self, filename=None, sign=False, verify=False): - """ - Initialise an instance using a (valid) filename. - """ - self.sign = sign - self.should_verify = verify - self.buildver = '' - self.pyver = [PYVER] - self.abi = ['none'] - self.arch = ['any'] - self.dirname = os.getcwd() - if filename is None: - self.name = 'dummy' - self.version = '0.1' - self._filename = self.filename - else: - m = NAME_VERSION_RE.match(filename) - if m: - info = m.groupdict('') - self.name = info['nm'] - # Reinstate the local version separator - self.version = info['vn'].replace('_', '-') - self.buildver = info['bn'] - self._filename = self.filename - else: - dirname, filename = os.path.split(filename) - m = FILENAME_RE.match(filename) - if not m: - raise DistlibException('Invalid name or ' - 'filename: %r' % filename) - if dirname: - self.dirname = os.path.abspath(dirname) - self._filename = filename - info = m.groupdict('') - self.name = info['nm'] - self.version = info['vn'] - self.buildver = info['bn'] - self.pyver = info['py'].split('.') - self.abi = info['bi'].split('.') - self.arch = info['ar'].split('.') - - @property - def filename(self): - """ - Build and return a filename from the various components. - """ - if self.buildver: - buildver = '-' + self.buildver - else: - buildver = '' - pyver = '.'.join(self.pyver) - abi = '.'.join(self.abi) - arch = '.'.join(self.arch) - # replace - with _ as a local version separator - version = self.version.replace('-', '_') - return '%s-%s%s-%s-%s-%s.whl' % (self.name, version, buildver, - pyver, abi, arch) - - @property - def exists(self): - path = os.path.join(self.dirname, self.filename) - return os.path.isfile(path) - - @property - def tags(self): - for pyver in self.pyver: - for abi in self.abi: - for arch in self.arch: - yield pyver, abi, arch - - @cached_property - def metadata(self): - pathname = os.path.join(self.dirname, self.filename) - name_ver = '%s-%s' % (self.name, self.version) - info_dir = '%s.dist-info' % name_ver - wrapper = codecs.getreader('utf-8') - with ZipFile(pathname, 'r') as zf: - 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): - fn = 'METADATA' - else: - fn = METADATA_FILENAME - try: - metadata_filename = posixpath.join(info_dir, fn) - with zf.open(metadata_filename) as bf: - wf = wrapper(bf) - result = Metadata(fileobj=wf) - except KeyError: - raise ValueError('Invalid wheel, because %s is ' - 'missing' % fn) - return result - - def get_wheel_metadata(self, zf): - name_ver = '%s-%s' % (self.name, self.version) - info_dir = '%s.dist-info' % name_ver - metadata_filename = posixpath.join(info_dir, 'WHEEL') - with zf.open(metadata_filename) as bf: - wf = codecs.getreader('utf-8')(bf) - message = message_from_file(wf) - return dict(message) - - @cached_property - def info(self): - pathname = os.path.join(self.dirname, self.filename) - with ZipFile(pathname, 'r') as zf: - result = self.get_wheel_metadata(zf) - return result - - def process_shebang(self, data): - m = SHEBANG_RE.match(data) - if m: - data = b'#!python' + data[m.end():] - else: - cr = data.find(b'\r') - lf = data.find(b'\n') - if cr < 0 or cr > lf: - term = b'\n' - else: - if data[cr:cr + 2] == b'\r\n': - term = b'\r\n' - else: - term = b'\r' - data = b'#!python' + term + data - return data - - def get_hash(self, data, hash_kind=None): - if hash_kind is None: - hash_kind = self.hash_kind - try: - hasher = getattr(hashlib, hash_kind) - except AttributeError: - raise DistlibException('Unsupported hash algorithm: %r' % hash_kind) - result = hasher(data).digest() - result = base64.urlsafe_b64encode(result).rstrip(b'=').decode('ascii') - return hash_kind, result - - def write_record(self, records, record_path, base): - with CSVWriter(record_path) as writer: - for row in records: - writer.writerow(row) - p = to_posix(os.path.relpath(record_path, base)) - writer.writerow((p, '', '')) - - def write_records(self, info, libdir, archive_paths): - records = [] - distinfo, info_dir = info - hasher = getattr(hashlib, self.hash_kind) - for ap, p in archive_paths: - with open(p, 'rb') as f: - data = f.read() - digest = '%s=%s' % self.get_hash(data) - size = os.path.getsize(p) - records.append((ap, digest, size)) - - p = os.path.join(distinfo, 'RECORD') - self.write_record(records, p, libdir) - ap = to_posix(os.path.join(info_dir, 'RECORD')) - archive_paths.append((ap, p)) - - def build_zip(self, pathname, archive_paths): - with ZipFile(pathname, 'w', zipfile.ZIP_DEFLATED) as zf: - for ap, p in archive_paths: - logger.debug('Wrote %s to %s in wheel', p, ap) - zf.write(p, ap) - - def build(self, paths, tags=None, wheel_version=None): - """ - Build a wheel from files in specified paths, and use any specified tags - when determining the name of the wheel. - """ - if tags is None: - tags = {} - - libkey = list(filter(lambda o: o in paths, ('purelib', 'platlib')))[0] - if libkey == 'platlib': - is_pure = 'false' - default_pyver = [IMPVER] - default_abi = [ABI] - default_arch = [ARCH] - else: - is_pure = 'true' - default_pyver = [PYVER] - default_abi = ['none'] - default_arch = ['any'] - - self.pyver = tags.get('pyver', default_pyver) - self.abi = tags.get('abi', default_abi) - self.arch = tags.get('arch', default_arch) - - libdir = paths[libkey] - - name_ver = '%s-%s' % (self.name, self.version) - data_dir = '%s.data' % name_ver - info_dir = '%s.dist-info' % name_ver - - archive_paths = [] - - # First, stuff which is not in site-packages - for key in ('data', 'headers', 'scripts'): - if key not in paths: - continue - path = paths[key] - if os.path.isdir(path): - for root, dirs, files in os.walk(path): - for fn in files: - p = fsdecode(os.path.join(root, fn)) - rp = os.path.relpath(p, path) - ap = to_posix(os.path.join(data_dir, key, rp)) - archive_paths.append((ap, p)) - if key == 'scripts' and not p.endswith('.exe'): - with open(p, 'rb') as f: - data = f.read() - data = self.process_shebang(data) - with open(p, 'wb') as f: - f.write(data) - - # Now, stuff which is in site-packages, other than the - # distinfo stuff. - path = libdir - distinfo = None - for root, dirs, files in os.walk(path): - if root == path: - # At the top level only, save distinfo for later - # and skip it for now - for i, dn in enumerate(dirs): - dn = fsdecode(dn) - if dn.endswith('.dist-info'): - distinfo = os.path.join(root, dn) - del dirs[i] - break - assert distinfo, '.dist-info directory expected, not found' - - for fn in files: - # comment out next suite to leave .pyc files in - if fsdecode(fn).endswith(('.pyc', '.pyo')): - continue - p = os.path.join(root, fn) - rp = to_posix(os.path.relpath(p, path)) - archive_paths.append((rp, p)) - - # Now distinfo. Assumed to be flat, i.e. os.listdir is enough. - files = os.listdir(distinfo) - for fn in files: - if fn not in ('RECORD', 'INSTALLER', 'SHARED'): - p = fsdecode(os.path.join(distinfo, fn)) - ap = to_posix(os.path.join(info_dir, fn)) - archive_paths.append((ap, p)) - - wheel_metadata = [ - 'Wheel-Version: %d.%d' % (wheel_version or self.wheel_version), - 'Generator: distlib %s' % __version__, - 'Root-Is-Purelib: %s' % is_pure, - ] - for pyver, abi, arch in self.tags: - wheel_metadata.append('Tag: %s-%s-%s' % (pyver, abi, arch)) - p = os.path.join(distinfo, 'WHEEL') - with open(p, 'w') as f: - f.write('\n'.join(wheel_metadata)) - ap = to_posix(os.path.join(info_dir, 'WHEEL')) - archive_paths.append((ap, p)) - - # Now, at last, RECORD. - # Paths in here are archive paths - nothing else makes sense. - self.write_records((distinfo, info_dir), libdir, archive_paths) - # Now, ready to build the zip file - pathname = os.path.join(self.dirname, self.filename) - self.build_zip(pathname, archive_paths) - return pathname - - def install(self, paths, maker, **kwargs): - """ - Install a wheel to the specified paths. If kwarg ``warner`` is - specified, it should be a callable, which will be called with two - tuples indicating the wheel version of this software and the wheel - version in the file, if there is a discrepancy in the versions. - This can be used to issue any warnings to raise any exceptions. - If kwarg ``lib_only`` is True, only the purelib/platlib files are - installed, and the headers, scripts, data and dist-info metadata are - not written. - - The return value is a :class:`InstalledDistribution` instance unless - ``options.lib_only`` is True, in which case the return value is ``None``. - """ - - dry_run = maker.dry_run - warner = kwargs.get('warner') - lib_only = kwargs.get('lib_only', False) - - pathname = os.path.join(self.dirname, self.filename) - name_ver = '%s-%s' % (self.name, self.version) - data_dir = '%s.data' % name_ver - info_dir = '%s.dist-info' % name_ver - - metadata_name = posixpath.join(info_dir, METADATA_FILENAME) - wheel_metadata_name = posixpath.join(info_dir, 'WHEEL') - record_name = posixpath.join(info_dir, 'RECORD') - - wrapper = codecs.getreader('utf-8') - - with ZipFile(pathname, 'r') as zf: - with zf.open(wheel_metadata_name) as bwf: - wf = wrapper(bwf) - message = message_from_file(wf) - wv = message['Wheel-Version'].split('.', 1) - file_version = tuple([int(i) for i in wv]) - if (file_version != self.wheel_version) and warner: - warner(self.wheel_version, file_version) - - if message['Root-Is-Purelib'] == 'true': - libdir = paths['purelib'] - else: - libdir = paths['platlib'] - - records = {} - with zf.open(record_name) as bf: - with CSVReader(stream=bf) as reader: - for row in reader: - p = row[0] - records[p] = row - - data_pfx = posixpath.join(data_dir, '') - info_pfx = posixpath.join(info_dir, '') - script_pfx = posixpath.join(data_dir, 'scripts', '') - - # make a new instance rather than a copy of maker's, - # as we mutate it - fileop = FileOperator(dry_run=dry_run) - fileop.record = True # so we can rollback if needed - - bc = not sys.dont_write_bytecode # Double negatives. Lovely! - - outfiles = [] # for RECORD writing - - # for script copying/shebang processing - workdir = tempfile.mkdtemp() - # set target dir later - # we default add_launchers to False, as the - # Python Launcher should be used instead - maker.source_dir = workdir - maker.target_dir = None - try: - for zinfo in zf.infolist(): - arcname = zinfo.filename - if isinstance(arcname, text_type): - u_arcname = arcname - else: - u_arcname = arcname.decode('utf-8') - # The signature file won't be in RECORD, - # and we don't currently don't do anything with it - if u_arcname.endswith('/RECORD.jws'): - continue - row = records[u_arcname] - if row[2] and str(zinfo.file_size) != row[2]: - raise DistlibException('size mismatch for ' - '%s' % u_arcname) - if row[1]: - kind, value = row[1].split('=', 1) - with zf.open(arcname) as bf: - data = bf.read() - _, digest = self.get_hash(data, kind) - if digest != value: - raise DistlibException('digest mismatch for ' - '%s' % arcname) - - if lib_only and u_arcname.startswith((info_pfx, data_pfx)): - logger.debug('lib_only: skipping %s', u_arcname) - continue - is_script = (u_arcname.startswith(script_pfx) - and not u_arcname.endswith('.exe')) - - if u_arcname.startswith(data_pfx): - _, where, rp = u_arcname.split('/', 2) - outfile = os.path.join(paths[where], convert_path(rp)) - else: - # meant for site-packages. - if u_arcname in (wheel_metadata_name, record_name): - continue - outfile = os.path.join(libdir, convert_path(u_arcname)) - if not is_script: - with zf.open(arcname) as bf: - fileop.copy_stream(bf, outfile) - outfiles.append(outfile) - # Double check the digest of the written file - if not dry_run and row[1]: - with open(outfile, 'rb') as bf: - data = bf.read() - _, newdigest = self.get_hash(data, kind) - if newdigest != digest: - raise DistlibException('digest mismatch ' - 'on write for ' - '%s' % outfile) - if bc and outfile.endswith('.py'): - try: - pyc = fileop.byte_compile(outfile) - outfiles.append(pyc) - except Exception: - # Don't give up if byte-compilation fails, - # but log it and perhaps warn the user - logger.warning('Byte-compilation failed', - exc_info=True) - else: - fn = os.path.basename(convert_path(arcname)) - workname = os.path.join(workdir, fn) - with zf.open(arcname) as bf: - fileop.copy_stream(bf, workname) - - dn, fn = os.path.split(outfile) - maker.target_dir = dn - filenames = maker.make(fn) - fileop.set_executable_mode(filenames) - outfiles.extend(filenames) - - if lib_only: - logger.debug('lib_only: returning None') - dist = None - else: - # Generate scripts - - # Try to get pydist.json so we can see if there are - # any commands to generate. If this fails (e.g. because - # of a legacy wheel), log a warning but don't give up. - commands = None - file_version = self.info['Wheel-Version'] - if file_version == '1.0': - # Use legacy info - ep = posixpath.join(info_dir, 'entry_points.txt') - try: - with zf.open(ep) as bwf: - epdata = read_exports(bwf) - commands = {} - for key in ('console', 'gui'): - k = '%s_scripts' % key - if k in epdata: - commands['wrap_%s' % key] = d = {} - for v in epdata[k].values(): - s = '%s:%s' % (v.prefix, v.suffix) - if v.flags: - s += ' %s' % v.flags - d[v.name] = s - except Exception: - logger.warning('Unable to read legacy script ' - 'metadata, so cannot generate ' - 'scripts') - else: - try: - with zf.open(metadata_name) as bwf: - wf = wrapper(bwf) - commands = json.load(wf).get('commands') - except Exception: - logger.warning('Unable to read JSON metadata, so ' - 'cannot generate scripts') - if commands: - console_scripts = commands.get('wrap_console', {}) - gui_scripts = commands.get('wrap_gui', {}) - if console_scripts or gui_scripts: - script_dir = paths.get('scripts', '') - if not os.path.isdir(script_dir): - raise ValueError('Valid script path not ' - 'specified') - maker.target_dir = script_dir - for k, v in console_scripts.items(): - script = '%s = %s' % (k, v) - filenames = maker.make(script) - fileop.set_executable_mode(filenames) - - if gui_scripts: - options = {'gui': True } - for k, v in gui_scripts.items(): - script = '%s = %s' % (k, v) - filenames = maker.make(script, options) - fileop.set_executable_mode(filenames) - - p = os.path.join(libdir, info_dir) - dist = InstalledDistribution(p) - - # Write SHARED - paths = dict(paths) # don't change passed in dict - del paths['purelib'] - del paths['platlib'] - paths['lib'] = libdir - p = dist.write_shared_locations(paths, dry_run) - if p: - outfiles.append(p) - - # Write RECORD - dist.write_installed_files(outfiles, paths['prefix'], - dry_run) - return dist - except Exception: # pragma: no cover - logger.exception('installation failed.') - fileop.rollback() - raise - finally: - shutil.rmtree(workdir) - - def _get_dylib_cache(self): - global cache - 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]) - cache = Cache(base) - return cache - - def _get_extensions(self): - pathname = os.path.join(self.dirname, self.filename) - name_ver = '%s-%s' % (self.name, self.version) - info_dir = '%s.dist-info' % name_ver - arcname = posixpath.join(info_dir, 'EXTENSIONS') - wrapper = codecs.getreader('utf-8') - result = [] - with ZipFile(pathname, 'r') as zf: - try: - with zf.open(arcname) as bf: - wf = wrapper(bf) - extensions = json.load(wf) - cache = self._get_dylib_cache() - prefix = cache.prefix_to_dir(pathname) - cache_base = os.path.join(cache.base, prefix) - if not os.path.isdir(cache_base): - os.makedirs(cache_base) - for name, relpath in extensions.items(): - dest = os.path.join(cache_base, convert_path(relpath)) - if not os.path.exists(dest): - extract = True - else: - file_time = os.stat(dest).st_mtime - file_time = datetime.datetime.fromtimestamp(file_time) - info = zf.getinfo(relpath) - wheel_time = datetime.datetime(*info.date_time) - extract = wheel_time > file_time - if extract: - zf.extract(relpath, cache_base) - result.append((name, dest)) - except KeyError: - pass - return result - - def is_compatible(self): - """ - Determine if a wheel is compatible with the running system. - """ - return is_compatible(self) - - def is_mountable(self): - """ - Determine if a wheel is asserted as mountable by its metadata. - """ - return True # for now - metadata details TBD - - def mount(self, append=False): - pathname = os.path.abspath(os.path.join(self.dirname, self.filename)) - if not self.is_compatible(): - msg = 'Wheel %s not compatible with this Python.' % pathname - raise DistlibException(msg) - if not self.is_mountable(): - msg = 'Wheel %s is marked as not mountable.' % pathname - raise DistlibException(msg) - if pathname in sys.path: - logger.debug('%s already in path', pathname) - else: - if append: - sys.path.append(pathname) - else: - sys.path.insert(0, pathname) - extensions = self._get_extensions() - if extensions: - if _hook not in sys.meta_path: - sys.meta_path.append(_hook) - _hook.add(pathname, extensions) - - def unmount(self): - pathname = os.path.abspath(os.path.join(self.dirname, self.filename)) - if pathname not in sys.path: - logger.debug('%s not in path', pathname) - else: - sys.path.remove(pathname) - if pathname in _hook.impure_wheels: - _hook.remove(pathname) - if not _hook.impure_wheels: - if _hook in sys.meta_path: - sys.meta_path.remove(_hook) - - def verify(self): - pathname = os.path.join(self.dirname, self.filename) - name_ver = '%s-%s' % (self.name, self.version) - data_dir = '%s.data' % name_ver - info_dir = '%s.dist-info' % name_ver - - metadata_name = posixpath.join(info_dir, METADATA_FILENAME) - wheel_metadata_name = posixpath.join(info_dir, 'WHEEL') - record_name = posixpath.join(info_dir, 'RECORD') - - wrapper = codecs.getreader('utf-8') - - with ZipFile(pathname, 'r') as zf: - with zf.open(wheel_metadata_name) as bwf: - wf = wrapper(bwf) - message = message_from_file(wf) - wv = message['Wheel-Version'].split('.', 1) - file_version = tuple([int(i) for i in wv]) - # TODO version verification - - records = {} - with zf.open(record_name) as bf: - with CSVReader(stream=bf) as reader: - for row in reader: - p = row[0] - records[p] = row - - for zinfo in zf.infolist(): - arcname = zinfo.filename - if isinstance(arcname, text_type): - u_arcname = arcname - else: - u_arcname = arcname.decode('utf-8') - if '..' in u_arcname: - raise DistlibException('invalid entry in ' - 'wheel: %r' % u_arcname) - - # The signature file won't be in RECORD, - # and we don't currently don't do anything with it - if u_arcname.endswith('/RECORD.jws'): - continue - row = records[u_arcname] - if row[2] and str(zinfo.file_size) != row[2]: - raise DistlibException('size mismatch for ' - '%s' % u_arcname) - if row[1]: - kind, value = row[1].split('=', 1) - with zf.open(arcname) as bf: - data = bf.read() - _, digest = self.get_hash(data, kind) - if digest != value: - raise DistlibException('digest mismatch for ' - '%s' % arcname) - - def update(self, modifier, dest_dir=None, **kwargs): - """ - Update the contents of a wheel in a generic way. The modifier should - be a callable which expects a dictionary argument: its keys are - archive-entry paths, and its values are absolute filesystem paths - where the contents the corresponding archive entries can be found. The - modifier is free to change the contents of the files pointed to, add - new entries and remove entries, before returning. This method will - extract the entire contents of the wheel to a temporary location, call - the modifier, and then use the passed (and possibly updated) - dictionary to write a new wheel. If ``dest_dir`` is specified, the new - wheel is written there -- otherwise, the original wheel is overwritten. - - The modifier should return True if it updated the wheel, else False. - This method returns the same value the modifier returns. - """ - - def get_version(path_map, info_dir): - version = path = None - key = '%s/%s' % (info_dir, METADATA_FILENAME) - if key not in path_map: - key = '%s/PKG-INFO' % info_dir - if key in path_map: - path = path_map[key] - version = Metadata(path=path).version - return version, path - - def update_version(version, path): - updated = None - try: - v = NormalizedVersion(version) - i = version.find('-') - if i < 0: - updated = '%s-1' % version - else: - parts = [int(s) for s in version[i + 1:].split('.')] - parts[-1] += 1 - updated = '%s-%s' % (version[:i], - '.'.join(str(i) for i in parts)) - except UnsupportedVersionError: - logger.debug('Cannot update non-compliant (PEP-440) ' - 'version %r', version) - if updated: - md = Metadata(path=path) - md.version = updated - legacy = not path.endswith(METADATA_FILENAME) - md.write(path=path, legacy=legacy) - logger.debug('Version updated from %r to %r', version, - updated) - - pathname = os.path.join(self.dirname, self.filename) - name_ver = '%s-%s' % (self.name, self.version) - info_dir = '%s.dist-info' % name_ver - record_name = posixpath.join(info_dir, 'RECORD') - with tempdir() as workdir: - with ZipFile(pathname, 'r') as zf: - path_map = {} - for zinfo in zf.infolist(): - arcname = zinfo.filename - if isinstance(arcname, text_type): - u_arcname = arcname - else: - u_arcname = arcname.decode('utf-8') - if u_arcname == record_name: - continue - if '..' in u_arcname: - raise DistlibException('invalid entry in ' - 'wheel: %r' % u_arcname) - zf.extract(zinfo, workdir) - path = os.path.join(workdir, convert_path(u_arcname)) - path_map[u_arcname] = path - - # Remember the version. - original_version, _ = get_version(path_map, info_dir) - # Files extracted. Call the modifier. - modified = modifier(path_map, **kwargs) - if modified: - # Something changed - need to build a new wheel. - current_version, path = get_version(path_map, info_dir) - if current_version and (current_version == original_version): - # Add or update local version to signify changes. - update_version(current_version, path) - # Decide where the new wheel goes. - if dest_dir is None: - fd, newpath = tempfile.mkstemp(suffix='.whl', - prefix='wheel-update-', - dir=workdir) - os.close(fd) - else: - if not os.path.isdir(dest_dir): - raise DistlibException('Not a directory: %r' % dest_dir) - newpath = os.path.join(dest_dir, self.filename) - archive_paths = list(path_map.items()) - distinfo = os.path.join(workdir, info_dir) - info = distinfo, info_dir - self.write_records(info, workdir, archive_paths) - self.build_zip(newpath, archive_paths) - if dest_dir is None: - shutil.copyfile(newpath, pathname) - return modified - -def compatible_tags(): - """ - Return (pyver, abi, arch) tuples compatible with this Python. - """ - versions = [VER_SUFFIX] - major = VER_SUFFIX[0] - for minor in range(sys.version_info[1] - 1, - 1, -1): - versions.append(''.join([major, str(minor)])) - - abis = [] - for suffix, _, _ in imp.get_suffixes(): - if suffix.startswith('.abi'): - abis.append(suffix.split('.', 2)[1]) - abis.sort() - if ABI != 'none': - abis.insert(0, ABI) - abis.append('none') - result = [] - - arches = [ARCH] - if sys.platform == 'darwin': - m = re.match('(\w+)_(\d+)_(\d+)_(\w+)$', ARCH) - if m: - name, major, minor, arch = m.groups() - minor = int(minor) - matches = [arch] - if arch in ('i386', 'ppc'): - matches.append('fat') - if arch in ('i386', 'ppc', 'x86_64'): - matches.append('fat3') - if arch in ('ppc64', 'x86_64'): - matches.append('fat64') - if arch in ('i386', 'x86_64'): - matches.append('intel') - if arch in ('i386', 'x86_64', 'intel', 'ppc', 'ppc64'): - matches.append('universal') - while minor >= 0: - for match in matches: - s = '%s_%s_%s_%s' % (name, major, minor, match) - if s != ARCH: # already there - arches.append(s) - minor -= 1 - - # Most specific - our Python version, ABI and arch - for abi in abis: - for arch in arches: - result.append((''.join((IMP_PREFIX, versions[0])), abi, arch)) - - # where no ABI / arch dependency, but IMP_PREFIX dependency - for i, version in enumerate(versions): - result.append((''.join((IMP_PREFIX, version)), 'none', 'any')) - if i == 0: - result.append((''.join((IMP_PREFIX, version[0])), 'none', 'any')) - - # no IMP_PREFIX, ABI or arch dependency - for i, version in enumerate(versions): - result.append((''.join(('py', version)), 'none', 'any')) - if i == 0: - result.append((''.join(('py', version[0])), 'none', 'any')) - return set(result) - - -COMPATIBLE_TAGS = compatible_tags() - -del compatible_tags - - -def is_compatible(wheel, tags=None): - if not isinstance(wheel, Wheel): - wheel = Wheel(wheel) # assume it's a filename - result = False - if tags is None: - tags = COMPATIBLE_TAGS - for ver, abi, arch in tags: - if ver in wheel.pyver and abi in wheel.abi and arch in wheel.arch: - result = True - break - return result diff --git a/vendor/pip-1.5.6/pip/_vendor/html5lib/__init__.py b/vendor/pip-1.5.6/pip/_vendor/html5lib/__init__.py deleted file mode 100644 index ff5c775..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/html5lib/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -""" -HTML parsing library based on the WHATWG "HTML5" -specification. The parser is designed to be compatible with existing -HTML found in the wild and implements well-defined error recovery that -is largely compatible with modern desktop web browsers. - -Example usage: - -import html5lib -f = open("my_document.html") -tree = html5lib.parse(f) -""" - -from __future__ import absolute_import, division, unicode_literals - -from .html5parser import HTMLParser, parse, parseFragment -from .treebuilders import getTreeBuilder -from .treewalkers import getTreeWalker -from .serializer import serialize - -__all__ = ["HTMLParser", "parse", "parseFragment", "getTreeBuilder", - "getTreeWalker", "serialize"] -__version__ = "1.0b3" diff --git a/vendor/pip-1.5.6/pip/_vendor/html5lib/constants.py b/vendor/pip-1.5.6/pip/_vendor/html5lib/constants.py deleted file mode 100644 index e708984..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/html5lib/constants.py +++ /dev/null @@ -1,3104 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -import string -import gettext -_ = gettext.gettext - -EOF = None - -E = { - "null-character": - _("Null character in input stream, replaced with U+FFFD."), - "invalid-codepoint": - _("Invalid codepoint in stream."), - "incorrectly-placed-solidus": - _("Solidus (/) incorrectly placed in tag."), - "incorrect-cr-newline-entity": - _("Incorrect CR newline entity, replaced with LF."), - "illegal-windows-1252-entity": - _("Entity used with illegal number (windows-1252 reference)."), - "cant-convert-numeric-entity": - _("Numeric entity couldn't be converted to character " - "(codepoint U+%(charAsInt)08x)."), - "illegal-codepoint-for-numeric-entity": - _("Numeric entity represents an illegal codepoint: " - "U+%(charAsInt)08x."), - "numeric-entity-without-semicolon": - _("Numeric entity didn't end with ';'."), - "expected-numeric-entity-but-got-eof": - _("Numeric entity expected. Got end of file instead."), - "expected-numeric-entity": - _("Numeric entity expected but none found."), - "named-entity-without-semicolon": - _("Named entity didn't end with ';'."), - "expected-named-entity": - _("Named entity expected. Got none."), - "attributes-in-end-tag": - _("End tag contains unexpected attributes."), - 'self-closing-flag-on-end-tag': - _("End tag contains unexpected self-closing flag."), - "expected-tag-name-but-got-right-bracket": - _("Expected tag name. Got '>' instead."), - "expected-tag-name-but-got-question-mark": - _("Expected tag name. Got '?' instead. (HTML doesn't " - "support processing instructions.)"), - "expected-tag-name": - _("Expected tag name. Got something else instead"), - "expected-closing-tag-but-got-right-bracket": - _("Expected closing tag. Got '>' instead. Ignoring ''."), - "expected-closing-tag-but-got-eof": - _("Expected closing tag. Unexpected end of file."), - "expected-closing-tag-but-got-char": - _("Expected closing tag. Unexpected character '%(data)s' found."), - "eof-in-tag-name": - _("Unexpected end of file in the tag name."), - "expected-attribute-name-but-got-eof": - _("Unexpected end of file. Expected attribute name instead."), - "eof-in-attribute-name": - _("Unexpected end of file in attribute name."), - "invalid-character-in-attribute-name": - _("Invalid character in attribute name"), - "duplicate-attribute": - _("Dropped duplicate attribute on tag."), - "expected-end-of-tag-name-but-got-eof": - _("Unexpected end of file. Expected = or end of tag."), - "expected-attribute-value-but-got-eof": - _("Unexpected end of file. Expected attribute value."), - "expected-attribute-value-but-got-right-bracket": - _("Expected attribute value. Got '>' instead."), - 'equals-in-unquoted-attribute-value': - _("Unexpected = in unquoted attribute"), - 'unexpected-character-in-unquoted-attribute-value': - _("Unexpected character in unquoted attribute"), - "invalid-character-after-attribute-name": - _("Unexpected character after attribute name."), - "unexpected-character-after-attribute-value": - _("Unexpected character after attribute value."), - "eof-in-attribute-value-double-quote": - _("Unexpected end of file in attribute value (\")."), - "eof-in-attribute-value-single-quote": - _("Unexpected end of file in attribute value (')."), - "eof-in-attribute-value-no-quotes": - _("Unexpected end of file in attribute value."), - "unexpected-EOF-after-solidus-in-tag": - _("Unexpected end of file in tag. Expected >"), - "unexpected-character-after-solidus-in-tag": - _("Unexpected character after / in tag. Expected >"), - "expected-dashes-or-doctype": - _("Expected '--' or 'DOCTYPE'. Not found."), - "unexpected-bang-after-double-dash-in-comment": - _("Unexpected ! after -- in comment"), - "unexpected-space-after-double-dash-in-comment": - _("Unexpected space after -- in comment"), - "incorrect-comment": - _("Incorrect comment."), - "eof-in-comment": - _("Unexpected end of file in comment."), - "eof-in-comment-end-dash": - _("Unexpected end of file in comment (-)"), - "unexpected-dash-after-double-dash-in-comment": - _("Unexpected '-' after '--' found in comment."), - "eof-in-comment-double-dash": - _("Unexpected end of file in comment (--)."), - "eof-in-comment-end-space-state": - _("Unexpected end of file in comment."), - "eof-in-comment-end-bang-state": - _("Unexpected end of file in comment."), - "unexpected-char-in-comment": - _("Unexpected character in comment found."), - "need-space-after-doctype": - _("No space after literal string 'DOCTYPE'."), - "expected-doctype-name-but-got-right-bracket": - _("Unexpected > character. Expected DOCTYPE name."), - "expected-doctype-name-but-got-eof": - _("Unexpected end of file. Expected DOCTYPE name."), - "eof-in-doctype-name": - _("Unexpected end of file in DOCTYPE name."), - "eof-in-doctype": - _("Unexpected end of file in DOCTYPE."), - "expected-space-or-right-bracket-in-doctype": - _("Expected space or '>'. Got '%(data)s'"), - "unexpected-end-of-doctype": - _("Unexpected end of DOCTYPE."), - "unexpected-char-in-doctype": - _("Unexpected character in DOCTYPE."), - "eof-in-innerhtml": - _("XXX innerHTML EOF"), - "unexpected-doctype": - _("Unexpected DOCTYPE. Ignored."), - "non-html-root": - _("html needs to be the first start tag."), - "expected-doctype-but-got-eof": - _("Unexpected End of file. Expected DOCTYPE."), - "unknown-doctype": - _("Erroneous DOCTYPE."), - "expected-doctype-but-got-chars": - _("Unexpected non-space characters. Expected DOCTYPE."), - "expected-doctype-but-got-start-tag": - _("Unexpected start tag (%(name)s). Expected DOCTYPE."), - "expected-doctype-but-got-end-tag": - _("Unexpected end tag (%(name)s). Expected DOCTYPE."), - "end-tag-after-implied-root": - _("Unexpected end tag (%(name)s) after the (implied) root element."), - "expected-named-closing-tag-but-got-eof": - _("Unexpected end of file. Expected end tag (%(name)s)."), - "two-heads-are-not-better-than-one": - _("Unexpected start tag head in existing head. Ignored."), - "unexpected-end-tag": - _("Unexpected end tag (%(name)s). Ignored."), - "unexpected-start-tag-out-of-my-head": - _("Unexpected start tag (%(name)s) that can be in head. Moved."), - "unexpected-start-tag": - _("Unexpected start tag (%(name)s)."), - "missing-end-tag": - _("Missing end tag (%(name)s)."), - "missing-end-tags": - _("Missing end tags (%(name)s)."), - "unexpected-start-tag-implies-end-tag": - _("Unexpected start tag (%(startName)s) " - "implies end tag (%(endName)s)."), - "unexpected-start-tag-treated-as": - _("Unexpected start tag (%(originalName)s). Treated as %(newName)s."), - "deprecated-tag": - _("Unexpected start tag %(name)s. Don't use it!"), - "unexpected-start-tag-ignored": - _("Unexpected start tag %(name)s. Ignored."), - "expected-one-end-tag-but-got-another": - _("Unexpected end tag (%(gotName)s). " - "Missing end tag (%(expectedName)s)."), - "end-tag-too-early": - _("End tag (%(name)s) seen too early. Expected other end tag."), - "end-tag-too-early-named": - _("Unexpected end tag (%(gotName)s). Expected end tag (%(expectedName)s)."), - "end-tag-too-early-ignored": - _("End tag (%(name)s) seen too early. Ignored."), - "adoption-agency-1.1": - _("End tag (%(name)s) violates step 1, " - "paragraph 1 of the adoption agency algorithm."), - "adoption-agency-1.2": - _("End tag (%(name)s) violates step 1, " - "paragraph 2 of the adoption agency algorithm."), - "adoption-agency-1.3": - _("End tag (%(name)s) violates step 1, " - "paragraph 3 of the adoption agency algorithm."), - "adoption-agency-4.4": - _("End tag (%(name)s) violates step 4, " - "paragraph 4 of the adoption agency algorithm."), - "unexpected-end-tag-treated-as": - _("Unexpected end tag (%(originalName)s). Treated as %(newName)s."), - "no-end-tag": - _("This element (%(name)s) has no end tag."), - "unexpected-implied-end-tag-in-table": - _("Unexpected implied end tag (%(name)s) in the table phase."), - "unexpected-implied-end-tag-in-table-body": - _("Unexpected implied end tag (%(name)s) in the table body phase."), - "unexpected-char-implies-table-voodoo": - _("Unexpected non-space characters in " - "table context caused voodoo mode."), - "unexpected-hidden-input-in-table": - _("Unexpected input with type hidden in table context."), - "unexpected-form-in-table": - _("Unexpected form in table context."), - "unexpected-start-tag-implies-table-voodoo": - _("Unexpected start tag (%(name)s) in " - "table context caused voodoo mode."), - "unexpected-end-tag-implies-table-voodoo": - _("Unexpected end tag (%(name)s) in " - "table context caused voodoo mode."), - "unexpected-cell-in-table-body": - _("Unexpected table cell start tag (%(name)s) " - "in the table body phase."), - "unexpected-cell-end-tag": - _("Got table cell end tag (%(name)s) " - "while required end tags are missing."), - "unexpected-end-tag-in-table-body": - _("Unexpected end tag (%(name)s) in the table body phase. Ignored."), - "unexpected-implied-end-tag-in-table-row": - _("Unexpected implied end tag (%(name)s) in the table row phase."), - "unexpected-end-tag-in-table-row": - _("Unexpected end tag (%(name)s) in the table row phase. Ignored."), - "unexpected-select-in-select": - _("Unexpected select start tag in the select phase " - "treated as select end tag."), - "unexpected-input-in-select": - _("Unexpected input start tag in the select phase."), - "unexpected-start-tag-in-select": - _("Unexpected start tag token (%(name)s in the select phase. " - "Ignored."), - "unexpected-end-tag-in-select": - _("Unexpected end tag (%(name)s) in the select phase. Ignored."), - "unexpected-table-element-start-tag-in-select-in-table": - _("Unexpected table element start tag (%(name)s) in the select in table phase."), - "unexpected-table-element-end-tag-in-select-in-table": - _("Unexpected table element end tag (%(name)s) in the select in table phase."), - "unexpected-char-after-body": - _("Unexpected non-space characters in the after body phase."), - "unexpected-start-tag-after-body": - _("Unexpected start tag token (%(name)s)" - " in the after body phase."), - "unexpected-end-tag-after-body": - _("Unexpected end tag token (%(name)s)" - " in the after body phase."), - "unexpected-char-in-frameset": - _("Unexpected characters in the frameset phase. Characters ignored."), - "unexpected-start-tag-in-frameset": - _("Unexpected start tag token (%(name)s)" - " in the frameset phase. Ignored."), - "unexpected-frameset-in-frameset-innerhtml": - _("Unexpected end tag token (frameset) " - "in the frameset phase (innerHTML)."), - "unexpected-end-tag-in-frameset": - _("Unexpected end tag token (%(name)s)" - " in the frameset phase. Ignored."), - "unexpected-char-after-frameset": - _("Unexpected non-space characters in the " - "after frameset phase. Ignored."), - "unexpected-start-tag-after-frameset": - _("Unexpected start tag (%(name)s)" - " in the after frameset phase. Ignored."), - "unexpected-end-tag-after-frameset": - _("Unexpected end tag (%(name)s)" - " in the after frameset phase. Ignored."), - "unexpected-end-tag-after-body-innerhtml": - _("Unexpected end tag after body(innerHtml)"), - "expected-eof-but-got-char": - _("Unexpected non-space characters. Expected end of file."), - "expected-eof-but-got-start-tag": - _("Unexpected start tag (%(name)s)" - ". Expected end of file."), - "expected-eof-but-got-end-tag": - _("Unexpected end tag (%(name)s)" - ". Expected end of file."), - "eof-in-table": - _("Unexpected end of file. Expected table content."), - "eof-in-select": - _("Unexpected end of file. Expected select content."), - "eof-in-frameset": - _("Unexpected end of file. Expected frameset content."), - "eof-in-script-in-script": - _("Unexpected end of file. Expected script content."), - "eof-in-foreign-lands": - _("Unexpected end of file. Expected foreign content"), - "non-void-element-with-trailing-solidus": - _("Trailing solidus not allowed on element %(name)s"), - "unexpected-html-element-in-foreign-content": - _("Element %(name)s not allowed in a non-html context"), - "unexpected-end-tag-before-html": - _("Unexpected end tag (%(name)s) before html."), - "XXX-undefined-error": - _("Undefined error (this sucks and should be fixed)"), -} - -namespaces = { - "html": "http://www.w3.org/1999/xhtml", - "mathml": "http://www.w3.org/1998/Math/MathML", - "svg": "http://www.w3.org/2000/svg", - "xlink": "http://www.w3.org/1999/xlink", - "xml": "http://www.w3.org/XML/1998/namespace", - "xmlns": "http://www.w3.org/2000/xmlns/" -} - -scopingElements = frozenset(( - (namespaces["html"], "applet"), - (namespaces["html"], "caption"), - (namespaces["html"], "html"), - (namespaces["html"], "marquee"), - (namespaces["html"], "object"), - (namespaces["html"], "table"), - (namespaces["html"], "td"), - (namespaces["html"], "th"), - (namespaces["mathml"], "mi"), - (namespaces["mathml"], "mo"), - (namespaces["mathml"], "mn"), - (namespaces["mathml"], "ms"), - (namespaces["mathml"], "mtext"), - (namespaces["mathml"], "annotation-xml"), - (namespaces["svg"], "foreignObject"), - (namespaces["svg"], "desc"), - (namespaces["svg"], "title"), -)) - -formattingElements = frozenset(( - (namespaces["html"], "a"), - (namespaces["html"], "b"), - (namespaces["html"], "big"), - (namespaces["html"], "code"), - (namespaces["html"], "em"), - (namespaces["html"], "font"), - (namespaces["html"], "i"), - (namespaces["html"], "nobr"), - (namespaces["html"], "s"), - (namespaces["html"], "small"), - (namespaces["html"], "strike"), - (namespaces["html"], "strong"), - (namespaces["html"], "tt"), - (namespaces["html"], "u") -)) - -specialElements = frozenset(( - (namespaces["html"], "address"), - (namespaces["html"], "applet"), - (namespaces["html"], "area"), - (namespaces["html"], "article"), - (namespaces["html"], "aside"), - (namespaces["html"], "base"), - (namespaces["html"], "basefont"), - (namespaces["html"], "bgsound"), - (namespaces["html"], "blockquote"), - (namespaces["html"], "body"), - (namespaces["html"], "br"), - (namespaces["html"], "button"), - (namespaces["html"], "caption"), - (namespaces["html"], "center"), - (namespaces["html"], "col"), - (namespaces["html"], "colgroup"), - (namespaces["html"], "command"), - (namespaces["html"], "dd"), - (namespaces["html"], "details"), - (namespaces["html"], "dir"), - (namespaces["html"], "div"), - (namespaces["html"], "dl"), - (namespaces["html"], "dt"), - (namespaces["html"], "embed"), - (namespaces["html"], "fieldset"), - (namespaces["html"], "figure"), - (namespaces["html"], "footer"), - (namespaces["html"], "form"), - (namespaces["html"], "frame"), - (namespaces["html"], "frameset"), - (namespaces["html"], "h1"), - (namespaces["html"], "h2"), - (namespaces["html"], "h3"), - (namespaces["html"], "h4"), - (namespaces["html"], "h5"), - (namespaces["html"], "h6"), - (namespaces["html"], "head"), - (namespaces["html"], "header"), - (namespaces["html"], "hr"), - (namespaces["html"], "html"), - (namespaces["html"], "iframe"), - # Note that image is commented out in the spec as "this isn't an - # element that can end up on the stack, so it doesn't matter," - (namespaces["html"], "image"), - (namespaces["html"], "img"), - (namespaces["html"], "input"), - (namespaces["html"], "isindex"), - (namespaces["html"], "li"), - (namespaces["html"], "link"), - (namespaces["html"], "listing"), - (namespaces["html"], "marquee"), - (namespaces["html"], "menu"), - (namespaces["html"], "meta"), - (namespaces["html"], "nav"), - (namespaces["html"], "noembed"), - (namespaces["html"], "noframes"), - (namespaces["html"], "noscript"), - (namespaces["html"], "object"), - (namespaces["html"], "ol"), - (namespaces["html"], "p"), - (namespaces["html"], "param"), - (namespaces["html"], "plaintext"), - (namespaces["html"], "pre"), - (namespaces["html"], "script"), - (namespaces["html"], "section"), - (namespaces["html"], "select"), - (namespaces["html"], "style"), - (namespaces["html"], "table"), - (namespaces["html"], "tbody"), - (namespaces["html"], "td"), - (namespaces["html"], "textarea"), - (namespaces["html"], "tfoot"), - (namespaces["html"], "th"), - (namespaces["html"], "thead"), - (namespaces["html"], "title"), - (namespaces["html"], "tr"), - (namespaces["html"], "ul"), - (namespaces["html"], "wbr"), - (namespaces["html"], "xmp"), - (namespaces["svg"], "foreignObject") -)) - -htmlIntegrationPointElements = frozenset(( - (namespaces["mathml"], "annotaion-xml"), - (namespaces["svg"], "foreignObject"), - (namespaces["svg"], "desc"), - (namespaces["svg"], "title") -)) - -mathmlTextIntegrationPointElements = frozenset(( - (namespaces["mathml"], "mi"), - (namespaces["mathml"], "mo"), - (namespaces["mathml"], "mn"), - (namespaces["mathml"], "ms"), - (namespaces["mathml"], "mtext") -)) - -adjustForeignAttributes = { - "xlink:actuate": ("xlink", "actuate", namespaces["xlink"]), - "xlink:arcrole": ("xlink", "arcrole", namespaces["xlink"]), - "xlink:href": ("xlink", "href", namespaces["xlink"]), - "xlink:role": ("xlink", "role", namespaces["xlink"]), - "xlink:show": ("xlink", "show", namespaces["xlink"]), - "xlink:title": ("xlink", "title", namespaces["xlink"]), - "xlink:type": ("xlink", "type", namespaces["xlink"]), - "xml:base": ("xml", "base", namespaces["xml"]), - "xml:lang": ("xml", "lang", namespaces["xml"]), - "xml:space": ("xml", "space", namespaces["xml"]), - "xmlns": (None, "xmlns", namespaces["xmlns"]), - "xmlns:xlink": ("xmlns", "xlink", namespaces["xmlns"]) -} - -unadjustForeignAttributes = dict([((ns, local), qname) for qname, (prefix, local, ns) in - adjustForeignAttributes.items()]) - -spaceCharacters = frozenset(( - "\t", - "\n", - "\u000C", - " ", - "\r" -)) - -tableInsertModeElements = frozenset(( - "table", - "tbody", - "tfoot", - "thead", - "tr" -)) - -asciiLowercase = frozenset(string.ascii_lowercase) -asciiUppercase = frozenset(string.ascii_uppercase) -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]) - -# Heading elements need to be ordered -headingElements = ( - "h1", - "h2", - "h3", - "h4", - "h5", - "h6" -) - -voidElements = frozenset(( - "base", - "command", - "event-source", - "link", - "meta", - "hr", - "br", - "img", - "embed", - "param", - "area", - "col", - "input", - "source", - "track" -)) - -cdataElements = frozenset(('title', 'textarea')) - -rcdataElements = frozenset(( - 'style', - 'script', - 'xmp', - 'iframe', - 'noembed', - 'noframes', - 'noscript' -)) - -booleanAttributes = { - "": frozenset(("irrelevant",)), - "style": frozenset(("scoped",)), - "img": frozenset(("ismap",)), - "audio": frozenset(("autoplay", "controls")), - "video": frozenset(("autoplay", "controls")), - "script": frozenset(("defer", "async")), - "details": frozenset(("open",)), - "datagrid": frozenset(("multiple", "disabled")), - "command": frozenset(("hidden", "disabled", "checked", "default")), - "hr": frozenset(("noshade")), - "menu": frozenset(("autosubmit",)), - "fieldset": frozenset(("disabled", "readonly")), - "option": frozenset(("disabled", "readonly", "selected")), - "optgroup": frozenset(("disabled", "readonly")), - "button": frozenset(("disabled", "autofocus")), - "input": frozenset(("disabled", "readonly", "required", "autofocus", "checked", "ismap")), - "select": frozenset(("disabled", "readonly", "autofocus", "multiple")), - "output": frozenset(("disabled", "readonly")), -} - -# entitiesWindows1252 has to be _ordered_ and needs to have an index. It -# therefore can't be a frozenset. -entitiesWindows1252 = ( - 8364, # 0x80 0x20AC EURO SIGN - 65533, # 0x81 UNDEFINED - 8218, # 0x82 0x201A SINGLE LOW-9 QUOTATION MARK - 402, # 0x83 0x0192 LATIN SMALL LETTER F WITH HOOK - 8222, # 0x84 0x201E DOUBLE LOW-9 QUOTATION MARK - 8230, # 0x85 0x2026 HORIZONTAL ELLIPSIS - 8224, # 0x86 0x2020 DAGGER - 8225, # 0x87 0x2021 DOUBLE DAGGER - 710, # 0x88 0x02C6 MODIFIER LETTER CIRCUMFLEX ACCENT - 8240, # 0x89 0x2030 PER MILLE SIGN - 352, # 0x8A 0x0160 LATIN CAPITAL LETTER S WITH CARON - 8249, # 0x8B 0x2039 SINGLE LEFT-POINTING ANGLE QUOTATION MARK - 338, # 0x8C 0x0152 LATIN CAPITAL LIGATURE OE - 65533, # 0x8D UNDEFINED - 381, # 0x8E 0x017D LATIN CAPITAL LETTER Z WITH CARON - 65533, # 0x8F UNDEFINED - 65533, # 0x90 UNDEFINED - 8216, # 0x91 0x2018 LEFT SINGLE QUOTATION MARK - 8217, # 0x92 0x2019 RIGHT SINGLE QUOTATION MARK - 8220, # 0x93 0x201C LEFT DOUBLE QUOTATION MARK - 8221, # 0x94 0x201D RIGHT DOUBLE QUOTATION MARK - 8226, # 0x95 0x2022 BULLET - 8211, # 0x96 0x2013 EN DASH - 8212, # 0x97 0x2014 EM DASH - 732, # 0x98 0x02DC SMALL TILDE - 8482, # 0x99 0x2122 TRADE MARK SIGN - 353, # 0x9A 0x0161 LATIN SMALL LETTER S WITH CARON - 8250, # 0x9B 0x203A SINGLE RIGHT-POINTING ANGLE QUOTATION MARK - 339, # 0x9C 0x0153 LATIN SMALL LIGATURE OE - 65533, # 0x9D UNDEFINED - 382, # 0x9E 0x017E LATIN SMALL LETTER Z WITH CARON - 376 # 0x9F 0x0178 LATIN CAPITAL LETTER Y WITH DIAERESIS -) - -xmlEntities = frozenset(('lt;', 'gt;', 'amp;', 'apos;', 'quot;')) - -entities = { - "AElig": "\xc6", - "AElig;": "\xc6", - "AMP": "&", - "AMP;": "&", - "Aacute": "\xc1", - "Aacute;": "\xc1", - "Abreve;": "\u0102", - "Acirc": "\xc2", - "Acirc;": "\xc2", - "Acy;": "\u0410", - "Afr;": "\U0001d504", - "Agrave": "\xc0", - "Agrave;": "\xc0", - "Alpha;": "\u0391", - "Amacr;": "\u0100", - "And;": "\u2a53", - "Aogon;": "\u0104", - "Aopf;": "\U0001d538", - "ApplyFunction;": "\u2061", - "Aring": "\xc5", - "Aring;": "\xc5", - "Ascr;": "\U0001d49c", - "Assign;": "\u2254", - "Atilde": "\xc3", - "Atilde;": "\xc3", - "Auml": "\xc4", - "Auml;": "\xc4", - "Backslash;": "\u2216", - "Barv;": "\u2ae7", - "Barwed;": "\u2306", - "Bcy;": "\u0411", - "Because;": "\u2235", - "Bernoullis;": "\u212c", - "Beta;": "\u0392", - "Bfr;": "\U0001d505", - "Bopf;": "\U0001d539", - "Breve;": "\u02d8", - "Bscr;": "\u212c", - "Bumpeq;": "\u224e", - "CHcy;": "\u0427", - "COPY": "\xa9", - "COPY;": "\xa9", - "Cacute;": "\u0106", - "Cap;": "\u22d2", - "CapitalDifferentialD;": "\u2145", - "Cayleys;": "\u212d", - "Ccaron;": "\u010c", - "Ccedil": "\xc7", - "Ccedil;": "\xc7", - "Ccirc;": "\u0108", - "Cconint;": "\u2230", - "Cdot;": "\u010a", - "Cedilla;": "\xb8", - "CenterDot;": "\xb7", - "Cfr;": "\u212d", - "Chi;": "\u03a7", - "CircleDot;": "\u2299", - "CircleMinus;": "\u2296", - "CirclePlus;": "\u2295", - "CircleTimes;": "\u2297", - "ClockwiseContourIntegral;": "\u2232", - "CloseCurlyDoubleQuote;": "\u201d", - "CloseCurlyQuote;": "\u2019", - "Colon;": "\u2237", - "Colone;": "\u2a74", - "Congruent;": "\u2261", - "Conint;": "\u222f", - "ContourIntegral;": "\u222e", - "Copf;": "\u2102", - "Coproduct;": "\u2210", - "CounterClockwiseContourIntegral;": "\u2233", - "Cross;": "\u2a2f", - "Cscr;": "\U0001d49e", - "Cup;": "\u22d3", - "CupCap;": "\u224d", - "DD;": "\u2145", - "DDotrahd;": "\u2911", - "DJcy;": "\u0402", - "DScy;": "\u0405", - "DZcy;": "\u040f", - "Dagger;": "\u2021", - "Darr;": "\u21a1", - "Dashv;": "\u2ae4", - "Dcaron;": "\u010e", - "Dcy;": "\u0414", - "Del;": "\u2207", - "Delta;": "\u0394", - "Dfr;": "\U0001d507", - "DiacriticalAcute;": "\xb4", - "DiacriticalDot;": "\u02d9", - "DiacriticalDoubleAcute;": "\u02dd", - "DiacriticalGrave;": "`", - "DiacriticalTilde;": "\u02dc", - "Diamond;": "\u22c4", - "DifferentialD;": "\u2146", - "Dopf;": "\U0001d53b", - "Dot;": "\xa8", - "DotDot;": "\u20dc", - "DotEqual;": "\u2250", - "DoubleContourIntegral;": "\u222f", - "DoubleDot;": "\xa8", - "DoubleDownArrow;": "\u21d3", - "DoubleLeftArrow;": "\u21d0", - "DoubleLeftRightArrow;": "\u21d4", - "DoubleLeftTee;": "\u2ae4", - "DoubleLongLeftArrow;": "\u27f8", - "DoubleLongLeftRightArrow;": "\u27fa", - "DoubleLongRightArrow;": "\u27f9", - "DoubleRightArrow;": "\u21d2", - "DoubleRightTee;": "\u22a8", - "DoubleUpArrow;": "\u21d1", - "DoubleUpDownArrow;": "\u21d5", - "DoubleVerticalBar;": "\u2225", - "DownArrow;": "\u2193", - "DownArrowBar;": "\u2913", - "DownArrowUpArrow;": "\u21f5", - "DownBreve;": "\u0311", - "DownLeftRightVector;": "\u2950", - "DownLeftTeeVector;": "\u295e", - "DownLeftVector;": "\u21bd", - "DownLeftVectorBar;": "\u2956", - "DownRightTeeVector;": "\u295f", - "DownRightVector;": "\u21c1", - "DownRightVectorBar;": "\u2957", - "DownTee;": "\u22a4", - "DownTeeArrow;": "\u21a7", - "Downarrow;": "\u21d3", - "Dscr;": "\U0001d49f", - "Dstrok;": "\u0110", - "ENG;": "\u014a", - "ETH": "\xd0", - "ETH;": "\xd0", - "Eacute": "\xc9", - "Eacute;": "\xc9", - "Ecaron;": "\u011a", - "Ecirc": "\xca", - "Ecirc;": "\xca", - "Ecy;": "\u042d", - "Edot;": "\u0116", - "Efr;": "\U0001d508", - "Egrave": "\xc8", - "Egrave;": "\xc8", - "Element;": "\u2208", - "Emacr;": "\u0112", - "EmptySmallSquare;": "\u25fb", - "EmptyVerySmallSquare;": "\u25ab", - "Eogon;": "\u0118", - "Eopf;": "\U0001d53c", - "Epsilon;": "\u0395", - "Equal;": "\u2a75", - "EqualTilde;": "\u2242", - "Equilibrium;": "\u21cc", - "Escr;": "\u2130", - "Esim;": "\u2a73", - "Eta;": "\u0397", - "Euml": "\xcb", - "Euml;": "\xcb", - "Exists;": "\u2203", - "ExponentialE;": "\u2147", - "Fcy;": "\u0424", - "Ffr;": "\U0001d509", - "FilledSmallSquare;": "\u25fc", - "FilledVerySmallSquare;": "\u25aa", - "Fopf;": "\U0001d53d", - "ForAll;": "\u2200", - "Fouriertrf;": "\u2131", - "Fscr;": "\u2131", - "GJcy;": "\u0403", - "GT": ">", - "GT;": ">", - "Gamma;": "\u0393", - "Gammad;": "\u03dc", - "Gbreve;": "\u011e", - "Gcedil;": "\u0122", - "Gcirc;": "\u011c", - "Gcy;": "\u0413", - "Gdot;": "\u0120", - "Gfr;": "\U0001d50a", - "Gg;": "\u22d9", - "Gopf;": "\U0001d53e", - "GreaterEqual;": "\u2265", - "GreaterEqualLess;": "\u22db", - "GreaterFullEqual;": "\u2267", - "GreaterGreater;": "\u2aa2", - "GreaterLess;": "\u2277", - "GreaterSlantEqual;": "\u2a7e", - "GreaterTilde;": "\u2273", - "Gscr;": "\U0001d4a2", - "Gt;": "\u226b", - "HARDcy;": "\u042a", - "Hacek;": "\u02c7", - "Hat;": "^", - "Hcirc;": "\u0124", - "Hfr;": "\u210c", - "HilbertSpace;": "\u210b", - "Hopf;": "\u210d", - "HorizontalLine;": "\u2500", - "Hscr;": "\u210b", - "Hstrok;": "\u0126", - "HumpDownHump;": "\u224e", - "HumpEqual;": "\u224f", - "IEcy;": "\u0415", - "IJlig;": "\u0132", - "IOcy;": "\u0401", - "Iacute": "\xcd", - "Iacute;": "\xcd", - "Icirc": "\xce", - "Icirc;": "\xce", - "Icy;": "\u0418", - "Idot;": "\u0130", - "Ifr;": "\u2111", - "Igrave": "\xcc", - "Igrave;": "\xcc", - "Im;": "\u2111", - "Imacr;": "\u012a", - "ImaginaryI;": "\u2148", - "Implies;": "\u21d2", - "Int;": "\u222c", - "Integral;": "\u222b", - "Intersection;": "\u22c2", - "InvisibleComma;": "\u2063", - "InvisibleTimes;": "\u2062", - "Iogon;": "\u012e", - "Iopf;": "\U0001d540", - "Iota;": "\u0399", - "Iscr;": "\u2110", - "Itilde;": "\u0128", - "Iukcy;": "\u0406", - "Iuml": "\xcf", - "Iuml;": "\xcf", - "Jcirc;": "\u0134", - "Jcy;": "\u0419", - "Jfr;": "\U0001d50d", - "Jopf;": "\U0001d541", - "Jscr;": "\U0001d4a5", - "Jsercy;": "\u0408", - "Jukcy;": "\u0404", - "KHcy;": "\u0425", - "KJcy;": "\u040c", - "Kappa;": "\u039a", - "Kcedil;": "\u0136", - "Kcy;": "\u041a", - "Kfr;": "\U0001d50e", - "Kopf;": "\U0001d542", - "Kscr;": "\U0001d4a6", - "LJcy;": "\u0409", - "LT": "<", - "LT;": "<", - "Lacute;": "\u0139", - "Lambda;": "\u039b", - "Lang;": "\u27ea", - "Laplacetrf;": "\u2112", - "Larr;": "\u219e", - "Lcaron;": "\u013d", - "Lcedil;": "\u013b", - "Lcy;": "\u041b", - "LeftAngleBracket;": "\u27e8", - "LeftArrow;": "\u2190", - "LeftArrowBar;": "\u21e4", - "LeftArrowRightArrow;": "\u21c6", - "LeftCeiling;": "\u2308", - "LeftDoubleBracket;": "\u27e6", - "LeftDownTeeVector;": "\u2961", - "LeftDownVector;": "\u21c3", - "LeftDownVectorBar;": "\u2959", - "LeftFloor;": "\u230a", - "LeftRightArrow;": "\u2194", - "LeftRightVector;": "\u294e", - "LeftTee;": "\u22a3", - "LeftTeeArrow;": "\u21a4", - "LeftTeeVector;": "\u295a", - "LeftTriangle;": "\u22b2", - "LeftTriangleBar;": "\u29cf", - "LeftTriangleEqual;": "\u22b4", - "LeftUpDownVector;": "\u2951", - "LeftUpTeeVector;": "\u2960", - "LeftUpVector;": "\u21bf", - "LeftUpVectorBar;": "\u2958", - "LeftVector;": "\u21bc", - "LeftVectorBar;": "\u2952", - "Leftarrow;": "\u21d0", - "Leftrightarrow;": "\u21d4", - "LessEqualGreater;": "\u22da", - "LessFullEqual;": "\u2266", - "LessGreater;": "\u2276", - "LessLess;": "\u2aa1", - "LessSlantEqual;": "\u2a7d", - "LessTilde;": "\u2272", - "Lfr;": "\U0001d50f", - "Ll;": "\u22d8", - "Lleftarrow;": "\u21da", - "Lmidot;": "\u013f", - "LongLeftArrow;": "\u27f5", - "LongLeftRightArrow;": "\u27f7", - "LongRightArrow;": "\u27f6", - "Longleftarrow;": "\u27f8", - "Longleftrightarrow;": "\u27fa", - "Longrightarrow;": "\u27f9", - "Lopf;": "\U0001d543", - "LowerLeftArrow;": "\u2199", - "LowerRightArrow;": "\u2198", - "Lscr;": "\u2112", - "Lsh;": "\u21b0", - "Lstrok;": "\u0141", - "Lt;": "\u226a", - "Map;": "\u2905", - "Mcy;": "\u041c", - "MediumSpace;": "\u205f", - "Mellintrf;": "\u2133", - "Mfr;": "\U0001d510", - "MinusPlus;": "\u2213", - "Mopf;": "\U0001d544", - "Mscr;": "\u2133", - "Mu;": "\u039c", - "NJcy;": "\u040a", - "Nacute;": "\u0143", - "Ncaron;": "\u0147", - "Ncedil;": "\u0145", - "Ncy;": "\u041d", - "NegativeMediumSpace;": "\u200b", - "NegativeThickSpace;": "\u200b", - "NegativeThinSpace;": "\u200b", - "NegativeVeryThinSpace;": "\u200b", - "NestedGreaterGreater;": "\u226b", - "NestedLessLess;": "\u226a", - "NewLine;": "\n", - "Nfr;": "\U0001d511", - "NoBreak;": "\u2060", - "NonBreakingSpace;": "\xa0", - "Nopf;": "\u2115", - "Not;": "\u2aec", - "NotCongruent;": "\u2262", - "NotCupCap;": "\u226d", - "NotDoubleVerticalBar;": "\u2226", - "NotElement;": "\u2209", - "NotEqual;": "\u2260", - "NotEqualTilde;": "\u2242\u0338", - "NotExists;": "\u2204", - "NotGreater;": "\u226f", - "NotGreaterEqual;": "\u2271", - "NotGreaterFullEqual;": "\u2267\u0338", - "NotGreaterGreater;": "\u226b\u0338", - "NotGreaterLess;": "\u2279", - "NotGreaterSlantEqual;": "\u2a7e\u0338", - "NotGreaterTilde;": "\u2275", - "NotHumpDownHump;": "\u224e\u0338", - "NotHumpEqual;": "\u224f\u0338", - "NotLeftTriangle;": "\u22ea", - "NotLeftTriangleBar;": "\u29cf\u0338", - "NotLeftTriangleEqual;": "\u22ec", - "NotLess;": "\u226e", - "NotLessEqual;": "\u2270", - "NotLessGreater;": "\u2278", - "NotLessLess;": "\u226a\u0338", - "NotLessSlantEqual;": "\u2a7d\u0338", - "NotLessTilde;": "\u2274", - "NotNestedGreaterGreater;": "\u2aa2\u0338", - "NotNestedLessLess;": "\u2aa1\u0338", - "NotPrecedes;": "\u2280", - "NotPrecedesEqual;": "\u2aaf\u0338", - "NotPrecedesSlantEqual;": "\u22e0", - "NotReverseElement;": "\u220c", - "NotRightTriangle;": "\u22eb", - "NotRightTriangleBar;": "\u29d0\u0338", - "NotRightTriangleEqual;": "\u22ed", - "NotSquareSubset;": "\u228f\u0338", - "NotSquareSubsetEqual;": "\u22e2", - "NotSquareSuperset;": "\u2290\u0338", - "NotSquareSupersetEqual;": "\u22e3", - "NotSubset;": "\u2282\u20d2", - "NotSubsetEqual;": "\u2288", - "NotSucceeds;": "\u2281", - "NotSucceedsEqual;": "\u2ab0\u0338", - "NotSucceedsSlantEqual;": "\u22e1", - "NotSucceedsTilde;": "\u227f\u0338", - "NotSuperset;": "\u2283\u20d2", - "NotSupersetEqual;": "\u2289", - "NotTilde;": "\u2241", - "NotTildeEqual;": "\u2244", - "NotTildeFullEqual;": "\u2247", - "NotTildeTilde;": "\u2249", - "NotVerticalBar;": "\u2224", - "Nscr;": "\U0001d4a9", - "Ntilde": "\xd1", - "Ntilde;": "\xd1", - "Nu;": "\u039d", - "OElig;": "\u0152", - "Oacute": "\xd3", - "Oacute;": "\xd3", - "Ocirc": "\xd4", - "Ocirc;": "\xd4", - "Ocy;": "\u041e", - "Odblac;": "\u0150", - "Ofr;": "\U0001d512", - "Ograve": "\xd2", - "Ograve;": "\xd2", - "Omacr;": "\u014c", - "Omega;": "\u03a9", - "Omicron;": "\u039f", - "Oopf;": "\U0001d546", - "OpenCurlyDoubleQuote;": "\u201c", - "OpenCurlyQuote;": "\u2018", - "Or;": "\u2a54", - "Oscr;": "\U0001d4aa", - "Oslash": "\xd8", - "Oslash;": "\xd8", - "Otilde": "\xd5", - "Otilde;": "\xd5", - "Otimes;": "\u2a37", - "Ouml": "\xd6", - "Ouml;": "\xd6", - "OverBar;": "\u203e", - "OverBrace;": "\u23de", - "OverBracket;": "\u23b4", - "OverParenthesis;": "\u23dc", - "PartialD;": "\u2202", - "Pcy;": "\u041f", - "Pfr;": "\U0001d513", - "Phi;": "\u03a6", - "Pi;": "\u03a0", - "PlusMinus;": "\xb1", - "Poincareplane;": "\u210c", - "Popf;": "\u2119", - "Pr;": "\u2abb", - "Precedes;": "\u227a", - "PrecedesEqual;": "\u2aaf", - "PrecedesSlantEqual;": "\u227c", - "PrecedesTilde;": "\u227e", - "Prime;": "\u2033", - "Product;": "\u220f", - "Proportion;": "\u2237", - "Proportional;": "\u221d", - "Pscr;": "\U0001d4ab", - "Psi;": "\u03a8", - "QUOT": "\"", - "QUOT;": "\"", - "Qfr;": "\U0001d514", - "Qopf;": "\u211a", - "Qscr;": "\U0001d4ac", - "RBarr;": "\u2910", - "REG": "\xae", - "REG;": "\xae", - "Racute;": "\u0154", - "Rang;": "\u27eb", - "Rarr;": "\u21a0", - "Rarrtl;": "\u2916", - "Rcaron;": "\u0158", - "Rcedil;": "\u0156", - "Rcy;": "\u0420", - "Re;": "\u211c", - "ReverseElement;": "\u220b", - "ReverseEquilibrium;": "\u21cb", - "ReverseUpEquilibrium;": "\u296f", - "Rfr;": "\u211c", - "Rho;": "\u03a1", - "RightAngleBracket;": "\u27e9", - "RightArrow;": "\u2192", - "RightArrowBar;": "\u21e5", - "RightArrowLeftArrow;": "\u21c4", - "RightCeiling;": "\u2309", - "RightDoubleBracket;": "\u27e7", - "RightDownTeeVector;": "\u295d", - "RightDownVector;": "\u21c2", - "RightDownVectorBar;": "\u2955", - "RightFloor;": "\u230b", - "RightTee;": "\u22a2", - "RightTeeArrow;": "\u21a6", - "RightTeeVector;": "\u295b", - "RightTriangle;": "\u22b3", - "RightTriangleBar;": "\u29d0", - "RightTriangleEqual;": "\u22b5", - "RightUpDownVector;": "\u294f", - "RightUpTeeVector;": "\u295c", - "RightUpVector;": "\u21be", - "RightUpVectorBar;": "\u2954", - "RightVector;": "\u21c0", - "RightVectorBar;": "\u2953", - "Rightarrow;": "\u21d2", - "Ropf;": "\u211d", - "RoundImplies;": "\u2970", - "Rrightarrow;": "\u21db", - "Rscr;": "\u211b", - "Rsh;": "\u21b1", - "RuleDelayed;": "\u29f4", - "SHCHcy;": "\u0429", - "SHcy;": "\u0428", - "SOFTcy;": "\u042c", - "Sacute;": "\u015a", - "Sc;": "\u2abc", - "Scaron;": "\u0160", - "Scedil;": "\u015e", - "Scirc;": "\u015c", - "Scy;": "\u0421", - "Sfr;": "\U0001d516", - "ShortDownArrow;": "\u2193", - "ShortLeftArrow;": "\u2190", - "ShortRightArrow;": "\u2192", - "ShortUpArrow;": "\u2191", - "Sigma;": "\u03a3", - "SmallCircle;": "\u2218", - "Sopf;": "\U0001d54a", - "Sqrt;": "\u221a", - "Square;": "\u25a1", - "SquareIntersection;": "\u2293", - "SquareSubset;": "\u228f", - "SquareSubsetEqual;": "\u2291", - "SquareSuperset;": "\u2290", - "SquareSupersetEqual;": "\u2292", - "SquareUnion;": "\u2294", - "Sscr;": "\U0001d4ae", - "Star;": "\u22c6", - "Sub;": "\u22d0", - "Subset;": "\u22d0", - "SubsetEqual;": "\u2286", - "Succeeds;": "\u227b", - "SucceedsEqual;": "\u2ab0", - "SucceedsSlantEqual;": "\u227d", - "SucceedsTilde;": "\u227f", - "SuchThat;": "\u220b", - "Sum;": "\u2211", - "Sup;": "\u22d1", - "Superset;": "\u2283", - "SupersetEqual;": "\u2287", - "Supset;": "\u22d1", - "THORN": "\xde", - "THORN;": "\xde", - "TRADE;": "\u2122", - "TSHcy;": "\u040b", - "TScy;": "\u0426", - "Tab;": "\t", - "Tau;": "\u03a4", - "Tcaron;": "\u0164", - "Tcedil;": "\u0162", - "Tcy;": "\u0422", - "Tfr;": "\U0001d517", - "Therefore;": "\u2234", - "Theta;": "\u0398", - "ThickSpace;": "\u205f\u200a", - "ThinSpace;": "\u2009", - "Tilde;": "\u223c", - "TildeEqual;": "\u2243", - "TildeFullEqual;": "\u2245", - "TildeTilde;": "\u2248", - "Topf;": "\U0001d54b", - "TripleDot;": "\u20db", - "Tscr;": "\U0001d4af", - "Tstrok;": "\u0166", - "Uacute": "\xda", - "Uacute;": "\xda", - "Uarr;": "\u219f", - "Uarrocir;": "\u2949", - "Ubrcy;": "\u040e", - "Ubreve;": "\u016c", - "Ucirc": "\xdb", - "Ucirc;": "\xdb", - "Ucy;": "\u0423", - "Udblac;": "\u0170", - "Ufr;": "\U0001d518", - "Ugrave": "\xd9", - "Ugrave;": "\xd9", - "Umacr;": "\u016a", - "UnderBar;": "_", - "UnderBrace;": "\u23df", - "UnderBracket;": "\u23b5", - "UnderParenthesis;": "\u23dd", - "Union;": "\u22c3", - "UnionPlus;": "\u228e", - "Uogon;": "\u0172", - "Uopf;": "\U0001d54c", - "UpArrow;": "\u2191", - "UpArrowBar;": "\u2912", - "UpArrowDownArrow;": "\u21c5", - "UpDownArrow;": "\u2195", - "UpEquilibrium;": "\u296e", - "UpTee;": "\u22a5", - "UpTeeArrow;": "\u21a5", - "Uparrow;": "\u21d1", - "Updownarrow;": "\u21d5", - "UpperLeftArrow;": "\u2196", - "UpperRightArrow;": "\u2197", - "Upsi;": "\u03d2", - "Upsilon;": "\u03a5", - "Uring;": "\u016e", - "Uscr;": "\U0001d4b0", - "Utilde;": "\u0168", - "Uuml": "\xdc", - "Uuml;": "\xdc", - "VDash;": "\u22ab", - "Vbar;": "\u2aeb", - "Vcy;": "\u0412", - "Vdash;": "\u22a9", - "Vdashl;": "\u2ae6", - "Vee;": "\u22c1", - "Verbar;": "\u2016", - "Vert;": "\u2016", - "VerticalBar;": "\u2223", - "VerticalLine;": "|", - "VerticalSeparator;": "\u2758", - "VerticalTilde;": "\u2240", - "VeryThinSpace;": "\u200a", - "Vfr;": "\U0001d519", - "Vopf;": "\U0001d54d", - "Vscr;": "\U0001d4b1", - "Vvdash;": "\u22aa", - "Wcirc;": "\u0174", - "Wedge;": "\u22c0", - "Wfr;": "\U0001d51a", - "Wopf;": "\U0001d54e", - "Wscr;": "\U0001d4b2", - "Xfr;": "\U0001d51b", - "Xi;": "\u039e", - "Xopf;": "\U0001d54f", - "Xscr;": "\U0001d4b3", - "YAcy;": "\u042f", - "YIcy;": "\u0407", - "YUcy;": "\u042e", - "Yacute": "\xdd", - "Yacute;": "\xdd", - "Ycirc;": "\u0176", - "Ycy;": "\u042b", - "Yfr;": "\U0001d51c", - "Yopf;": "\U0001d550", - "Yscr;": "\U0001d4b4", - "Yuml;": "\u0178", - "ZHcy;": "\u0416", - "Zacute;": "\u0179", - "Zcaron;": "\u017d", - "Zcy;": "\u0417", - "Zdot;": "\u017b", - "ZeroWidthSpace;": "\u200b", - "Zeta;": "\u0396", - "Zfr;": "\u2128", - "Zopf;": "\u2124", - "Zscr;": "\U0001d4b5", - "aacute": "\xe1", - "aacute;": "\xe1", - "abreve;": "\u0103", - "ac;": "\u223e", - "acE;": "\u223e\u0333", - "acd;": "\u223f", - "acirc": "\xe2", - "acirc;": "\xe2", - "acute": "\xb4", - "acute;": "\xb4", - "acy;": "\u0430", - "aelig": "\xe6", - "aelig;": "\xe6", - "af;": "\u2061", - "afr;": "\U0001d51e", - "agrave": "\xe0", - "agrave;": "\xe0", - "alefsym;": "\u2135", - "aleph;": "\u2135", - "alpha;": "\u03b1", - "amacr;": "\u0101", - "amalg;": "\u2a3f", - "amp": "&", - "amp;": "&", - "and;": "\u2227", - "andand;": "\u2a55", - "andd;": "\u2a5c", - "andslope;": "\u2a58", - "andv;": "\u2a5a", - "ang;": "\u2220", - "ange;": "\u29a4", - "angle;": "\u2220", - "angmsd;": "\u2221", - "angmsdaa;": "\u29a8", - "angmsdab;": "\u29a9", - "angmsdac;": "\u29aa", - "angmsdad;": "\u29ab", - "angmsdae;": "\u29ac", - "angmsdaf;": "\u29ad", - "angmsdag;": "\u29ae", - "angmsdah;": "\u29af", - "angrt;": "\u221f", - "angrtvb;": "\u22be", - "angrtvbd;": "\u299d", - "angsph;": "\u2222", - "angst;": "\xc5", - "angzarr;": "\u237c", - "aogon;": "\u0105", - "aopf;": "\U0001d552", - "ap;": "\u2248", - "apE;": "\u2a70", - "apacir;": "\u2a6f", - "ape;": "\u224a", - "apid;": "\u224b", - "apos;": "'", - "approx;": "\u2248", - "approxeq;": "\u224a", - "aring": "\xe5", - "aring;": "\xe5", - "ascr;": "\U0001d4b6", - "ast;": "*", - "asymp;": "\u2248", - "asympeq;": "\u224d", - "atilde": "\xe3", - "atilde;": "\xe3", - "auml": "\xe4", - "auml;": "\xe4", - "awconint;": "\u2233", - "awint;": "\u2a11", - "bNot;": "\u2aed", - "backcong;": "\u224c", - "backepsilon;": "\u03f6", - "backprime;": "\u2035", - "backsim;": "\u223d", - "backsimeq;": "\u22cd", - "barvee;": "\u22bd", - "barwed;": "\u2305", - "barwedge;": "\u2305", - "bbrk;": "\u23b5", - "bbrktbrk;": "\u23b6", - "bcong;": "\u224c", - "bcy;": "\u0431", - "bdquo;": "\u201e", - "becaus;": "\u2235", - "because;": "\u2235", - "bemptyv;": "\u29b0", - "bepsi;": "\u03f6", - "bernou;": "\u212c", - "beta;": "\u03b2", - "beth;": "\u2136", - "between;": "\u226c", - "bfr;": "\U0001d51f", - "bigcap;": "\u22c2", - "bigcirc;": "\u25ef", - "bigcup;": "\u22c3", - "bigodot;": "\u2a00", - "bigoplus;": "\u2a01", - "bigotimes;": "\u2a02", - "bigsqcup;": "\u2a06", - "bigstar;": "\u2605", - "bigtriangledown;": "\u25bd", - "bigtriangleup;": "\u25b3", - "biguplus;": "\u2a04", - "bigvee;": "\u22c1", - "bigwedge;": "\u22c0", - "bkarow;": "\u290d", - "blacklozenge;": "\u29eb", - "blacksquare;": "\u25aa", - "blacktriangle;": "\u25b4", - "blacktriangledown;": "\u25be", - "blacktriangleleft;": "\u25c2", - "blacktriangleright;": "\u25b8", - "blank;": "\u2423", - "blk12;": "\u2592", - "blk14;": "\u2591", - "blk34;": "\u2593", - "block;": "\u2588", - "bne;": "=\u20e5", - "bnequiv;": "\u2261\u20e5", - "bnot;": "\u2310", - "bopf;": "\U0001d553", - "bot;": "\u22a5", - "bottom;": "\u22a5", - "bowtie;": "\u22c8", - "boxDL;": "\u2557", - "boxDR;": "\u2554", - "boxDl;": "\u2556", - "boxDr;": "\u2553", - "boxH;": "\u2550", - "boxHD;": "\u2566", - "boxHU;": "\u2569", - "boxHd;": "\u2564", - "boxHu;": "\u2567", - "boxUL;": "\u255d", - "boxUR;": "\u255a", - "boxUl;": "\u255c", - "boxUr;": "\u2559", - "boxV;": "\u2551", - "boxVH;": "\u256c", - "boxVL;": "\u2563", - "boxVR;": "\u2560", - "boxVh;": "\u256b", - "boxVl;": "\u2562", - "boxVr;": "\u255f", - "boxbox;": "\u29c9", - "boxdL;": "\u2555", - "boxdR;": "\u2552", - "boxdl;": "\u2510", - "boxdr;": "\u250c", - "boxh;": "\u2500", - "boxhD;": "\u2565", - "boxhU;": "\u2568", - "boxhd;": "\u252c", - "boxhu;": "\u2534", - "boxminus;": "\u229f", - "boxplus;": "\u229e", - "boxtimes;": "\u22a0", - "boxuL;": "\u255b", - "boxuR;": "\u2558", - "boxul;": "\u2518", - "boxur;": "\u2514", - "boxv;": "\u2502", - "boxvH;": "\u256a", - "boxvL;": "\u2561", - "boxvR;": "\u255e", - "boxvh;": "\u253c", - "boxvl;": "\u2524", - "boxvr;": "\u251c", - "bprime;": "\u2035", - "breve;": "\u02d8", - "brvbar": "\xa6", - "brvbar;": "\xa6", - "bscr;": "\U0001d4b7", - "bsemi;": "\u204f", - "bsim;": "\u223d", - "bsime;": "\u22cd", - "bsol;": "\\", - "bsolb;": "\u29c5", - "bsolhsub;": "\u27c8", - "bull;": "\u2022", - "bullet;": "\u2022", - "bump;": "\u224e", - "bumpE;": "\u2aae", - "bumpe;": "\u224f", - "bumpeq;": "\u224f", - "cacute;": "\u0107", - "cap;": "\u2229", - "capand;": "\u2a44", - "capbrcup;": "\u2a49", - "capcap;": "\u2a4b", - "capcup;": "\u2a47", - "capdot;": "\u2a40", - "caps;": "\u2229\ufe00", - "caret;": "\u2041", - "caron;": "\u02c7", - "ccaps;": "\u2a4d", - "ccaron;": "\u010d", - "ccedil": "\xe7", - "ccedil;": "\xe7", - "ccirc;": "\u0109", - "ccups;": "\u2a4c", - "ccupssm;": "\u2a50", - "cdot;": "\u010b", - "cedil": "\xb8", - "cedil;": "\xb8", - "cemptyv;": "\u29b2", - "cent": "\xa2", - "cent;": "\xa2", - "centerdot;": "\xb7", - "cfr;": "\U0001d520", - "chcy;": "\u0447", - "check;": "\u2713", - "checkmark;": "\u2713", - "chi;": "\u03c7", - "cir;": "\u25cb", - "cirE;": "\u29c3", - "circ;": "\u02c6", - "circeq;": "\u2257", - "circlearrowleft;": "\u21ba", - "circlearrowright;": "\u21bb", - "circledR;": "\xae", - "circledS;": "\u24c8", - "circledast;": "\u229b", - "circledcirc;": "\u229a", - "circleddash;": "\u229d", - "cire;": "\u2257", - "cirfnint;": "\u2a10", - "cirmid;": "\u2aef", - "cirscir;": "\u29c2", - "clubs;": "\u2663", - "clubsuit;": "\u2663", - "colon;": ":", - "colone;": "\u2254", - "coloneq;": "\u2254", - "comma;": ",", - "commat;": "@", - "comp;": "\u2201", - "compfn;": "\u2218", - "complement;": "\u2201", - "complexes;": "\u2102", - "cong;": "\u2245", - "congdot;": "\u2a6d", - "conint;": "\u222e", - "copf;": "\U0001d554", - "coprod;": "\u2210", - "copy": "\xa9", - "copy;": "\xa9", - "copysr;": "\u2117", - "crarr;": "\u21b5", - "cross;": "\u2717", - "cscr;": "\U0001d4b8", - "csub;": "\u2acf", - "csube;": "\u2ad1", - "csup;": "\u2ad0", - "csupe;": "\u2ad2", - "ctdot;": "\u22ef", - "cudarrl;": "\u2938", - "cudarrr;": "\u2935", - "cuepr;": "\u22de", - "cuesc;": "\u22df", - "cularr;": "\u21b6", - "cularrp;": "\u293d", - "cup;": "\u222a", - "cupbrcap;": "\u2a48", - "cupcap;": "\u2a46", - "cupcup;": "\u2a4a", - "cupdot;": "\u228d", - "cupor;": "\u2a45", - "cups;": "\u222a\ufe00", - "curarr;": "\u21b7", - "curarrm;": "\u293c", - "curlyeqprec;": "\u22de", - "curlyeqsucc;": "\u22df", - "curlyvee;": "\u22ce", - "curlywedge;": "\u22cf", - "curren": "\xa4", - "curren;": "\xa4", - "curvearrowleft;": "\u21b6", - "curvearrowright;": "\u21b7", - "cuvee;": "\u22ce", - "cuwed;": "\u22cf", - "cwconint;": "\u2232", - "cwint;": "\u2231", - "cylcty;": "\u232d", - "dArr;": "\u21d3", - "dHar;": "\u2965", - "dagger;": "\u2020", - "daleth;": "\u2138", - "darr;": "\u2193", - "dash;": "\u2010", - "dashv;": "\u22a3", - "dbkarow;": "\u290f", - "dblac;": "\u02dd", - "dcaron;": "\u010f", - "dcy;": "\u0434", - "dd;": "\u2146", - "ddagger;": "\u2021", - "ddarr;": "\u21ca", - "ddotseq;": "\u2a77", - "deg": "\xb0", - "deg;": "\xb0", - "delta;": "\u03b4", - "demptyv;": "\u29b1", - "dfisht;": "\u297f", - "dfr;": "\U0001d521", - "dharl;": "\u21c3", - "dharr;": "\u21c2", - "diam;": "\u22c4", - "diamond;": "\u22c4", - "diamondsuit;": "\u2666", - "diams;": "\u2666", - "die;": "\xa8", - "digamma;": "\u03dd", - "disin;": "\u22f2", - "div;": "\xf7", - "divide": "\xf7", - "divide;": "\xf7", - "divideontimes;": "\u22c7", - "divonx;": "\u22c7", - "djcy;": "\u0452", - "dlcorn;": "\u231e", - "dlcrop;": "\u230d", - "dollar;": "$", - "dopf;": "\U0001d555", - "dot;": "\u02d9", - "doteq;": "\u2250", - "doteqdot;": "\u2251", - "dotminus;": "\u2238", - "dotplus;": "\u2214", - "dotsquare;": "\u22a1", - "doublebarwedge;": "\u2306", - "downarrow;": "\u2193", - "downdownarrows;": "\u21ca", - "downharpoonleft;": "\u21c3", - "downharpoonright;": "\u21c2", - "drbkarow;": "\u2910", - "drcorn;": "\u231f", - "drcrop;": "\u230c", - "dscr;": "\U0001d4b9", - "dscy;": "\u0455", - "dsol;": "\u29f6", - "dstrok;": "\u0111", - "dtdot;": "\u22f1", - "dtri;": "\u25bf", - "dtrif;": "\u25be", - "duarr;": "\u21f5", - "duhar;": "\u296f", - "dwangle;": "\u29a6", - "dzcy;": "\u045f", - "dzigrarr;": "\u27ff", - "eDDot;": "\u2a77", - "eDot;": "\u2251", - "eacute": "\xe9", - "eacute;": "\xe9", - "easter;": "\u2a6e", - "ecaron;": "\u011b", - "ecir;": "\u2256", - "ecirc": "\xea", - "ecirc;": "\xea", - "ecolon;": "\u2255", - "ecy;": "\u044d", - "edot;": "\u0117", - "ee;": "\u2147", - "efDot;": "\u2252", - "efr;": "\U0001d522", - "eg;": "\u2a9a", - "egrave": "\xe8", - "egrave;": "\xe8", - "egs;": "\u2a96", - "egsdot;": "\u2a98", - "el;": "\u2a99", - "elinters;": "\u23e7", - "ell;": "\u2113", - "els;": "\u2a95", - "elsdot;": "\u2a97", - "emacr;": "\u0113", - "empty;": "\u2205", - "emptyset;": "\u2205", - "emptyv;": "\u2205", - "emsp13;": "\u2004", - "emsp14;": "\u2005", - "emsp;": "\u2003", - "eng;": "\u014b", - "ensp;": "\u2002", - "eogon;": "\u0119", - "eopf;": "\U0001d556", - "epar;": "\u22d5", - "eparsl;": "\u29e3", - "eplus;": "\u2a71", - "epsi;": "\u03b5", - "epsilon;": "\u03b5", - "epsiv;": "\u03f5", - "eqcirc;": "\u2256", - "eqcolon;": "\u2255", - "eqsim;": "\u2242", - "eqslantgtr;": "\u2a96", - "eqslantless;": "\u2a95", - "equals;": "=", - "equest;": "\u225f", - "equiv;": "\u2261", - "equivDD;": "\u2a78", - "eqvparsl;": "\u29e5", - "erDot;": "\u2253", - "erarr;": "\u2971", - "escr;": "\u212f", - "esdot;": "\u2250", - "esim;": "\u2242", - "eta;": "\u03b7", - "eth": "\xf0", - "eth;": "\xf0", - "euml": "\xeb", - "euml;": "\xeb", - "euro;": "\u20ac", - "excl;": "!", - "exist;": "\u2203", - "expectation;": "\u2130", - "exponentiale;": "\u2147", - "fallingdotseq;": "\u2252", - "fcy;": "\u0444", - "female;": "\u2640", - "ffilig;": "\ufb03", - "fflig;": "\ufb00", - "ffllig;": "\ufb04", - "ffr;": "\U0001d523", - "filig;": "\ufb01", - "fjlig;": "fj", - "flat;": "\u266d", - "fllig;": "\ufb02", - "fltns;": "\u25b1", - "fnof;": "\u0192", - "fopf;": "\U0001d557", - "forall;": "\u2200", - "fork;": "\u22d4", - "forkv;": "\u2ad9", - "fpartint;": "\u2a0d", - "frac12": "\xbd", - "frac12;": "\xbd", - "frac13;": "\u2153", - "frac14": "\xbc", - "frac14;": "\xbc", - "frac15;": "\u2155", - "frac16;": "\u2159", - "frac18;": "\u215b", - "frac23;": "\u2154", - "frac25;": "\u2156", - "frac34": "\xbe", - "frac34;": "\xbe", - "frac35;": "\u2157", - "frac38;": "\u215c", - "frac45;": "\u2158", - "frac56;": "\u215a", - "frac58;": "\u215d", - "frac78;": "\u215e", - "frasl;": "\u2044", - "frown;": "\u2322", - "fscr;": "\U0001d4bb", - "gE;": "\u2267", - "gEl;": "\u2a8c", - "gacute;": "\u01f5", - "gamma;": "\u03b3", - "gammad;": "\u03dd", - "gap;": "\u2a86", - "gbreve;": "\u011f", - "gcirc;": "\u011d", - "gcy;": "\u0433", - "gdot;": "\u0121", - "ge;": "\u2265", - "gel;": "\u22db", - "geq;": "\u2265", - "geqq;": "\u2267", - "geqslant;": "\u2a7e", - "ges;": "\u2a7e", - "gescc;": "\u2aa9", - "gesdot;": "\u2a80", - "gesdoto;": "\u2a82", - "gesdotol;": "\u2a84", - "gesl;": "\u22db\ufe00", - "gesles;": "\u2a94", - "gfr;": "\U0001d524", - "gg;": "\u226b", - "ggg;": "\u22d9", - "gimel;": "\u2137", - "gjcy;": "\u0453", - "gl;": "\u2277", - "glE;": "\u2a92", - "gla;": "\u2aa5", - "glj;": "\u2aa4", - "gnE;": "\u2269", - "gnap;": "\u2a8a", - "gnapprox;": "\u2a8a", - "gne;": "\u2a88", - "gneq;": "\u2a88", - "gneqq;": "\u2269", - "gnsim;": "\u22e7", - "gopf;": "\U0001d558", - "grave;": "`", - "gscr;": "\u210a", - "gsim;": "\u2273", - "gsime;": "\u2a8e", - "gsiml;": "\u2a90", - "gt": ">", - "gt;": ">", - "gtcc;": "\u2aa7", - "gtcir;": "\u2a7a", - "gtdot;": "\u22d7", - "gtlPar;": "\u2995", - "gtquest;": "\u2a7c", - "gtrapprox;": "\u2a86", - "gtrarr;": "\u2978", - "gtrdot;": "\u22d7", - "gtreqless;": "\u22db", - "gtreqqless;": "\u2a8c", - "gtrless;": "\u2277", - "gtrsim;": "\u2273", - "gvertneqq;": "\u2269\ufe00", - "gvnE;": "\u2269\ufe00", - "hArr;": "\u21d4", - "hairsp;": "\u200a", - "half;": "\xbd", - "hamilt;": "\u210b", - "hardcy;": "\u044a", - "harr;": "\u2194", - "harrcir;": "\u2948", - "harrw;": "\u21ad", - "hbar;": "\u210f", - "hcirc;": "\u0125", - "hearts;": "\u2665", - "heartsuit;": "\u2665", - "hellip;": "\u2026", - "hercon;": "\u22b9", - "hfr;": "\U0001d525", - "hksearow;": "\u2925", - "hkswarow;": "\u2926", - "hoarr;": "\u21ff", - "homtht;": "\u223b", - "hookleftarrow;": "\u21a9", - "hookrightarrow;": "\u21aa", - "hopf;": "\U0001d559", - "horbar;": "\u2015", - "hscr;": "\U0001d4bd", - "hslash;": "\u210f", - "hstrok;": "\u0127", - "hybull;": "\u2043", - "hyphen;": "\u2010", - "iacute": "\xed", - "iacute;": "\xed", - "ic;": "\u2063", - "icirc": "\xee", - "icirc;": "\xee", - "icy;": "\u0438", - "iecy;": "\u0435", - "iexcl": "\xa1", - "iexcl;": "\xa1", - "iff;": "\u21d4", - "ifr;": "\U0001d526", - "igrave": "\xec", - "igrave;": "\xec", - "ii;": "\u2148", - "iiiint;": "\u2a0c", - "iiint;": "\u222d", - "iinfin;": "\u29dc", - "iiota;": "\u2129", - "ijlig;": "\u0133", - "imacr;": "\u012b", - "image;": "\u2111", - "imagline;": "\u2110", - "imagpart;": "\u2111", - "imath;": "\u0131", - "imof;": "\u22b7", - "imped;": "\u01b5", - "in;": "\u2208", - "incare;": "\u2105", - "infin;": "\u221e", - "infintie;": "\u29dd", - "inodot;": "\u0131", - "int;": "\u222b", - "intcal;": "\u22ba", - "integers;": "\u2124", - "intercal;": "\u22ba", - "intlarhk;": "\u2a17", - "intprod;": "\u2a3c", - "iocy;": "\u0451", - "iogon;": "\u012f", - "iopf;": "\U0001d55a", - "iota;": "\u03b9", - "iprod;": "\u2a3c", - "iquest": "\xbf", - "iquest;": "\xbf", - "iscr;": "\U0001d4be", - "isin;": "\u2208", - "isinE;": "\u22f9", - "isindot;": "\u22f5", - "isins;": "\u22f4", - "isinsv;": "\u22f3", - "isinv;": "\u2208", - "it;": "\u2062", - "itilde;": "\u0129", - "iukcy;": "\u0456", - "iuml": "\xef", - "iuml;": "\xef", - "jcirc;": "\u0135", - "jcy;": "\u0439", - "jfr;": "\U0001d527", - "jmath;": "\u0237", - "jopf;": "\U0001d55b", - "jscr;": "\U0001d4bf", - "jsercy;": "\u0458", - "jukcy;": "\u0454", - "kappa;": "\u03ba", - "kappav;": "\u03f0", - "kcedil;": "\u0137", - "kcy;": "\u043a", - "kfr;": "\U0001d528", - "kgreen;": "\u0138", - "khcy;": "\u0445", - "kjcy;": "\u045c", - "kopf;": "\U0001d55c", - "kscr;": "\U0001d4c0", - "lAarr;": "\u21da", - "lArr;": "\u21d0", - "lAtail;": "\u291b", - "lBarr;": "\u290e", - "lE;": "\u2266", - "lEg;": "\u2a8b", - "lHar;": "\u2962", - "lacute;": "\u013a", - "laemptyv;": "\u29b4", - "lagran;": "\u2112", - "lambda;": "\u03bb", - "lang;": "\u27e8", - "langd;": "\u2991", - "langle;": "\u27e8", - "lap;": "\u2a85", - "laquo": "\xab", - "laquo;": "\xab", - "larr;": "\u2190", - "larrb;": "\u21e4", - "larrbfs;": "\u291f", - "larrfs;": "\u291d", - "larrhk;": "\u21a9", - "larrlp;": "\u21ab", - "larrpl;": "\u2939", - "larrsim;": "\u2973", - "larrtl;": "\u21a2", - "lat;": "\u2aab", - "latail;": "\u2919", - "late;": "\u2aad", - "lates;": "\u2aad\ufe00", - "lbarr;": "\u290c", - "lbbrk;": "\u2772", - "lbrace;": "{", - "lbrack;": "[", - "lbrke;": "\u298b", - "lbrksld;": "\u298f", - "lbrkslu;": "\u298d", - "lcaron;": "\u013e", - "lcedil;": "\u013c", - "lceil;": "\u2308", - "lcub;": "{", - "lcy;": "\u043b", - "ldca;": "\u2936", - "ldquo;": "\u201c", - "ldquor;": "\u201e", - "ldrdhar;": "\u2967", - "ldrushar;": "\u294b", - "ldsh;": "\u21b2", - "le;": "\u2264", - "leftarrow;": "\u2190", - "leftarrowtail;": "\u21a2", - "leftharpoondown;": "\u21bd", - "leftharpoonup;": "\u21bc", - "leftleftarrows;": "\u21c7", - "leftrightarrow;": "\u2194", - "leftrightarrows;": "\u21c6", - "leftrightharpoons;": "\u21cb", - "leftrightsquigarrow;": "\u21ad", - "leftthreetimes;": "\u22cb", - "leg;": "\u22da", - "leq;": "\u2264", - "leqq;": "\u2266", - "leqslant;": "\u2a7d", - "les;": "\u2a7d", - "lescc;": "\u2aa8", - "lesdot;": "\u2a7f", - "lesdoto;": "\u2a81", - "lesdotor;": "\u2a83", - "lesg;": "\u22da\ufe00", - "lesges;": "\u2a93", - "lessapprox;": "\u2a85", - "lessdot;": "\u22d6", - "lesseqgtr;": "\u22da", - "lesseqqgtr;": "\u2a8b", - "lessgtr;": "\u2276", - "lesssim;": "\u2272", - "lfisht;": "\u297c", - "lfloor;": "\u230a", - "lfr;": "\U0001d529", - "lg;": "\u2276", - "lgE;": "\u2a91", - "lhard;": "\u21bd", - "lharu;": "\u21bc", - "lharul;": "\u296a", - "lhblk;": "\u2584", - "ljcy;": "\u0459", - "ll;": "\u226a", - "llarr;": "\u21c7", - "llcorner;": "\u231e", - "llhard;": "\u296b", - "lltri;": "\u25fa", - "lmidot;": "\u0140", - "lmoust;": "\u23b0", - "lmoustache;": "\u23b0", - "lnE;": "\u2268", - "lnap;": "\u2a89", - "lnapprox;": "\u2a89", - "lne;": "\u2a87", - "lneq;": "\u2a87", - "lneqq;": "\u2268", - "lnsim;": "\u22e6", - "loang;": "\u27ec", - "loarr;": "\u21fd", - "lobrk;": "\u27e6", - "longleftarrow;": "\u27f5", - "longleftrightarrow;": "\u27f7", - "longmapsto;": "\u27fc", - "longrightarrow;": "\u27f6", - "looparrowleft;": "\u21ab", - "looparrowright;": "\u21ac", - "lopar;": "\u2985", - "lopf;": "\U0001d55d", - "loplus;": "\u2a2d", - "lotimes;": "\u2a34", - "lowast;": "\u2217", - "lowbar;": "_", - "loz;": "\u25ca", - "lozenge;": "\u25ca", - "lozf;": "\u29eb", - "lpar;": "(", - "lparlt;": "\u2993", - "lrarr;": "\u21c6", - "lrcorner;": "\u231f", - "lrhar;": "\u21cb", - "lrhard;": "\u296d", - "lrm;": "\u200e", - "lrtri;": "\u22bf", - "lsaquo;": "\u2039", - "lscr;": "\U0001d4c1", - "lsh;": "\u21b0", - "lsim;": "\u2272", - "lsime;": "\u2a8d", - "lsimg;": "\u2a8f", - "lsqb;": "[", - "lsquo;": "\u2018", - "lsquor;": "\u201a", - "lstrok;": "\u0142", - "lt": "<", - "lt;": "<", - "ltcc;": "\u2aa6", - "ltcir;": "\u2a79", - "ltdot;": "\u22d6", - "lthree;": "\u22cb", - "ltimes;": "\u22c9", - "ltlarr;": "\u2976", - "ltquest;": "\u2a7b", - "ltrPar;": "\u2996", - "ltri;": "\u25c3", - "ltrie;": "\u22b4", - "ltrif;": "\u25c2", - "lurdshar;": "\u294a", - "luruhar;": "\u2966", - "lvertneqq;": "\u2268\ufe00", - "lvnE;": "\u2268\ufe00", - "mDDot;": "\u223a", - "macr": "\xaf", - "macr;": "\xaf", - "male;": "\u2642", - "malt;": "\u2720", - "maltese;": "\u2720", - "map;": "\u21a6", - "mapsto;": "\u21a6", - "mapstodown;": "\u21a7", - "mapstoleft;": "\u21a4", - "mapstoup;": "\u21a5", - "marker;": "\u25ae", - "mcomma;": "\u2a29", - "mcy;": "\u043c", - "mdash;": "\u2014", - "measuredangle;": "\u2221", - "mfr;": "\U0001d52a", - "mho;": "\u2127", - "micro": "\xb5", - "micro;": "\xb5", - "mid;": "\u2223", - "midast;": "*", - "midcir;": "\u2af0", - "middot": "\xb7", - "middot;": "\xb7", - "minus;": "\u2212", - "minusb;": "\u229f", - "minusd;": "\u2238", - "minusdu;": "\u2a2a", - "mlcp;": "\u2adb", - "mldr;": "\u2026", - "mnplus;": "\u2213", - "models;": "\u22a7", - "mopf;": "\U0001d55e", - "mp;": "\u2213", - "mscr;": "\U0001d4c2", - "mstpos;": "\u223e", - "mu;": "\u03bc", - "multimap;": "\u22b8", - "mumap;": "\u22b8", - "nGg;": "\u22d9\u0338", - "nGt;": "\u226b\u20d2", - "nGtv;": "\u226b\u0338", - "nLeftarrow;": "\u21cd", - "nLeftrightarrow;": "\u21ce", - "nLl;": "\u22d8\u0338", - "nLt;": "\u226a\u20d2", - "nLtv;": "\u226a\u0338", - "nRightarrow;": "\u21cf", - "nVDash;": "\u22af", - "nVdash;": "\u22ae", - "nabla;": "\u2207", - "nacute;": "\u0144", - "nang;": "\u2220\u20d2", - "nap;": "\u2249", - "napE;": "\u2a70\u0338", - "napid;": "\u224b\u0338", - "napos;": "\u0149", - "napprox;": "\u2249", - "natur;": "\u266e", - "natural;": "\u266e", - "naturals;": "\u2115", - "nbsp": "\xa0", - "nbsp;": "\xa0", - "nbump;": "\u224e\u0338", - "nbumpe;": "\u224f\u0338", - "ncap;": "\u2a43", - "ncaron;": "\u0148", - "ncedil;": "\u0146", - "ncong;": "\u2247", - "ncongdot;": "\u2a6d\u0338", - "ncup;": "\u2a42", - "ncy;": "\u043d", - "ndash;": "\u2013", - "ne;": "\u2260", - "neArr;": "\u21d7", - "nearhk;": "\u2924", - "nearr;": "\u2197", - "nearrow;": "\u2197", - "nedot;": "\u2250\u0338", - "nequiv;": "\u2262", - "nesear;": "\u2928", - "nesim;": "\u2242\u0338", - "nexist;": "\u2204", - "nexists;": "\u2204", - "nfr;": "\U0001d52b", - "ngE;": "\u2267\u0338", - "nge;": "\u2271", - "ngeq;": "\u2271", - "ngeqq;": "\u2267\u0338", - "ngeqslant;": "\u2a7e\u0338", - "nges;": "\u2a7e\u0338", - "ngsim;": "\u2275", - "ngt;": "\u226f", - "ngtr;": "\u226f", - "nhArr;": "\u21ce", - "nharr;": "\u21ae", - "nhpar;": "\u2af2", - "ni;": "\u220b", - "nis;": "\u22fc", - "nisd;": "\u22fa", - "niv;": "\u220b", - "njcy;": "\u045a", - "nlArr;": "\u21cd", - "nlE;": "\u2266\u0338", - "nlarr;": "\u219a", - "nldr;": "\u2025", - "nle;": "\u2270", - "nleftarrow;": "\u219a", - "nleftrightarrow;": "\u21ae", - "nleq;": "\u2270", - "nleqq;": "\u2266\u0338", - "nleqslant;": "\u2a7d\u0338", - "nles;": "\u2a7d\u0338", - "nless;": "\u226e", - "nlsim;": "\u2274", - "nlt;": "\u226e", - "nltri;": "\u22ea", - "nltrie;": "\u22ec", - "nmid;": "\u2224", - "nopf;": "\U0001d55f", - "not": "\xac", - "not;": "\xac", - "notin;": "\u2209", - "notinE;": "\u22f9\u0338", - "notindot;": "\u22f5\u0338", - "notinva;": "\u2209", - "notinvb;": "\u22f7", - "notinvc;": "\u22f6", - "notni;": "\u220c", - "notniva;": "\u220c", - "notnivb;": "\u22fe", - "notnivc;": "\u22fd", - "npar;": "\u2226", - "nparallel;": "\u2226", - "nparsl;": "\u2afd\u20e5", - "npart;": "\u2202\u0338", - "npolint;": "\u2a14", - "npr;": "\u2280", - "nprcue;": "\u22e0", - "npre;": "\u2aaf\u0338", - "nprec;": "\u2280", - "npreceq;": "\u2aaf\u0338", - "nrArr;": "\u21cf", - "nrarr;": "\u219b", - "nrarrc;": "\u2933\u0338", - "nrarrw;": "\u219d\u0338", - "nrightarrow;": "\u219b", - "nrtri;": "\u22eb", - "nrtrie;": "\u22ed", - "nsc;": "\u2281", - "nsccue;": "\u22e1", - "nsce;": "\u2ab0\u0338", - "nscr;": "\U0001d4c3", - "nshortmid;": "\u2224", - "nshortparallel;": "\u2226", - "nsim;": "\u2241", - "nsime;": "\u2244", - "nsimeq;": "\u2244", - "nsmid;": "\u2224", - "nspar;": "\u2226", - "nsqsube;": "\u22e2", - "nsqsupe;": "\u22e3", - "nsub;": "\u2284", - "nsubE;": "\u2ac5\u0338", - "nsube;": "\u2288", - "nsubset;": "\u2282\u20d2", - "nsubseteq;": "\u2288", - "nsubseteqq;": "\u2ac5\u0338", - "nsucc;": "\u2281", - "nsucceq;": "\u2ab0\u0338", - "nsup;": "\u2285", - "nsupE;": "\u2ac6\u0338", - "nsupe;": "\u2289", - "nsupset;": "\u2283\u20d2", - "nsupseteq;": "\u2289", - "nsupseteqq;": "\u2ac6\u0338", - "ntgl;": "\u2279", - "ntilde": "\xf1", - "ntilde;": "\xf1", - "ntlg;": "\u2278", - "ntriangleleft;": "\u22ea", - "ntrianglelefteq;": "\u22ec", - "ntriangleright;": "\u22eb", - "ntrianglerighteq;": "\u22ed", - "nu;": "\u03bd", - "num;": "#", - "numero;": "\u2116", - "numsp;": "\u2007", - "nvDash;": "\u22ad", - "nvHarr;": "\u2904", - "nvap;": "\u224d\u20d2", - "nvdash;": "\u22ac", - "nvge;": "\u2265\u20d2", - "nvgt;": ">\u20d2", - "nvinfin;": "\u29de", - "nvlArr;": "\u2902", - "nvle;": "\u2264\u20d2", - "nvlt;": "<\u20d2", - "nvltrie;": "\u22b4\u20d2", - "nvrArr;": "\u2903", - "nvrtrie;": "\u22b5\u20d2", - "nvsim;": "\u223c\u20d2", - "nwArr;": "\u21d6", - "nwarhk;": "\u2923", - "nwarr;": "\u2196", - "nwarrow;": "\u2196", - "nwnear;": "\u2927", - "oS;": "\u24c8", - "oacute": "\xf3", - "oacute;": "\xf3", - "oast;": "\u229b", - "ocir;": "\u229a", - "ocirc": "\xf4", - "ocirc;": "\xf4", - "ocy;": "\u043e", - "odash;": "\u229d", - "odblac;": "\u0151", - "odiv;": "\u2a38", - "odot;": "\u2299", - "odsold;": "\u29bc", - "oelig;": "\u0153", - "ofcir;": "\u29bf", - "ofr;": "\U0001d52c", - "ogon;": "\u02db", - "ograve": "\xf2", - "ograve;": "\xf2", - "ogt;": "\u29c1", - "ohbar;": "\u29b5", - "ohm;": "\u03a9", - "oint;": "\u222e", - "olarr;": "\u21ba", - "olcir;": "\u29be", - "olcross;": "\u29bb", - "oline;": "\u203e", - "olt;": "\u29c0", - "omacr;": "\u014d", - "omega;": "\u03c9", - "omicron;": "\u03bf", - "omid;": "\u29b6", - "ominus;": "\u2296", - "oopf;": "\U0001d560", - "opar;": "\u29b7", - "operp;": "\u29b9", - "oplus;": "\u2295", - "or;": "\u2228", - "orarr;": "\u21bb", - "ord;": "\u2a5d", - "order;": "\u2134", - "orderof;": "\u2134", - "ordf": "\xaa", - "ordf;": "\xaa", - "ordm": "\xba", - "ordm;": "\xba", - "origof;": "\u22b6", - "oror;": "\u2a56", - "orslope;": "\u2a57", - "orv;": "\u2a5b", - "oscr;": "\u2134", - "oslash": "\xf8", - "oslash;": "\xf8", - "osol;": "\u2298", - "otilde": "\xf5", - "otilde;": "\xf5", - "otimes;": "\u2297", - "otimesas;": "\u2a36", - "ouml": "\xf6", - "ouml;": "\xf6", - "ovbar;": "\u233d", - "par;": "\u2225", - "para": "\xb6", - "para;": "\xb6", - "parallel;": "\u2225", - "parsim;": "\u2af3", - "parsl;": "\u2afd", - "part;": "\u2202", - "pcy;": "\u043f", - "percnt;": "%", - "period;": ".", - "permil;": "\u2030", - "perp;": "\u22a5", - "pertenk;": "\u2031", - "pfr;": "\U0001d52d", - "phi;": "\u03c6", - "phiv;": "\u03d5", - "phmmat;": "\u2133", - "phone;": "\u260e", - "pi;": "\u03c0", - "pitchfork;": "\u22d4", - "piv;": "\u03d6", - "planck;": "\u210f", - "planckh;": "\u210e", - "plankv;": "\u210f", - "plus;": "+", - "plusacir;": "\u2a23", - "plusb;": "\u229e", - "pluscir;": "\u2a22", - "plusdo;": "\u2214", - "plusdu;": "\u2a25", - "pluse;": "\u2a72", - "plusmn": "\xb1", - "plusmn;": "\xb1", - "plussim;": "\u2a26", - "plustwo;": "\u2a27", - "pm;": "\xb1", - "pointint;": "\u2a15", - "popf;": "\U0001d561", - "pound": "\xa3", - "pound;": "\xa3", - "pr;": "\u227a", - "prE;": "\u2ab3", - "prap;": "\u2ab7", - "prcue;": "\u227c", - "pre;": "\u2aaf", - "prec;": "\u227a", - "precapprox;": "\u2ab7", - "preccurlyeq;": "\u227c", - "preceq;": "\u2aaf", - "precnapprox;": "\u2ab9", - "precneqq;": "\u2ab5", - "precnsim;": "\u22e8", - "precsim;": "\u227e", - "prime;": "\u2032", - "primes;": "\u2119", - "prnE;": "\u2ab5", - "prnap;": "\u2ab9", - "prnsim;": "\u22e8", - "prod;": "\u220f", - "profalar;": "\u232e", - "profline;": "\u2312", - "profsurf;": "\u2313", - "prop;": "\u221d", - "propto;": "\u221d", - "prsim;": "\u227e", - "prurel;": "\u22b0", - "pscr;": "\U0001d4c5", - "psi;": "\u03c8", - "puncsp;": "\u2008", - "qfr;": "\U0001d52e", - "qint;": "\u2a0c", - "qopf;": "\U0001d562", - "qprime;": "\u2057", - "qscr;": "\U0001d4c6", - "quaternions;": "\u210d", - "quatint;": "\u2a16", - "quest;": "?", - "questeq;": "\u225f", - "quot": "\"", - "quot;": "\"", - "rAarr;": "\u21db", - "rArr;": "\u21d2", - "rAtail;": "\u291c", - "rBarr;": "\u290f", - "rHar;": "\u2964", - "race;": "\u223d\u0331", - "racute;": "\u0155", - "radic;": "\u221a", - "raemptyv;": "\u29b3", - "rang;": "\u27e9", - "rangd;": "\u2992", - "range;": "\u29a5", - "rangle;": "\u27e9", - "raquo": "\xbb", - "raquo;": "\xbb", - "rarr;": "\u2192", - "rarrap;": "\u2975", - "rarrb;": "\u21e5", - "rarrbfs;": "\u2920", - "rarrc;": "\u2933", - "rarrfs;": "\u291e", - "rarrhk;": "\u21aa", - "rarrlp;": "\u21ac", - "rarrpl;": "\u2945", - "rarrsim;": "\u2974", - "rarrtl;": "\u21a3", - "rarrw;": "\u219d", - "ratail;": "\u291a", - "ratio;": "\u2236", - "rationals;": "\u211a", - "rbarr;": "\u290d", - "rbbrk;": "\u2773", - "rbrace;": "}", - "rbrack;": "]", - "rbrke;": "\u298c", - "rbrksld;": "\u298e", - "rbrkslu;": "\u2990", - "rcaron;": "\u0159", - "rcedil;": "\u0157", - "rceil;": "\u2309", - "rcub;": "}", - "rcy;": "\u0440", - "rdca;": "\u2937", - "rdldhar;": "\u2969", - "rdquo;": "\u201d", - "rdquor;": "\u201d", - "rdsh;": "\u21b3", - "real;": "\u211c", - "realine;": "\u211b", - "realpart;": "\u211c", - "reals;": "\u211d", - "rect;": "\u25ad", - "reg": "\xae", - "reg;": "\xae", - "rfisht;": "\u297d", - "rfloor;": "\u230b", - "rfr;": "\U0001d52f", - "rhard;": "\u21c1", - "rharu;": "\u21c0", - "rharul;": "\u296c", - "rho;": "\u03c1", - "rhov;": "\u03f1", - "rightarrow;": "\u2192", - "rightarrowtail;": "\u21a3", - "rightharpoondown;": "\u21c1", - "rightharpoonup;": "\u21c0", - "rightleftarrows;": "\u21c4", - "rightleftharpoons;": "\u21cc", - "rightrightarrows;": "\u21c9", - "rightsquigarrow;": "\u219d", - "rightthreetimes;": "\u22cc", - "ring;": "\u02da", - "risingdotseq;": "\u2253", - "rlarr;": "\u21c4", - "rlhar;": "\u21cc", - "rlm;": "\u200f", - "rmoust;": "\u23b1", - "rmoustache;": "\u23b1", - "rnmid;": "\u2aee", - "roang;": "\u27ed", - "roarr;": "\u21fe", - "robrk;": "\u27e7", - "ropar;": "\u2986", - "ropf;": "\U0001d563", - "roplus;": "\u2a2e", - "rotimes;": "\u2a35", - "rpar;": ")", - "rpargt;": "\u2994", - "rppolint;": "\u2a12", - "rrarr;": "\u21c9", - "rsaquo;": "\u203a", - "rscr;": "\U0001d4c7", - "rsh;": "\u21b1", - "rsqb;": "]", - "rsquo;": "\u2019", - "rsquor;": "\u2019", - "rthree;": "\u22cc", - "rtimes;": "\u22ca", - "rtri;": "\u25b9", - "rtrie;": "\u22b5", - "rtrif;": "\u25b8", - "rtriltri;": "\u29ce", - "ruluhar;": "\u2968", - "rx;": "\u211e", - "sacute;": "\u015b", - "sbquo;": "\u201a", - "sc;": "\u227b", - "scE;": "\u2ab4", - "scap;": "\u2ab8", - "scaron;": "\u0161", - "sccue;": "\u227d", - "sce;": "\u2ab0", - "scedil;": "\u015f", - "scirc;": "\u015d", - "scnE;": "\u2ab6", - "scnap;": "\u2aba", - "scnsim;": "\u22e9", - "scpolint;": "\u2a13", - "scsim;": "\u227f", - "scy;": "\u0441", - "sdot;": "\u22c5", - "sdotb;": "\u22a1", - "sdote;": "\u2a66", - "seArr;": "\u21d8", - "searhk;": "\u2925", - "searr;": "\u2198", - "searrow;": "\u2198", - "sect": "\xa7", - "sect;": "\xa7", - "semi;": ";", - "seswar;": "\u2929", - "setminus;": "\u2216", - "setmn;": "\u2216", - "sext;": "\u2736", - "sfr;": "\U0001d530", - "sfrown;": "\u2322", - "sharp;": "\u266f", - "shchcy;": "\u0449", - "shcy;": "\u0448", - "shortmid;": "\u2223", - "shortparallel;": "\u2225", - "shy": "\xad", - "shy;": "\xad", - "sigma;": "\u03c3", - "sigmaf;": "\u03c2", - "sigmav;": "\u03c2", - "sim;": "\u223c", - "simdot;": "\u2a6a", - "sime;": "\u2243", - "simeq;": "\u2243", - "simg;": "\u2a9e", - "simgE;": "\u2aa0", - "siml;": "\u2a9d", - "simlE;": "\u2a9f", - "simne;": "\u2246", - "simplus;": "\u2a24", - "simrarr;": "\u2972", - "slarr;": "\u2190", - "smallsetminus;": "\u2216", - "smashp;": "\u2a33", - "smeparsl;": "\u29e4", - "smid;": "\u2223", - "smile;": "\u2323", - "smt;": "\u2aaa", - "smte;": "\u2aac", - "smtes;": "\u2aac\ufe00", - "softcy;": "\u044c", - "sol;": "/", - "solb;": "\u29c4", - "solbar;": "\u233f", - "sopf;": "\U0001d564", - "spades;": "\u2660", - "spadesuit;": "\u2660", - "spar;": "\u2225", - "sqcap;": "\u2293", - "sqcaps;": "\u2293\ufe00", - "sqcup;": "\u2294", - "sqcups;": "\u2294\ufe00", - "sqsub;": "\u228f", - "sqsube;": "\u2291", - "sqsubset;": "\u228f", - "sqsubseteq;": "\u2291", - "sqsup;": "\u2290", - "sqsupe;": "\u2292", - "sqsupset;": "\u2290", - "sqsupseteq;": "\u2292", - "squ;": "\u25a1", - "square;": "\u25a1", - "squarf;": "\u25aa", - "squf;": "\u25aa", - "srarr;": "\u2192", - "sscr;": "\U0001d4c8", - "ssetmn;": "\u2216", - "ssmile;": "\u2323", - "sstarf;": "\u22c6", - "star;": "\u2606", - "starf;": "\u2605", - "straightepsilon;": "\u03f5", - "straightphi;": "\u03d5", - "strns;": "\xaf", - "sub;": "\u2282", - "subE;": "\u2ac5", - "subdot;": "\u2abd", - "sube;": "\u2286", - "subedot;": "\u2ac3", - "submult;": "\u2ac1", - "subnE;": "\u2acb", - "subne;": "\u228a", - "subplus;": "\u2abf", - "subrarr;": "\u2979", - "subset;": "\u2282", - "subseteq;": "\u2286", - "subseteqq;": "\u2ac5", - "subsetneq;": "\u228a", - "subsetneqq;": "\u2acb", - "subsim;": "\u2ac7", - "subsub;": "\u2ad5", - "subsup;": "\u2ad3", - "succ;": "\u227b", - "succapprox;": "\u2ab8", - "succcurlyeq;": "\u227d", - "succeq;": "\u2ab0", - "succnapprox;": "\u2aba", - "succneqq;": "\u2ab6", - "succnsim;": "\u22e9", - "succsim;": "\u227f", - "sum;": "\u2211", - "sung;": "\u266a", - "sup1": "\xb9", - "sup1;": "\xb9", - "sup2": "\xb2", - "sup2;": "\xb2", - "sup3": "\xb3", - "sup3;": "\xb3", - "sup;": "\u2283", - "supE;": "\u2ac6", - "supdot;": "\u2abe", - "supdsub;": "\u2ad8", - "supe;": "\u2287", - "supedot;": "\u2ac4", - "suphsol;": "\u27c9", - "suphsub;": "\u2ad7", - "suplarr;": "\u297b", - "supmult;": "\u2ac2", - "supnE;": "\u2acc", - "supne;": "\u228b", - "supplus;": "\u2ac0", - "supset;": "\u2283", - "supseteq;": "\u2287", - "supseteqq;": "\u2ac6", - "supsetneq;": "\u228b", - "supsetneqq;": "\u2acc", - "supsim;": "\u2ac8", - "supsub;": "\u2ad4", - "supsup;": "\u2ad6", - "swArr;": "\u21d9", - "swarhk;": "\u2926", - "swarr;": "\u2199", - "swarrow;": "\u2199", - "swnwar;": "\u292a", - "szlig": "\xdf", - "szlig;": "\xdf", - "target;": "\u2316", - "tau;": "\u03c4", - "tbrk;": "\u23b4", - "tcaron;": "\u0165", - "tcedil;": "\u0163", - "tcy;": "\u0442", - "tdot;": "\u20db", - "telrec;": "\u2315", - "tfr;": "\U0001d531", - "there4;": "\u2234", - "therefore;": "\u2234", - "theta;": "\u03b8", - "thetasym;": "\u03d1", - "thetav;": "\u03d1", - "thickapprox;": "\u2248", - "thicksim;": "\u223c", - "thinsp;": "\u2009", - "thkap;": "\u2248", - "thksim;": "\u223c", - "thorn": "\xfe", - "thorn;": "\xfe", - "tilde;": "\u02dc", - "times": "\xd7", - "times;": "\xd7", - "timesb;": "\u22a0", - "timesbar;": "\u2a31", - "timesd;": "\u2a30", - "tint;": "\u222d", - "toea;": "\u2928", - "top;": "\u22a4", - "topbot;": "\u2336", - "topcir;": "\u2af1", - "topf;": "\U0001d565", - "topfork;": "\u2ada", - "tosa;": "\u2929", - "tprime;": "\u2034", - "trade;": "\u2122", - "triangle;": "\u25b5", - "triangledown;": "\u25bf", - "triangleleft;": "\u25c3", - "trianglelefteq;": "\u22b4", - "triangleq;": "\u225c", - "triangleright;": "\u25b9", - "trianglerighteq;": "\u22b5", - "tridot;": "\u25ec", - "trie;": "\u225c", - "triminus;": "\u2a3a", - "triplus;": "\u2a39", - "trisb;": "\u29cd", - "tritime;": "\u2a3b", - "trpezium;": "\u23e2", - "tscr;": "\U0001d4c9", - "tscy;": "\u0446", - "tshcy;": "\u045b", - "tstrok;": "\u0167", - "twixt;": "\u226c", - "twoheadleftarrow;": "\u219e", - "twoheadrightarrow;": "\u21a0", - "uArr;": "\u21d1", - "uHar;": "\u2963", - "uacute": "\xfa", - "uacute;": "\xfa", - "uarr;": "\u2191", - "ubrcy;": "\u045e", - "ubreve;": "\u016d", - "ucirc": "\xfb", - "ucirc;": "\xfb", - "ucy;": "\u0443", - "udarr;": "\u21c5", - "udblac;": "\u0171", - "udhar;": "\u296e", - "ufisht;": "\u297e", - "ufr;": "\U0001d532", - "ugrave": "\xf9", - "ugrave;": "\xf9", - "uharl;": "\u21bf", - "uharr;": "\u21be", - "uhblk;": "\u2580", - "ulcorn;": "\u231c", - "ulcorner;": "\u231c", - "ulcrop;": "\u230f", - "ultri;": "\u25f8", - "umacr;": "\u016b", - "uml": "\xa8", - "uml;": "\xa8", - "uogon;": "\u0173", - "uopf;": "\U0001d566", - "uparrow;": "\u2191", - "updownarrow;": "\u2195", - "upharpoonleft;": "\u21bf", - "upharpoonright;": "\u21be", - "uplus;": "\u228e", - "upsi;": "\u03c5", - "upsih;": "\u03d2", - "upsilon;": "\u03c5", - "upuparrows;": "\u21c8", - "urcorn;": "\u231d", - "urcorner;": "\u231d", - "urcrop;": "\u230e", - "uring;": "\u016f", - "urtri;": "\u25f9", - "uscr;": "\U0001d4ca", - "utdot;": "\u22f0", - "utilde;": "\u0169", - "utri;": "\u25b5", - "utrif;": "\u25b4", - "uuarr;": "\u21c8", - "uuml": "\xfc", - "uuml;": "\xfc", - "uwangle;": "\u29a7", - "vArr;": "\u21d5", - "vBar;": "\u2ae8", - "vBarv;": "\u2ae9", - "vDash;": "\u22a8", - "vangrt;": "\u299c", - "varepsilon;": "\u03f5", - "varkappa;": "\u03f0", - "varnothing;": "\u2205", - "varphi;": "\u03d5", - "varpi;": "\u03d6", - "varpropto;": "\u221d", - "varr;": "\u2195", - "varrho;": "\u03f1", - "varsigma;": "\u03c2", - "varsubsetneq;": "\u228a\ufe00", - "varsubsetneqq;": "\u2acb\ufe00", - "varsupsetneq;": "\u228b\ufe00", - "varsupsetneqq;": "\u2acc\ufe00", - "vartheta;": "\u03d1", - "vartriangleleft;": "\u22b2", - "vartriangleright;": "\u22b3", - "vcy;": "\u0432", - "vdash;": "\u22a2", - "vee;": "\u2228", - "veebar;": "\u22bb", - "veeeq;": "\u225a", - "vellip;": "\u22ee", - "verbar;": "|", - "vert;": "|", - "vfr;": "\U0001d533", - "vltri;": "\u22b2", - "vnsub;": "\u2282\u20d2", - "vnsup;": "\u2283\u20d2", - "vopf;": "\U0001d567", - "vprop;": "\u221d", - "vrtri;": "\u22b3", - "vscr;": "\U0001d4cb", - "vsubnE;": "\u2acb\ufe00", - "vsubne;": "\u228a\ufe00", - "vsupnE;": "\u2acc\ufe00", - "vsupne;": "\u228b\ufe00", - "vzigzag;": "\u299a", - "wcirc;": "\u0175", - "wedbar;": "\u2a5f", - "wedge;": "\u2227", - "wedgeq;": "\u2259", - "weierp;": "\u2118", - "wfr;": "\U0001d534", - "wopf;": "\U0001d568", - "wp;": "\u2118", - "wr;": "\u2240", - "wreath;": "\u2240", - "wscr;": "\U0001d4cc", - "xcap;": "\u22c2", - "xcirc;": "\u25ef", - "xcup;": "\u22c3", - "xdtri;": "\u25bd", - "xfr;": "\U0001d535", - "xhArr;": "\u27fa", - "xharr;": "\u27f7", - "xi;": "\u03be", - "xlArr;": "\u27f8", - "xlarr;": "\u27f5", - "xmap;": "\u27fc", - "xnis;": "\u22fb", - "xodot;": "\u2a00", - "xopf;": "\U0001d569", - "xoplus;": "\u2a01", - "xotime;": "\u2a02", - "xrArr;": "\u27f9", - "xrarr;": "\u27f6", - "xscr;": "\U0001d4cd", - "xsqcup;": "\u2a06", - "xuplus;": "\u2a04", - "xutri;": "\u25b3", - "xvee;": "\u22c1", - "xwedge;": "\u22c0", - "yacute": "\xfd", - "yacute;": "\xfd", - "yacy;": "\u044f", - "ycirc;": "\u0177", - "ycy;": "\u044b", - "yen": "\xa5", - "yen;": "\xa5", - "yfr;": "\U0001d536", - "yicy;": "\u0457", - "yopf;": "\U0001d56a", - "yscr;": "\U0001d4ce", - "yucy;": "\u044e", - "yuml": "\xff", - "yuml;": "\xff", - "zacute;": "\u017a", - "zcaron;": "\u017e", - "zcy;": "\u0437", - "zdot;": "\u017c", - "zeetrf;": "\u2128", - "zeta;": "\u03b6", - "zfr;": "\U0001d537", - "zhcy;": "\u0436", - "zigrarr;": "\u21dd", - "zopf;": "\U0001d56b", - "zscr;": "\U0001d4cf", - "zwj;": "\u200d", - "zwnj;": "\u200c", -} - -replacementCharacters = { - 0x0: "\uFFFD", - 0x0d: "\u000D", - 0x80: "\u20AC", - 0x81: "\u0081", - 0x81: "\u0081", - 0x82: "\u201A", - 0x83: "\u0192", - 0x84: "\u201E", - 0x85: "\u2026", - 0x86: "\u2020", - 0x87: "\u2021", - 0x88: "\u02C6", - 0x89: "\u2030", - 0x8A: "\u0160", - 0x8B: "\u2039", - 0x8C: "\u0152", - 0x8D: "\u008D", - 0x8E: "\u017D", - 0x8F: "\u008F", - 0x90: "\u0090", - 0x91: "\u2018", - 0x92: "\u2019", - 0x93: "\u201C", - 0x94: "\u201D", - 0x95: "\u2022", - 0x96: "\u2013", - 0x97: "\u2014", - 0x98: "\u02DC", - 0x99: "\u2122", - 0x9A: "\u0161", - 0x9B: "\u203A", - 0x9C: "\u0153", - 0x9D: "\u009D", - 0x9E: "\u017E", - 0x9F: "\u0178", -} - -encodings = { - '437': 'cp437', - '850': 'cp850', - '852': 'cp852', - '855': 'cp855', - '857': 'cp857', - '860': 'cp860', - '861': 'cp861', - '862': 'cp862', - '863': 'cp863', - '865': 'cp865', - '866': 'cp866', - '869': 'cp869', - 'ansix341968': 'ascii', - 'ansix341986': 'ascii', - 'arabic': 'iso8859-6', - 'ascii': 'ascii', - 'asmo708': 'iso8859-6', - 'big5': 'big5', - 'big5hkscs': 'big5hkscs', - 'chinese': 'gbk', - 'cp037': 'cp037', - 'cp1026': 'cp1026', - 'cp154': 'ptcp154', - 'cp367': 'ascii', - 'cp424': 'cp424', - 'cp437': 'cp437', - 'cp500': 'cp500', - 'cp775': 'cp775', - 'cp819': 'windows-1252', - 'cp850': 'cp850', - 'cp852': 'cp852', - 'cp855': 'cp855', - 'cp857': 'cp857', - 'cp860': 'cp860', - 'cp861': 'cp861', - 'cp862': 'cp862', - 'cp863': 'cp863', - 'cp864': 'cp864', - 'cp865': 'cp865', - 'cp866': 'cp866', - 'cp869': 'cp869', - 'cp936': 'gbk', - 'cpgr': 'cp869', - 'cpis': 'cp861', - 'csascii': 'ascii', - 'csbig5': 'big5', - 'cseuckr': 'cp949', - 'cseucpkdfmtjapanese': 'euc_jp', - 'csgb2312': 'gbk', - 'cshproman8': 'hp-roman8', - 'csibm037': 'cp037', - 'csibm1026': 'cp1026', - 'csibm424': 'cp424', - 'csibm500': 'cp500', - 'csibm855': 'cp855', - 'csibm857': 'cp857', - 'csibm860': 'cp860', - 'csibm861': 'cp861', - 'csibm863': 'cp863', - 'csibm864': 'cp864', - 'csibm865': 'cp865', - 'csibm866': 'cp866', - 'csibm869': 'cp869', - 'csiso2022jp': 'iso2022_jp', - 'csiso2022jp2': 'iso2022_jp_2', - 'csiso2022kr': 'iso2022_kr', - 'csiso58gb231280': 'gbk', - 'csisolatin1': 'windows-1252', - 'csisolatin2': 'iso8859-2', - 'csisolatin3': 'iso8859-3', - 'csisolatin4': 'iso8859-4', - 'csisolatin5': 'windows-1254', - 'csisolatin6': 'iso8859-10', - 'csisolatinarabic': 'iso8859-6', - 'csisolatincyrillic': 'iso8859-5', - 'csisolatingreek': 'iso8859-7', - 'csisolatinhebrew': 'iso8859-8', - 'cskoi8r': 'koi8-r', - 'csksc56011987': 'cp949', - 'cspc775baltic': 'cp775', - 'cspc850multilingual': 'cp850', - 'cspc862latinhebrew': 'cp862', - 'cspc8codepage437': 'cp437', - 'cspcp852': 'cp852', - 'csptcp154': 'ptcp154', - 'csshiftjis': 'shift_jis', - 'csunicode11utf7': 'utf-7', - 'cyrillic': 'iso8859-5', - 'cyrillicasian': 'ptcp154', - 'ebcdiccpbe': 'cp500', - 'ebcdiccpca': 'cp037', - 'ebcdiccpch': 'cp500', - 'ebcdiccphe': 'cp424', - 'ebcdiccpnl': 'cp037', - 'ebcdiccpus': 'cp037', - 'ebcdiccpwt': 'cp037', - 'ecma114': 'iso8859-6', - 'ecma118': 'iso8859-7', - 'elot928': 'iso8859-7', - 'eucjp': 'euc_jp', - 'euckr': 'cp949', - 'extendedunixcodepackedformatforjapanese': 'euc_jp', - 'gb18030': 'gb18030', - 'gb2312': 'gbk', - 'gb231280': 'gbk', - 'gbk': 'gbk', - 'greek': 'iso8859-7', - 'greek8': 'iso8859-7', - 'hebrew': 'iso8859-8', - 'hproman8': 'hp-roman8', - 'hzgb2312': 'hz', - 'ibm037': 'cp037', - 'ibm1026': 'cp1026', - 'ibm367': 'ascii', - 'ibm424': 'cp424', - 'ibm437': 'cp437', - 'ibm500': 'cp500', - 'ibm775': 'cp775', - 'ibm819': 'windows-1252', - 'ibm850': 'cp850', - 'ibm852': 'cp852', - 'ibm855': 'cp855', - 'ibm857': 'cp857', - 'ibm860': 'cp860', - 'ibm861': 'cp861', - 'ibm862': 'cp862', - 'ibm863': 'cp863', - 'ibm864': 'cp864', - 'ibm865': 'cp865', - 'ibm866': 'cp866', - 'ibm869': 'cp869', - 'iso2022jp': 'iso2022_jp', - 'iso2022jp2': 'iso2022_jp_2', - 'iso2022kr': 'iso2022_kr', - 'iso646irv1991': 'ascii', - 'iso646us': 'ascii', - 'iso88591': 'windows-1252', - 'iso885910': 'iso8859-10', - 'iso8859101992': 'iso8859-10', - 'iso885911987': 'windows-1252', - 'iso885913': 'iso8859-13', - 'iso885914': 'iso8859-14', - 'iso8859141998': 'iso8859-14', - 'iso885915': 'iso8859-15', - 'iso885916': 'iso8859-16', - 'iso8859162001': 'iso8859-16', - 'iso88592': 'iso8859-2', - 'iso885921987': 'iso8859-2', - 'iso88593': 'iso8859-3', - 'iso885931988': 'iso8859-3', - 'iso88594': 'iso8859-4', - 'iso885941988': 'iso8859-4', - 'iso88595': 'iso8859-5', - 'iso885951988': 'iso8859-5', - 'iso88596': 'iso8859-6', - 'iso885961987': 'iso8859-6', - 'iso88597': 'iso8859-7', - 'iso885971987': 'iso8859-7', - 'iso88598': 'iso8859-8', - 'iso885981988': 'iso8859-8', - 'iso88599': 'windows-1254', - 'iso885991989': 'windows-1254', - 'isoceltic': 'iso8859-14', - 'isoir100': 'windows-1252', - 'isoir101': 'iso8859-2', - 'isoir109': 'iso8859-3', - 'isoir110': 'iso8859-4', - 'isoir126': 'iso8859-7', - 'isoir127': 'iso8859-6', - 'isoir138': 'iso8859-8', - 'isoir144': 'iso8859-5', - 'isoir148': 'windows-1254', - 'isoir149': 'cp949', - 'isoir157': 'iso8859-10', - 'isoir199': 'iso8859-14', - 'isoir226': 'iso8859-16', - 'isoir58': 'gbk', - 'isoir6': 'ascii', - 'koi8r': 'koi8-r', - 'koi8u': 'koi8-u', - 'korean': 'cp949', - 'ksc5601': 'cp949', - 'ksc56011987': 'cp949', - 'ksc56011989': 'cp949', - 'l1': 'windows-1252', - 'l10': 'iso8859-16', - 'l2': 'iso8859-2', - 'l3': 'iso8859-3', - 'l4': 'iso8859-4', - 'l5': 'windows-1254', - 'l6': 'iso8859-10', - 'l8': 'iso8859-14', - 'latin1': 'windows-1252', - 'latin10': 'iso8859-16', - 'latin2': 'iso8859-2', - 'latin3': 'iso8859-3', - 'latin4': 'iso8859-4', - 'latin5': 'windows-1254', - 'latin6': 'iso8859-10', - 'latin8': 'iso8859-14', - 'latin9': 'iso8859-15', - 'ms936': 'gbk', - 'mskanji': 'shift_jis', - 'pt154': 'ptcp154', - 'ptcp154': 'ptcp154', - 'r8': 'hp-roman8', - 'roman8': 'hp-roman8', - 'shiftjis': 'shift_jis', - 'tis620': 'cp874', - 'unicode11utf7': 'utf-7', - 'us': 'ascii', - 'usascii': 'ascii', - 'utf16': 'utf-16', - 'utf16be': 'utf-16-be', - 'utf16le': 'utf-16-le', - 'utf8': 'utf-8', - 'windows1250': 'cp1250', - 'windows1251': 'cp1251', - 'windows1252': 'cp1252', - 'windows1253': 'cp1253', - 'windows1254': 'cp1254', - 'windows1255': 'cp1255', - 'windows1256': 'cp1256', - 'windows1257': 'cp1257', - 'windows1258': 'cp1258', - 'windows936': 'gbk', - 'x-x-big5': 'big5'} - -tokenTypes = { - "Doctype": 0, - "Characters": 1, - "SpaceCharacters": 2, - "StartTag": 3, - "EndTag": 4, - "EmptyTag": 5, - "Comment": 6, - "ParseError": 7 -} - -tagTokenTypes = frozenset((tokenTypes["StartTag"], tokenTypes["EndTag"], - tokenTypes["EmptyTag"])) - - -prefixes = dict([(v, k) for k, v in namespaces.items()]) -prefixes["http://www.w3.org/1998/Math/MathML"] = "math" - - -class DataLossWarning(UserWarning): - pass - - -class ReparseException(Exception): - pass diff --git a/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/__init__.py b/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/_base.py b/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/_base.py deleted file mode 100644 index c7dbaed..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/_base.py +++ /dev/null @@ -1,12 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - - -class Filter(object): - def __init__(self, source): - self.source = source - - def __iter__(self): - return iter(self.source) - - def __getattr__(self, name): - return getattr(self.source, name) diff --git a/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/alphabeticalattributes.py b/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/alphabeticalattributes.py deleted file mode 100644 index fed6996..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/alphabeticalattributes.py +++ /dev/null @@ -1,20 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -from . import _base - -try: - from collections import OrderedDict -except ImportError: - from ordereddict import OrderedDict - - -class Filter(_base.Filter): - def __iter__(self): - for token in _base.Filter.__iter__(self): - if token["type"] in ("StartTag", "EmptyTag"): - attrs = OrderedDict() - for name, value in sorted(token["data"].items(), - key=lambda x: x[0]): - attrs[name] = value - token["data"] = attrs - yield token diff --git a/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/inject_meta_charset.py b/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/inject_meta_charset.py deleted file mode 100644 index ca33b70..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/inject_meta_charset.py +++ /dev/null @@ -1,65 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -from . import _base - - -class Filter(_base.Filter): - def __init__(self, source, encoding): - _base.Filter.__init__(self, source) - self.encoding = encoding - - def __iter__(self): - state = "pre_head" - meta_found = (self.encoding is None) - pending = [] - - for token in _base.Filter.__iter__(self): - type = token["type"] - if type == "StartTag": - if token["name"].lower() == "head": - state = "in_head" - - elif type == "EmptyTag": - if token["name"].lower() == "meta": - # replace charset with actual encoding - has_http_equiv_content_type = False - for (namespace, name), value in token["data"].items(): - if namespace is not None: - continue - elif name.lower() == 'charset': - token["data"][(namespace, name)] = self.encoding - meta_found = True - break - elif name == 'http-equiv' and value.lower() == 'content-type': - has_http_equiv_content_type = True - else: - if has_http_equiv_content_type and (None, "content") in token["data"]: - token["data"][(None, "content")] = 'text/html; charset=%s' % self.encoding - meta_found = True - - elif token["name"].lower() == "head" and not meta_found: - # insert meta into empty head - yield {"type": "StartTag", "name": "head", - "data": token["data"]} - yield {"type": "EmptyTag", "name": "meta", - "data": {(None, "charset"): self.encoding}} - yield {"type": "EndTag", "name": "head"} - meta_found = True - continue - - elif type == "EndTag": - if token["name"].lower() == "head" and pending: - # insert meta into head (if necessary) and flush pending queue - yield pending.pop(0) - if not meta_found: - yield {"type": "EmptyTag", "name": "meta", - "data": {(None, "charset"): self.encoding}} - while pending: - yield pending.pop(0) - meta_found = True - state = "post_head" - - if state == "in_head": - pending.append(token) - else: - yield token diff --git a/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/lint.py b/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/lint.py deleted file mode 100644 index 7cc99a4..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/lint.py +++ /dev/null @@ -1,93 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -from gettext import gettext -_ = gettext - -from . import _base -from ..constants import cdataElements, rcdataElements, voidElements - -from ..constants import spaceCharacters -spaceCharacters = "".join(spaceCharacters) - - -class LintError(Exception): - pass - - -class Filter(_base.Filter): - def __iter__(self): - open_elements = [] - contentModelFlag = "PCDATA" - for token in _base.Filter.__iter__(self): - type = token["type"] - if type in ("StartTag", "EmptyTag"): - name = token["name"] - if contentModelFlag != "PCDATA": - raise LintError(_("StartTag not in PCDATA content model flag: %(tag)s") % {"tag": name}) - if not isinstance(name, str): - raise LintError(_("Tag name is not a string: %(tag)r") % {"tag": name}) - if not name: - raise LintError(_("Empty tag name")) - if type == "StartTag" and name in voidElements: - raise LintError(_("Void element reported as StartTag token: %(tag)s") % {"tag": name}) - elif type == "EmptyTag" and name not in voidElements: - raise LintError(_("Non-void element reported as EmptyTag token: %(tag)s") % {"tag": token["name"]}) - if type == "StartTag": - open_elements.append(name) - for name, value in token["data"]: - if not isinstance(name, str): - raise LintError(_("Attribute name is not a string: %(name)r") % {"name": name}) - if not name: - raise LintError(_("Empty attribute name")) - if not isinstance(value, str): - raise LintError(_("Attribute value is not a string: %(value)r") % {"value": value}) - if name in cdataElements: - contentModelFlag = "CDATA" - elif name in rcdataElements: - contentModelFlag = "RCDATA" - elif name == "plaintext": - contentModelFlag = "PLAINTEXT" - - elif type == "EndTag": - name = token["name"] - if not isinstance(name, str): - raise LintError(_("Tag name is not a string: %(tag)r") % {"tag": name}) - if not name: - raise LintError(_("Empty tag name")) - if name in voidElements: - raise LintError(_("Void element reported as EndTag token: %(tag)s") % {"tag": name}) - start_name = open_elements.pop() - if start_name != name: - raise LintError(_("EndTag (%(end)s) does not match StartTag (%(start)s)") % {"end": name, "start": start_name}) - contentModelFlag = "PCDATA" - - elif type == "Comment": - if contentModelFlag != "PCDATA": - raise LintError(_("Comment not in PCDATA content model flag")) - - elif type in ("Characters", "SpaceCharacters"): - data = token["data"] - if not isinstance(data, str): - raise LintError(_("Attribute name is not a string: %(name)r") % {"name": data}) - if not data: - raise LintError(_("%(type)s token with empty data") % {"type": type}) - if type == "SpaceCharacters": - data = data.strip(spaceCharacters) - if data: - raise LintError(_("Non-space character(s) found in SpaceCharacters token: %(token)r") % {"token": data}) - - elif type == "Doctype": - name = token["name"] - if contentModelFlag != "PCDATA": - raise LintError(_("Doctype not in PCDATA content model flag: %(name)s") % {"name": name}) - if not isinstance(name, str): - raise LintError(_("Tag name is not a string: %(tag)r") % {"tag": name}) - # XXX: what to do with token["data"] ? - - elif type in ("ParseError", "SerializeError"): - pass - - else: - raise LintError(_("Unknown token type: %(type)s") % {"type": type}) - - yield token diff --git a/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/optionaltags.py b/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/optionaltags.py deleted file mode 100644 index fefe0b3..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/optionaltags.py +++ /dev/null @@ -1,205 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -from . import _base - - -class Filter(_base.Filter): - def slider(self): - previous1 = previous2 = None - for token in self.source: - if previous1 is not None: - yield previous2, previous1, token - previous2 = previous1 - previous1 = token - yield previous2, previous1, None - - def __iter__(self): - for previous, token, next in self.slider(): - type = token["type"] - if type == "StartTag": - if (token["data"] or - not self.is_optional_start(token["name"], previous, next)): - yield token - elif type == "EndTag": - if not self.is_optional_end(token["name"], next): - yield token - else: - yield token - - def is_optional_start(self, tagname, previous, next): - type = next and next["type"] or None - if tagname in 'html': - # An html element's start tag may be omitted if the first thing - # inside the html element is not a space character or a comment. - return type not in ("Comment", "SpaceCharacters") - elif tagname == 'head': - # A head element's start tag may be omitted if the first thing - # inside the head element is an element. - # XXX: we also omit the start tag if the head element is empty - if type in ("StartTag", "EmptyTag"): - return True - elif type == "EndTag": - return next["name"] == "head" - elif tagname == 'body': - # A body element's start tag may be omitted if the first thing - # inside the body element is not a space character or a comment, - # except if the first thing inside the body element is a script - # or style element and the node immediately preceding the body - # element is a head element whose end tag has been omitted. - if type in ("Comment", "SpaceCharacters"): - return False - elif type == "StartTag": - # XXX: we do not look at the preceding event, so we never omit - # the body element's start tag if it's followed by a script or - # a style element. - return next["name"] not in ('script', 'style') - else: - return True - elif tagname == 'colgroup': - # A colgroup element's start tag may be omitted if the first thing - # inside the colgroup element is a col element, and if the element - # is not immediately preceeded by another colgroup element whose - # end tag has been omitted. - if type in ("StartTag", "EmptyTag"): - # XXX: we do not look at the preceding event, so instead we never - # omit the colgroup element's end tag when it is immediately - # followed by another colgroup element. See is_optional_end. - return next["name"] == "col" - else: - return False - elif tagname == 'tbody': - # A tbody element's start tag may be omitted if the first thing - # inside the tbody element is a tr element, and if the element is - # not immediately preceeded by a tbody, thead, or tfoot element - # whose end tag has been omitted. - if type == "StartTag": - # omit the thead and tfoot elements' end tag when they are - # immediately followed by a tbody element. See is_optional_end. - if previous and previous['type'] == 'EndTag' and \ - previous['name'] in ('tbody', 'thead', 'tfoot'): - return False - return next["name"] == 'tr' - else: - return False - return False - - def is_optional_end(self, tagname, next): - type = next and next["type"] or None - if tagname in ('html', 'head', 'body'): - # An html element's end tag may be omitted if the html element - # is not immediately followed by a space character or a comment. - return type not in ("Comment", "SpaceCharacters") - elif tagname in ('li', 'optgroup', 'tr'): - # A li element's end tag may be omitted if the li element is - # immediately followed by another li element or if there is - # no more content in the parent element. - # An optgroup element's end tag may be omitted if the optgroup - # element is immediately followed by another optgroup element, - # or if there is no more content in the parent element. - # A tr element's end tag may be omitted if the tr element is - # immediately followed by another tr element, or if there is - # no more content in the parent element. - if type == "StartTag": - return next["name"] == tagname - else: - return type == "EndTag" or type is None - elif tagname in ('dt', 'dd'): - # A dt element's end tag may be omitted if the dt element is - # immediately followed by another dt element or a dd element. - # A dd element's end tag may be omitted if the dd element is - # immediately followed by another dd element or a dt element, - # or if there is no more content in the parent element. - if type == "StartTag": - return next["name"] in ('dt', 'dd') - elif tagname == 'dd': - return type == "EndTag" or type is None - else: - return False - elif tagname == 'p': - # A p element's end tag may be omitted if the p element is - # immediately followed by an address, article, aside, - # blockquote, datagrid, dialog, dir, div, dl, fieldset, - # footer, form, h1, h2, h3, h4, h5, h6, header, hr, menu, - # nav, ol, p, pre, section, table, or ul, element, or if - # there is no more content in the parent element. - if type in ("StartTag", "EmptyTag"): - return next["name"] in ('address', 'article', 'aside', - 'blockquote', 'datagrid', 'dialog', - 'dir', 'div', 'dl', 'fieldset', 'footer', - 'form', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', - 'header', 'hr', 'menu', 'nav', 'ol', - 'p', 'pre', 'section', 'table', 'ul') - else: - return type == "EndTag" or type is None - elif tagname == 'option': - # An option element's end tag may be omitted if the option - # element is immediately followed by another option element, - # or if it is immediately followed by an optgroup - # element, or if there is no more content in the parent - # element. - if type == "StartTag": - return next["name"] in ('option', 'optgroup') - else: - return type == "EndTag" or type is None - elif tagname in ('rt', 'rp'): - # An rt element's end tag may be omitted if the rt element is - # immediately followed by an rt or rp element, or if there is - # no more content in the parent element. - # An rp element's end tag may be omitted if the rp element is - # immediately followed by an rt or rp element, or if there is - # no more content in the parent element. - if type == "StartTag": - return next["name"] in ('rt', 'rp') - else: - return type == "EndTag" or type is None - elif tagname == 'colgroup': - # A colgroup element's end tag may be omitted if the colgroup - # element is not immediately followed by a space character or - # a comment. - if type in ("Comment", "SpaceCharacters"): - return False - elif type == "StartTag": - # XXX: we also look for an immediately following colgroup - # element. See is_optional_start. - return next["name"] != 'colgroup' - else: - return True - elif tagname in ('thead', 'tbody'): - # A thead element's end tag may be omitted if the thead element - # is immediately followed by a tbody or tfoot element. - # A tbody element's end tag may be omitted if the tbody element - # is immediately followed by a tbody or tfoot element, or if - # there is no more content in the parent element. - # A tfoot element's end tag may be omitted if the tfoot element - # is immediately followed by a tbody element, or if there is no - # more content in the parent element. - # XXX: we never omit the end tag when the following element is - # a tbody. See is_optional_start. - if type == "StartTag": - return next["name"] in ['tbody', 'tfoot'] - elif tagname == 'tbody': - return type == "EndTag" or type is None - else: - return False - elif tagname == 'tfoot': - # A tfoot element's end tag may be omitted if the tfoot element - # is immediately followed by a tbody element, or if there is no - # more content in the parent element. - # XXX: we never omit the end tag when the following element is - # a tbody. See is_optional_start. - if type == "StartTag": - return next["name"] == 'tbody' - else: - return type == "EndTag" or type is None - elif tagname in ('td', 'th'): - # A td element's end tag may be omitted if the td element is - # immediately followed by a td or th element, or if there is - # no more content in the parent element. - # A th element's end tag may be omitted if the th element is - # immediately followed by a td or th element, or if there is - # no more content in the parent element. - if type == "StartTag": - return next["name"] in ('td', 'th') - else: - return type == "EndTag" or type is None - return False diff --git a/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/sanitizer.py b/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/sanitizer.py deleted file mode 100644 index b206b54..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/sanitizer.py +++ /dev/null @@ -1,12 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -from . import _base -from ..sanitizer import HTMLSanitizerMixin - - -class Filter(_base.Filter, HTMLSanitizerMixin): - def __iter__(self): - for token in _base.Filter.__iter__(self): - token = self.sanitize_token(token) - if token: - yield token diff --git a/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/whitespace.py b/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/whitespace.py deleted file mode 100644 index dfc60ee..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/html5lib/filters/whitespace.py +++ /dev/null @@ -1,38 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals - -import re - -from . import _base -from ..constants import rcdataElements, spaceCharacters -spaceCharacters = "".join(spaceCharacters) - -SPACES_REGEX = re.compile("[%s]+" % spaceCharacters) - - -class Filter(_base.Filter): - - spacePreserveElements = frozenset(["pre", "textarea"] + list(rcdataElements)) - - def __iter__(self): - preserve = 0 - for token in _base.Filter.__iter__(self): - type = token["type"] - if type == "StartTag" \ - and (preserve or token["name"] in self.spacePreserveElements): - preserve += 1 - - elif type == "EndTag" and preserve: - preserve -= 1 - - elif not preserve and type == "SpaceCharacters" and token["data"]: - # Test on token["data"] above to not introduce spaces where there were not - token["data"] = " " - - elif not preserve and type == "Characters": - token["data"] = collapse_spaces(token["data"]) - - yield token - - -def collapse_spaces(text): - return SPACES_REGEX.sub(' ', text) diff --git a/vendor/pip-1.5.6/pip/_vendor/html5lib/html5parser.py b/vendor/pip-1.5.6/pip/_vendor/html5lib/html5parser.py deleted file mode 100644 index b28f46f..0000000 --- a/vendor/pip-1.5.6/pip/_vendor/html5lib/html5parser.py +++ /dev/null @@ -1,2713 +0,0 @@ -from __future__ import absolute_import, division, unicode_literals -from pip._vendor.six import with_metaclass - -import types - -from . import inputstream -from . import tokenizer - -from . import treebuilders -from .treebuilders._base import Marker - -from . import utils -from . import constants -from .constants import spaceCharacters, asciiUpper2Lower -from .constants import specialElements -from .constants import headingElements -from .constants import cdataElements, rcdataElements -from .constants import tokenTypes, ReparseException, namespaces -from .constants import htmlIntegrationPointElements, mathmlTextIntegrationPointElements -from .constants import adjustForeignAttributes as adjustForeignAttributesMap - - -def parse(doc, treebuilder="etree", encoding=None, - namespaceHTMLElements=True): - """Parse a string or file-like object into a tree""" - tb = treebuilders.getTreeBuilder(treebuilder) - p = HTMLParser(tb, namespaceHTMLElements=namespaceHTMLElements) - return p.parse(doc, encoding=encoding) - - -def parseFragment(doc, container="div", treebuilder="etree", encoding=None, - namespaceHTMLElements=True): - tb = treebuilders.getTreeBuilder(treebuilder) - p = HTMLParser(tb, namespaceHTMLElements=namespaceHTMLElements) - return p.parseFragment(doc, container=container, encoding=encoding) - - -def method_decorator_metaclass(function): - class Decorated(type): - def __new__(meta, classname, bases, classDict): - for attributeName, attribute in classDict.items(): - if isinstance(attribute, types.FunctionType): - attribute = function(attribute) - - classDict[attributeName] = attribute - return type.__new__(meta, classname, bases, classDict) - return Decorated - - -class HTMLParser(object): - """HTML parser. Generates a tree structure from a stream of (possibly - malformed) HTML""" - - def __init__(self, tree=None, tokenizer=tokenizer.HTMLTokenizer, - strict=False, namespaceHTMLElements=True, debug=False): - """ - strict - raise an exception when a parse error is encountered - - tree - a treebuilder class controlling the type of tree that will be - returned. Built in treebuilders can be accessed through - html5lib.treebuilders.getTreeBuilder(treeType) - - tokenizer - a class that provides a stream of tokens to the treebuilder. - This may be replaced for e.g. a sanitizer which converts some tags to - text - """ - - # Raise an exception on the first error encountered - self.strict = strict - - if tree is None: - tree = treebuilders.getTreeBuilder("etree") - self.tree = tree(namespaceHTMLElements) - self.tokenizer_class = tokenizer - self.errors = [] - - self.phases = dict([(name, cls(self, self.tree)) for name, cls in - getPhases(debug).items()]) - - def _parse(self, stream, innerHTML=False, container="div", - encoding=None, parseMeta=True, useChardet=True, **kwargs): - - self.innerHTMLMode = innerHTML - self.container = container - self.tokenizer = self.tokenizer_class(stream, encoding=encoding, - parseMeta=parseMeta, - useChardet=useChardet, - parser=self, **kwargs) - self.reset() - - while True: - try: - self.mainLoop() - break - except ReparseException: - self.reset() - - def reset(self): - self.tree.reset() - self.firstStartTag = False - self.errors = [] - self.log = [] # only used with debug mode - # "quirks" / "limited quirks" / "no quirks" - self.compatMode = "no quirks" - - if self.innerHTMLMode: - self.innerHTML = self.container.lower() - - if self.innerHTML in cdataElements: - self.tokenizer.state = self.tokenizer.rcdataState - elif self.innerHTML in rcdataElements: - self.tokenizer.state = self.tokenizer.rawtextState - elif self.innerHTML == 'plaintext': - self.tokenizer.state = self.tokenizer.plaintextState - else: - # state already is data state - # self.tokenizer.state = self.tokenizer.dataState - pass - self.phase = self.phases["beforeHtml"] - self.phase.insertHtmlElement() - self.resetInsertionMode() - else: - self.innerHTML = False - self.phase = self.phases["initial"] - - self.lastPhase = None - - self.beforeRCDataPhase = None - - self.framesetOK = True - - def isHTMLIntegrationPoint(self, element): - if (element.name == "annotation-xml" and - element.namespace == namespaces["mathml"]): - return ("encoding" in element.attributes and - element.attributes["encoding"].translate( - asciiUpper2Lower) in - ("text/html", "application/xhtml+xml")) - else: - return (element.namespace, element.name) in htmlIntegrationPointElements - - def isMathMLTextIntegrationPoint(self, element): - return (element.namespace, element.name) in mathmlTextIntegrationPointElements - - def mainLoop(self): - CharactersToken = tokenTypes["Characters"] - SpaceCharactersToken = tokenTypes["SpaceCharacters"] - StartTagToken = tokenTypes["StartTag"] - EndTagToken = tokenTypes["EndTag"] - CommentToken = tokenTypes["Comment"] - DoctypeToken = tokenTypes["Doctype"] - ParseErrorToken = tokenTypes["ParseError"] - - for token in self.normalizedTokens(): - new_token = token - while new_token is not None: - currentNode = self.tree.openElements[-1] if self.tree.openElements else None - currentNodeNamespace = currentNode.namespace if currentNode else None - currentNodeName = currentNode.name if currentNode else None - - type = new_token["type"] - - if type == ParseErrorToken: - self.parseError(new_token["data"], new_token.get("datavars", {})) - new_token = None - else: - if (len(self.tree.openElements) == 0 or - currentNodeNamespace == self.tree.defaultNamespace or - (self.isMathMLTextIntegrationPoint(currentNode) and - ((type == StartTagToken and - token["name"] not in frozenset(["mglyph", "malignmark"])) or - type in (CharactersToken, SpaceCharactersToken))) or - (currentNodeNamespace == namespaces["mathml"] and - currentNodeName == "annotation-xml" and - token["name"] == "svg") or - (self.isHTMLIntegrationPoint(currentNode) and - type in (StartTagToken, CharactersToken, SpaceCharactersToken))): - phase = self.phase - else: - phase = self.phases["inForeignContent"] - - if type == CharactersToken: - new_token = phase.processCharacters(new_token) - elif type == SpaceCharactersToken: - new_token = phase.processSpaceCharacters(new_token) - elif type == StartTagToken: - new_token = phase.processStartTag(new_token) - elif type == EndTagToken: - new_token = phase.processEndTag(new_token) - elif type == CommentToken: - new_token = phase.processComment(new_token) - elif type == DoctypeToken: - new_token = phase.processDoctype(new_token) - - if (type == StartTagToken and token["selfClosing"] - and not token["selfClosingAcknowledged"]): - self.parseError("non-void-element-with-trailing-solidus", - {"name": token["name"]}) - - # When the loop finishes it's EOF - reprocess = True - phases = [] - while reprocess: - phases.append(self.phase) - reprocess = self.phase.processEOF() - if reprocess: - assert self.phase not in phases - - def normalizedTokens(self): - for token in self.tokenizer: - yield self.normalizeToken(token) - - def parse(self, stream, encoding=None, parseMeta=True, useChardet=True): - """Parse a HTML document into a well-formed tree - - stream - a filelike object or string containing the HTML to be parsed - - The optional encoding parameter must be a string that indicates - the encoding. If specified, that encoding will be used, - regardless of any BOM or later declaration (such as in a meta - element) - """ - self._parse(stream, innerHTML=False, encoding=encoding, - parseMeta=parseMeta, useChardet=useChardet) - return self.tree.getDocument() - - def parseFragment(self, stream, container="div", encoding=None, - parseMeta=False, useChardet=True): - """Parse a HTML fragment into a well-formed tree fragment - - container - name of the element we're setting the innerHTML property - if set to None, default to 'div' - - stream - a filelike object or string containing the HTML to be parsed - - The optional encoding parameter must be a string that indicates - the encoding. If specified, that encoding will be used, - regardless of any BOM or later declaration (such as in a meta - element) - """ - self._parse(stream, True, container=container, encoding=encoding) - return self.tree.getFragment() - - def parseError(self, errorcode="XXX-undefined-error", datavars={}): - # XXX The idea is to make errorcode mandatory. - self.errors.append((self.tokenizer.stream.position(), errorcode, datavars)) - if self.strict: - raise ParseError - - def normalizeToken(self, token): - """ HTML5 specific normalizations to the token stream """ - - if token["type"] == tokenTypes["StartTag"]: - token["data"] = dict(token["data"][::-1]) - - return token - - def adjustMathMLAttributes(self, token): - replacements = {"definitionurl": "definitionURL"} - for k, v in replacements.items(): - if k in token["data"]: - token["data"][v] = token["data"][k] - del token["data"][k] - - def adjustSVGAttributes(self, token): - replacements = { - "attributename": "attributeName", - "attributetype": "attributeType", - "basefrequency": "baseFrequency", - "baseprofile": "baseProfile", - "calcmode": "calcMode", - "clippathunits": "clipPathUnits", - "contentscripttype": "contentScriptType", - "contentstyletype": "contentStyleType", - "diffuseconstant": "diffuseConstant", - "edgemode": "edgeMode", - "externalresourcesrequired": "externalResourcesRequired", - "filterres": "filterRes", - "filterunits": "filterUnits", - "glyphref": "glyphRef", - "gradienttransform": "gradientTransform", - "gradientunits": "gradientUnits", - "kernelmatrix": "kernelMatrix", - "kernelunitlength": "kernelUnitLength", - "keypoints": "keyPoints", - "keysplines": "keySplines", - "keytimes": "keyTimes", - "lengthadjust": "lengthAdjust", - "limitingconeangle": "limitingConeAngle", - "markerheight": "markerHeight", - "markerunits": "markerUnits", - "markerwidth": "markerWidth", - "maskcontentunits": "maskContentUnits", - "maskunits": "maskUnits", - "numoctaves": "numOctaves", - "pathlength": "pathLength", - "patterncontentunits": "patternContentUnits", - "patterntransform": "patternTransform", - "patternunits": "patternUnits", - "pointsatx": "pointsAtX", - "pointsaty": "pointsAtY", - "pointsatz": "pointsAtZ", - "preservealpha": "preserveAlpha", - "preserveaspectratio": "preserveAspectRatio", - "primitiveunits": "primitiveUnits", - "refx": "refX", - "refy": "refY", - "repeatcount": "repeatCount", - "repeatdur": "repeatDur", - "requiredextensions": "requiredExtensions", - "requiredfeatures": "requiredFeatures", - "specularconstant": "specularConstant", - "specularexponent": "specularExponent", - "spreadmethod": "spreadMethod", - "startoffset": "startOffset", - "stddeviation": "stdDeviation", - "stitchtiles": "stitchTiles", - "surfacescale": "surfaceScale", - "systemlanguage": "systemLanguage", - "tablevalues": "tableValues", - "targetx": "targetX", - "targety": "targetY", - "textlength": "textLength", - "viewbox": "viewBox", - "viewtarget": "viewTarget", - "xchannelselector": "xChannelSelector", - "ychannelselector": "yChannelSelector", - "zoomandpan": "zoomAndPan" - } - for originalName in list(token["data"].keys()): - if originalName in replacements: - svgName = replacements[originalName] - token["data"][svgName] = token["data"][originalName] - del token["data"][originalName] - - def adjustForeignAttributes(self, token): - replacements = adjustForeignAttributesMap - - for originalName in token["data"].keys(): - if originalName in replacements: - foreignName = replacements[originalName] - token["data"][foreignName] = token["data"][originalName] - del token["data"][originalName] - - def reparseTokenNormal(self, token): - self.parser.phase() - - def resetInsertionMode(self): - # The name of this method is mostly historical. (It's also used in the - # specification.) - last = False - newModes = { - "select": "inSelect", - "td": "inCell", - "th": "inCell", - "tr": "inRow", - "tbody": "inTableBody", - "thead": "inTableBody", - "tfoot": "inTableBody", - "caption": "inCaption", - "colgroup": "inColumnGroup", - "table": "inTable", - "head": "inBody", - "body": "inBody", - "frameset": "inFrameset", - "html": "beforeHead" - } - for node in self.tree.openElements[::-1]: - nodeName = node.name - new_phase = None - if node == self.tree.openElements[0]: - assert self.innerHTML - last = True - nodeName = self.innerHTML - # Check for conditions that should only happen in the innerHTML - # case - if nodeName in ("select", "colgroup", "head", "html"): - assert self.innerHTML - - if not last and node.namespace != self.tree.defaultNamespace: - continue - - if nodeName in newModes: - new_phase = self.phases[newModes[nodeName]] - break - elif last: - new_phase = self.phases["inBody"] - break - - self.phase = new_phase - - def parseRCDataRawtext(self, token, contentType): - """Generic RCDATA/RAWTEXT Parsing algorithm - contentType - RCDATA or RAWTEXT - """ - assert contentType in ("RAWTEXT", "RCDATA") - - self.tree.insertElement(token) - - if contentType == "RAWTEXT": - self.tokenizer.state = self.tokenizer.rawtextState - else: - self.tokenizer.state = self.tokenizer.rcdataState - - self.originalPhase = self.phase - - self.phase = self.phases["text"] - - -def getPhases(debug): - def log(function): - """Logger that records which phase processes each token""" - type_names = dict((value, key) for key, value in - constants.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 - if token['type'] in constants.tagTokenTypes: - info["name"] = token['name'] - - self.parser.log.append((self.parser.tokenizer.state.__name__, - self.parser.phase.__class__.__name__, - self.__class__.__name__, - function.__name__, - info)) - return function(self, *args, **kwargs) - else: - return function(self, *args, **kwargs) - return wrapped - - def getMetaclass(use_metaclass, metaclass_func): - if use_metaclass: - return method_decorator_metaclass(metaclass_func) - else: - return type - - class Phase(with_metaclass(getMetaclass(debug, log))): - """Base class for helper object that implements each phase of processing - """ - - def __init__(self, parser, tree): - self.parser = parser - self.tree = tree - - def processEOF(self): - raise NotImplementedError - - def processComment(self, token): - # For most phases the following is correct. Where it's not it will be - # overridden. - self.tree.insertComment(token, self.tree.openElements[-1]) - - def processDoctype(self, token): - self.parser.parseError("unexpected-doctype") - - def processCharacters(self, token): - self.tree.insertText(token["data"]) - - def processSpaceCharacters(self, token): - self.tree.insertText(token["data"]) - - def processStartTag(self, token): - return self.startTagHandler[token["name"]](token) - - def startTagHtml(self, token): - if not self.parser.firstStartTag and token["name"] == "html": - self.parser.parseError("non-html-root") - # XXX Need a check here to see if the first start tag token emitted is - # this token... If it's not, invoke self.parser.parseError(). - for attr, value in token["data"].items(): - if attr not in self.tree.openElements[0].attributes: - self.tree.openElements[0].attributes[attr] = value - self.parser.firstStartTag = False - - def processEndTag(self, token): - return self.endTagHandler[token["name"]](token) - - class InitialPhase(Phase): - def processSpaceCharacters(self, token): - pass - - def processComment(self, token): - self.tree.insertComment(token, self.tree.document) - - def processDoctype(self, token): - name = token["name"] - publicId = token["publicId"] - systemId = token["systemId"] - correct = token["correct"] - - if (name != "html" or publicId is not None or - systemId is not None and systemId != "about:legacy-compat"): - self.parser.parseError("unknown-doctype") - - if publicId is None: - publicId = "" - - self.tree.insertDoctype(token) - - if publicId != "": - publicId = publicId.translate(asciiUpper2Lower) - - if (not correct or token["name"] != "html" - or publicId.startswith( - ("+//silmaril//dtd html pro v0r11 19970101//", - "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", - "-//as//dtd html 3.0 aswedit + extensions//", - "-//ietf//dtd html 2.0 level 1//", - "-//ietf//dtd html 2.0 level 2//", - "-//ietf//dtd html 2.0 strict level 1//", - "-//ietf//dtd html 2.0 strict level 2//", - "-//ietf//dtd html 2.0 strict//", - "-//ietf//dtd html 2.0//", - "-//ietf//dtd html 2.1e//", - "-//ietf//dtd html 3.0//", - "-//ietf//dtd html 3.2 final//", - "-//ietf//dtd html 3.2//", - "-//ietf//dtd html 3//", - "-//ietf//dtd html level 0//", - "-//ietf//dtd html level 1//", - "-//ietf//dtd html level 2//", - "-//ietf//dtd html level 3//", - "-//ietf//dtd html strict level 0//", - "-//ietf//dtd html strict level 1//", - "-//ietf//dtd html strict level 2//", - "-//ietf//dtd html strict level 3//", - "-//ietf//dtd html strict//", - "-//ietf//dtd html//", - "-//metrius//dtd metrius presentational//", - "-//microsoft//dtd internet explorer 2.0 html strict//", - "-//microsoft//dtd internet explorer 2.0 html//", - "-//microsoft//dtd internet explorer 2.0 tables//", - "-//microsoft//dtd internet explorer 3.0 html strict//", - "-//microsoft//dtd internet explorer 3.0 html//", - "-//microsoft//dtd internet explorer 3.0 tables//", - "-//netscape comm. corp.//dtd html//", - "-//netscape comm. corp.//dtd strict html//", - "-//o'reilly and associates//dtd html 2.0//", - "-//o'reilly and associates//dtd html extended 1.0//", - "-//o'reilly and associates//dtd html extended relaxed 1.0//", - "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//", - "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//", - "-//spyglass//dtd html 2.0 extended//", - "-//sq//dtd html 2.0 hotmetal + extensions//", - "-//sun microsystems corp.//dtd hotjava html//", - "-//sun microsystems corp.//dtd hotjava strict html//", - "-//w3c//dtd html 3 1995-03-24//", - "-//w3c//dtd html 3.2 draft//", - "-//w3c//dtd html 3.2 final//", - "-//w3c//dtd html 3.2//", - "-//w3c//dtd html 3.2s draft//", - "-//w3c//dtd html 4.0 frameset//", - "-//w3c//dtd html 4.0 transitional//", - "-//w3c//dtd html experimental 19960712//", - "-//w3c//dtd html experimental 970421//", - "-//w3c//dtd w3 html//", - "-//w3o//dtd w3 html 3.0//", - "-//webtechs//dtd mozilla html 2.0//", - "-//webtechs//dtd mozilla html//")) - or publicId in - ("-//w3o//dtd w3 html strict 3.0//en//", - "-/w3c/dtd html 4.0 transitional/en", - "html") - or publicId.startswith( - ("-//w3c//dtd html 4.01 frameset//", - "-//w3c//dtd html 4.01 transitional//")) and - systemId is None - or systemId and systemId.lower() == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd"): - self.parser.compatMode = "quirks" - elif (publicId.startswith( - ("-//w3c//dtd xhtml 1.0 frameset//", - "-//w3c//dtd xhtml 1.0 transitional//")) - or publicId.startswith( - ("-//w3c//dtd html 4.01 frameset//", - "-//w3c//dtd html 4.01 transitional//")) and - systemId is not None): - self.parser.compatMode = "limited quirks" - - self.parser.phase = self.parser.phases["beforeHtml"] - - def anythingElse(self): - self.parser.compatMode = "quirks" - self.parser.phase = self.parser.phases["beforeHtml"] - - def processCharacters(self, token): - self.parser.parseError("expected-doctype-but-got-chars") - self.anythingElse() - return token - - def processStartTag(self, token): - self.parser.parseError("expected-doctype-but-got-start-tag", - {"name": token["name"]}) - self.anythingElse() - return token - - def processEndTag(self, token): - self.parser.parseError("expected-doctype-but-got-end-tag", - {"name": token["name"]}) - self.anythingElse() - return token - - def processEOF(self): - self.parser.parseError("expected-doctype-but-got-eof") - self.anythingElse() - return True - - class BeforeHtmlPhase(Phase): - # helper methods - def insertHtmlElement(self): - self.tree.insertRoot(impliedTagToken("html", "StartTag")) - self.parser.phase = self.parser.phases["beforeHead"] - - # other - def processEOF(self): - self.insertHtmlElement() - return True - - def processComment(self, token): - self.tree.insertComment(token, self.tree.document) - - def processSpaceCharacters(self, token): - pass - - def processCharacters(self, token): - self.insertHtmlElement() - return token - - def processStartTag(self, token): - if token["name"] == "html": - self.parser.firstStartTag = True - self.insertHtmlElement() - return token - - def processEndTag(self, token): - if token["name"] not in ("head", "body", "html", "br"): - self.parser.parseError("unexpected-end-tag-before-html", - {"name": token["name"]}) - else: - self.insertHtmlElement() - return token - - class BeforeHeadPhase(Phase): - 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 - - def processEOF(self): - self.startTagHead(impliedTagToken("head", "StartTag")) - return True - - def processSpaceCharacters(self, token): - pass - - def processCharacters(self, token): - self.startTagHead(impliedTagToken("head", "StartTag")) - return token - - def startTagHtml(self, token): - return self.parser.phases["inBody"].processStartTag(token) - - def startTagHead(self, token): - self.tree.insertElement(token) - self.tree.headPointer = self.tree.openElements[-1] - self.parser.phase = self.parser.phases["inHead"] - - def startTagOther(self, token): - self.startTagHead(impliedTagToken("head", "StartTag")) - return token - - def endTagImplyHead(self, token): - self.startTagHead(impliedTagToken("head", "StartTag")) - return token - - def endTagOther(self, token): - self.parser.parseError("end-tag-after-implied-root", - {"name": token["name"]}) - - class InHeadPhase(Phase): - def __init__(self, parser, tree): - Phase.__init__(self, parser, tree) - - self.startTagHandler = utils.MethodDispatcher([ - ("html", self.startTagHtml), - ("title", self.startTagTitle), - (("noscript", "noframes", "style"), self.startTagNoScriptNoFramesStyle), - ("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 - - # the real thing - def processEOF(self): - self.anythingElse() - return True - - def processCharacters(self, token): - self.anythingElse() - return token - - def startTagHtml(self, token): - return self.parser.phases["inBody"].processStartTag(token) - - def startTagHead(self, token): - self.parser.parseError("two-heads-are-not-better-than-one") - - def startTagBaseLinkCommand(self, token): - self.tree.insertElement(token) - self.tree.openElements.pop() - token["selfClosingAcknowledged"] = True - - def startTagMeta(self, token): - self.tree.insertElement(token) - self.tree.openElements.pop() - token["selfClosingAcknowledged"] = True - - attributes = token["data"] - if self.parser.tokenizer.stream.charEncoding[1] == "tentative": - if "charset" in attributes: - self.parser.tokenizer.stream.changeEncoding(attributes["charset"]) - elif ("content" in attributes and - "http-equiv" in attributes and - attributes["http-equiv"].lower() == "content-type"): - # Encoding it as UTF-8 here is a hack, as really we should pass - # the abstract Unicode string, and just use the - # ContentAttrParser on that, but using UTF-8 allows all chars - # to be encoded and as a ASCII-superset works. - data = inputstream.EncodingBytes(attributes["content"].encode("utf-8")) - parser = inputstream.ContentAttrParser(data) - codec = parser.parse() - self.parser.tokenizer.stream.changeEncoding(codec) - - def startTagTitle(self, token): - self.parser.parseRCDataRawtext(token, "RCDATA") - - def startTagNoScriptNoFramesStyle(self, token): - # Need to decide whether to implement the scripting-disabled case - self.parser.parseRCDataRawtext(token, "RAWTEXT") - - def startTagScript(self, token): - self.tree.insertElement(token) - self.parser.tokenizer.state = self.parser.tokenizer.scriptDataState - self.parser.originalPhase = self.parser.phase - self.parser.phase = self.parser.phases["text"] - - def startTagOther(self, token): - self.anythingElse() - return token - - def endTagHead(self, token): - node = self.parser.tree.openElements.pop() - assert node.name == "head", "Expected head got %s" % node.name - self.parser.phase = self.parser.phases["afterHead"] - - def endTagHtmlBodyBr(self, token): - self.anythingElse() - return token - - def endTagOther(self, token): - self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) - - def anythingElse(self): - self.endTagHead(impliedTagToken("head")) - - # XXX If we implement a parser for which scripting is disabled we need to - # implement this phase. - # - # class InHeadNoScriptPhase(Phase): - class AfterHeadPhase(Phase): - def __init__(self, parser, tree): - Phase.__init__(self, parser, tree) - - 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 - - def processEOF(self): - self.anythingElse() - return True - - def processCharacters(self, token): - self.anythingElse() - return token - - def startTagHtml(self, token): - return self.parser.phases["inBody"].processStartTag(token) - - def startTagBody(self, token): - self.parser.framesetOK = False - self.tree.insertElement(token) - self.parser.phase = self.parser.phases["inBody"] - - def startTagFrameset(self, token): - self.tree.insertElement(token) - self.parser.phase = self.parser.phases["inFrameset"] - - def startTagFromHead(self, token): - self.parser.parseError("unexpected-start-tag-out-of-my-head", - {"name": token["name"]}) - self.tree.openElements.append(self.tree.headPointer) - self.parser.phases["inHead"].processStartTag(token) - for node in self.tree.openElements[::-1]: - if node.name == "head": - self.tree.openElements.remove(node) - break - - def startTagHead(self, token): - self.parser.parseError("unexpected-start-tag", {"name": token["name"]}) - - def startTagOther(self, token): - self.anythingElse() - return token - - def endTagHtmlBodyBr(self, token): - self.anythingElse() - return token - - def endTagOther(self, token): - self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) - - def anythingElse(self): - self.tree.insertElement(impliedTagToken("body", "StartTag")) - self.parser.phase = self.parser.phases["inBody"] - self.parser.framesetOK = True - - 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) - - # Keep a ref to this for special handling of whitespace in

-            self.processSpaceCharactersNonPre = self.processSpaceCharacters
-
-            self.startTagHandler = utils.MethodDispatcher([
-                ("html", self.startTagHtml),
-                (("base", "basefont", "bgsound", "command", "link", "meta",
-                  "noframes", "script", "style", "title"),
-                 self.startTagProcessInHead),
-                ("body", self.startTagBody),
-                ("frameset", self.startTagFrameset),
-                (("address", "article", "aside", "blockquote", "center", "details",
-                  "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),
-                (("noembed", "noframes", "noscript"), 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):
-            if node1.name != node2.name or node1.namespace != node2.namespace:
-                return False
-            elif len(node1.attributes) != len(node2.attributes):
-                return False
-            else:
-                attributes1 = sorted(node1.attributes.items())
-                attributes2 = sorted(node2.attributes.items())
-                for attr1, attr2 in zip(attributes1, attributes2):
-                    if attr1 != attr2:
-                        return False
-            return True
-
-        # helper
-        def addFormattingElement(self, token):
-            self.tree.insertElement(token)
-            element = self.tree.openElements[-1]
-
-            matchingElements = []
-            for node in self.tree.activeFormattingElements[::-1]:
-                if node is Marker:
-                    break
-                elif self.isMatchingFormattingElement(node, element):
-                    matchingElements.append(node)
-
-            assert len(matchingElements) <= 3
-            if len(matchingElements) == 3:
-                self.tree.activeFormattingElements.remove(matchingElements[-1])
-            self.tree.activeFormattingElements.append(element)
-
-        # the real deal
-        def processEOF(self):
-            allowed_elements = frozenset(("dd", "dt", "li", "p", "tbody", "td",
-                                          "tfoot", "th", "thead", "tr", "body",
-                                          "html"))
-            for node in self.tree.openElements[::-1]:
-                if node.name not in allowed_elements:
-                    self.parser.parseError("expected-closing-tag-but-got-eof")
-                    break
-            # Stop parsing
-
-        def processSpaceCharactersDropNewline(self, token):
-            # Sometimes (start of 
, , and